1.3K
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 instrucciones For-Each y Get-ChildItem). Puede usarlos 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, debe eliminar, copiar, mover archivos, agregar o reemplazar líneas en todos los archivos en el directorio específico de acuerdo con algunos criterios.
Puedes usar el Obtener elemento secundario 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 del sistema de archivos. Hay varios alias para ChildItem: gci, directorio, ls.
El cmdlet Get-ChildItem muestra una lista de objetos secundarios (anidados) en una unidad o directorio especificado. La ruta al directorio se especifica a través del 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 los directorios secundarios (subdirectorios) usando el -Recurso parámetro:
Get-ChildItem -Path ‘C:PS’ –Recurse
Como puede ver, los contenidos de cada subdirectorio se muestran 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 archivo 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 ciclo, la variable ps hace referencia 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, puede 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.
Elimine archivos con 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 (se puede usar cuando necesite limpiar la carpeta de registros o las carpetas de la red pública). Usamos el filtro Where-Object 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 }
Cambio de 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 usa para crear una nueva ruta de archivo que incluye el nombre del directorio actual ($_.Directory.FullName) y el nuevo nombre de archivo. El Rename-Item se usa para cambiar el nombre del archivo y el parámetro -Force para sobrescribir los archivos existentes.
Copie nuevos archivos recursivamente 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 = "\FS01ShareTargetFolder" $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 recursivamente 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
Encuentre 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 vamos a recorrer todos los archivos y moverlos al directorio de destino:
Get-ChildItem C:* -Include *.iso -Recurse |Where-Object { $_.Length -gt $filesize} |ForEach-Object { Move-Item $_.FullName D:ISO -whatif}
Recorra archivos de texto en un directorio usando PowerShell
El siguiente ejemplo de bucle de archivo permite encontrar archivos que contienen 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 }
Tal secuencia de comandos de PowerShell puede ser útil al buscar entradas de eventos específicos en archivos de registro y filtrar todo lo que no sea necesario. Además, puede usar este código PS en otros escenarios cuando necesite recorrer archivos, leer el contenido y hacer algo con él.
Descubra qué usuario está bloqueando un archivo en una carpeta compartida
Puede usar 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 } }