1,5K
En este artículo, veremos ejemplos del uso de construcciones para recorrer todos los archivos y carpetas en un disco o en un directorio específico (usando las declaraciones For-Each y Get-ChildItem). Puede utilizarlos ampliamente en sus scripts de PowerShell.
Por lo general, la tarea de iterar sobre todos los objetos del sistema de archivos en un directorio surge cuando necesita realizar una determinada acción con todos los objetos anidados. Por ejemplo, necesita eliminar, copiar, mover archivos, agregar o reemplazar líneas en todos los archivos en el directorio específico según algunos criterios.
Puedes usar el Get-ChildItem Cmdlet de PowerShell para obtener una lista de objetos secundarios (carpetas y archivos) en un directorio. Este es el cmdlet más popular para la administración de sistemas de archivos. Hay varios alias para ChildItem: gci, directorio, es.
El cmdlet Get-ChildItem muestra una lista de objetos secundarios (anidados) en una unidad o directorio específico. La ruta al directorio se especifica mediante el atributo –Path.
Por ejemplo, para enumerar los archivos en el directorio C:\PS, ejecute el comando:
Get-ChildItem -Path ‘C:\PS’
Sin embargo, muestra una lista de objetos ubicados en la raíz del directorio especificado. También puede mostrar el contenido de directorios secundarios (subdirectorios) utilizando el -recurse parámetro:
Get-ChildItem -Path ‘C:\PS’ –Recurse
Como puede ver, el contenido de cada subdirectorio se muestra secuencialmente.
Ahora, veamos la estructura general del bucle ForEach en PowerShell cuando se usa el cmdlet Get-ChildItem:
Get-ChildItem –Path "C:\PS" –Recurse | Foreach-Object { Write-Host $_.FullName }
Este comando imprime una lista completa de nombres de archivos en la carpeta de destino (incluidos los subdirectorios).
Puede reemplazar Write-Host con otro cmdlet y realizar cualquier otra acción en todos los archivos.
En este bucle, la variable ps se refiere al elemento actual ($PSItem, o this) dentro de un bucle foreach.
Nota. Aprenda a consultar el servidor Microsoft SQL con Invoke SqlCmd en PowerShell.
Además, puedes usar una estructura de bucle de este tipo (pero nos gusta menos):
foreach($file in Get-ChildItem $SomeFolder) { # Do something }
Por ejemplo, puede eliminar todos los archivos con la extensión *.log en el directorio especificado y todas las subcarpetas (realmente no eliminaremos los archivos del disco agregando el parámetro WhatIF en PowerShell):
Get-ChildItem –Path "C:\PS\" -Recurse -Filter *.log | Foreach-Object { Remove-Item $_.FullName -WhatIF }
El script encontró 3 archivos con la extensión *.log e indicó que este script podría eliminarlos.
Eliminar archivos de más de xx días usando PowerShell
Considere una secuencia de comandos que elimine archivos con más de 10 días de antigüedad en un directorio (puede usarse cuando necesite limpiar la carpeta de registros o las carpetas de la red pública). Usamos el filtro Dónde-Objeto de PowerShell para encontrar los archivos antiguos:
Get-ChildItem C:\ps\ -Recurse | Where-Object { $_.CreationTime -lt ($(Get-Date).AddDays(-10))} | ForEach-Object { remove-Item $_.FullName –whatif }
Cambiar el nombre de archivos con un bucle ForEach en PowerShell
Otra tarea común que es bastante fácil de resolver con PowerShell es cambiar el nombre de los archivos en una carpeta. Digamos que su tarea es encontrar todos los archivos con la extensión *.log en una carpeta y cambiar el nombre de todos los archivos de registro con números en sus nombres.
$logFolder = "C:\Logs" Get-ChildItem -Path $logFolder -Recurse -Filter *.log | ForEach-Object { $newName = $_.Name -replace "\d+", "" # Remove all digits from the file name $newPath = Join-Path -Path $_.Directory.FullName -ChildPath $newName # Generate a new file path Rename-Item -Path $_.FullName -NewName $newName -Force # Rename the current file with the new name }
En este caso, el cmdlet Join-Path se utiliza para crear una nueva ruta de archivo que incluye el nombre del directorio actual ($_.Directory.FullName) y el nuevo nombre del archivo. Rename-Item se utiliza para cambiar el nombre del archivo y el parámetro -Force para sobrescribir archivos existentes.
Copie archivos nuevos de forma recursiva con PowerShell
Puede usar PowerShell para copiar archivos nuevos a la carpeta de destino. Por ejemplo, desea sincronizar dos carpetas y copiar solo los archivos nuevos creados o modificados en los últimos 7 días a la carpeta de destino (en el servidor de archivos por la ruta UNC):
$sourceDir = "C:\Source" $targetDir = "\\FS01\Share\TargetFolder" $daysToCompare = 7 $compareDate = (Get-Date).AddDays(-$daysToCompare) Get-ChildItem -Path $source -Recurse | ForEach-Object { # Copy files that are newer than daysToCompare value if ($_.LastWriteTime -gt $compareDate) { $targetFilePath = $_.FullName.Replace($sourceDir, $targetDir) # Make sure that the target folder exists New-Item -ItemType Directory -Path (Split-Path $targetFilePath) -Force | Out-Null # Copy the file to the target Copy-Item $_.FullName -Destination $targetFilePath -Force } }
Eliminar directorios vacíos de forma recursiva con PowerShell
O puede recorrer todos los subdirectorios y carpetas y subcarpetas vacías, si existen:
$targetFolder = "C:\PS\" Get-ChildItem -Path $targetFolder -Recurse -Force -Directory | Where-Object {$_.GetFileSystemInfos().Count -eq 0} | Remove-Item -Force -Recurse -whatif
Busque archivos grandes y muévalos a una carpeta diferente
El siguiente ejemplo encontrará todos los archivos * .iso de más de 1 GB en la unidad del sistema C: y los moverá a otra partición.
Primero, configuremos el tamaño de archivo requerido (1 GB):
$filesize=1024*1024*1024
Ahora recorramos todos los archivos y movámoslos al directorio de destino:
Get-ChildItem C:\* -Include *.iso -Recurse |Where-Object { $_.Length -gt $filesize} |ForEach-Object { Move-Item $_.FullName D:\ISO -whatif}
Recorrer archivos de texto en un directorio usando PowerShell
El siguiente ejemplo de bucle de archivos permite buscar archivos que contengan el texto ‘flush_log’ o ‘error’ para todos los archivos *.log en el directorio y guarda las líneas encontradas en archivos con una nueva extensión (_outlog):
$files = Get-ChildItem C:\ps\ -Recurse *.log foreach ($f in $files){ $outfile = $f.FullName + "_outlog" Get-Content $f.FullName | Where-Object { ($_ -match 'flush_log' -or $_ -match 'error') } | Set-Content $outfile }
Un script de PowerShell de este tipo puede resultar útil a la hora de buscar entradas de eventos específicas en archivos de registro y filtrar todo lo innecesario. Además, puede utilizar este código PS en otros escenarios cuando necesite recorrer archivos, leer el contenido y hacer algo con él.
Puede utilizar un bucle foreach para encontrar al usuario que abre un archivo específico en un recurso compartido de red a través de SMB. En este ejemplo, nos conectaremos a una computadora remota (host SMB) usando CIMSession y recorreremos los archivos abiertos:
$filename="*annualreport.xlsx*" $sess = New-CIMSession –Computername ny-fs01 $files = Get-SMBOpenFile -CimSession $sess foreach ($file in $files) { if ($file.path -like $filename) { $file | select path, ClientUserName | fl } }
8 Comments