arrays - Combine los resultados de dos llamadas distintas de Get-ChildItem en una sola variable para hacer el mismo procesamiento en ellas
powershell (5)
Estoy tratando de escribir un script de PowerShell para construir una lista de archivos, de varios directorios. Después de que todos los directorios se hayan agregado a la lista principal, me gustaría hacer el mismo procesamiento en todos los archivos.
Esto es lo que tengo:
$items = New-Object Collections.Generic.List[IO.FileInfo]
$loc1 = @(Get-ChildItem -Path "//server/C$/Program Files (x86)/Data1/" -Recurse)
$loc2 = @(Get-ChildItem -Path "//server/C$/Web/DataStorage/" -Recurse)
$items.Add($loc1) # This line fails (the next also fails)
$items.Add($loc2)
# Processing code is here
que falla con este error:
No se puede convertir el argumento "0", con el valor: "System.Object []", para "Agregar" al tipo "System.IO.FileInfo": "No se puede convertir el valor" System.Object [] "del tipo" System. Objeto [] "para escribir" System.IO.FileInfo ".
Estoy interesado principalmente en cuál es el enfoque correcto para este tipo de situación. Me doy cuenta de que mi código es una forma muy C de hacerlo: si hay una forma más PowerShell de realizar la misma tarea, estoy totalmente a favor. La clave es que el número de $loc#''s
puede cambiar con el tiempo, por lo que agregar y eliminar uno o dos debería ser fácil en el código resultante.
La respuesta de Keith es a la manera de PowerShell: simplemente use @ (...) + @ (...).
Si realmente desea una Lista de tipos seguros [IO.FileInfo], entonces necesita utilizar AddRange y convertir la matriz de objetos en una matriz de FileInfo. También debe asegurarse de no obtener ningún objeto DirectoryInfo, o bien necesita usar IO.FileSystemInfo como su tipo de lista:
Por lo tanto, evitar directorios:
$items = New-Object Collections.Generic.List[IO.FileInfo]
$items.AddRange( ([IO.FileSystemInfo[]](ls ''//server/C$/Program Files (x86)/Data1/' -r | Where { -not $_.PSIsContainer } )) )
$items.AddRange( ([IO.FileSystemInfo[]](ls ''//server/C$/Web/DataStorage/' -r | Where { -not $_.PSIsContainer } )) )
O use FileSystemInfo (la clase base común de FileInfo y DirectoryInfo):
$items = New-Object Collections.Generic.List[IO.FileSystemInfo]
$items.AddRange( ([IO.FileSystemInfo[]](ls ''//server/C$/Program Files (x86)/Data1/' -r)) )
$items.AddRange( ([IO.FileSystemInfo[]](ls ''//server/C$/Web/DataStorage/' -r)) )
Aquí hay una manera tal vez incluso más de PowerShell-ish que no necesita concatenación de partes o agregar elementos explícitos al resultado en absoluto:
# Collect the results by two or more calls of Get-ChildItem
# and perhaps do some other job (but avoid unwanted output!)
$result = .{
# Output items
Get-ChildItem C:/TEMP/_100715_103408 -Recurse
# Some other job
$x = 1 + 1
# Output some more items
Get-ChildItem C:/TEMP/_100715_110341 -Recurse
#...
}
# Process the result items
$result
Pero el código dentro del bloque de script debe escribirse un poco más cuidadosamente para evitar la salida no deseada mezclada con elementos del sistema de archivos.
EDITAR: Alternativamente, y quizás más efectivamente, en lugar de .{ ... }
podemos usar @( ... )
o $( ... )
donde ...
representa el código que contiene varias llamadas de Get-ChildItem
.
Desde get-help get-childitem: -Path Especifica una ruta a una o más ubicaciones. Se permiten comodines. La ubicación predeterminada es el directorio actual (.).
$items = get-childitem ''//server/C$/Program Files (x86)/Data1/',''//server/C$/Web/DataStorage/' -Recurse
No estoy seguro de que necesites una lista genérica aquí. Puedes usar una matriz de PowerShell, por ejemplo:
$items = @(Get-ChildItem ''//server/C$/Program Files (x86)/Data1/' -r)
$items += @(Get-ChildItem ''//server/C$/Web/DataStorage/' -r)
Los arreglos de PowerShell se pueden concatenar usando +=
.
-Filter
es más -Include
que -Include
, por lo que si no tiene muchas extensiones diferentes, simplemente concatenar dos listas filtradas puede ser más rápido.
$files = Get-ChildItem -Path "H:/stash/" -Filter *.rdlc -Recurse
$files += Get-ChildItem -Path "H:/stash/" -Filter *.rdl -Recurse
Comparé la salida con un temporizador como este:
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# Do Stuff Here
$stopwatch.Stop()
Write-Host "$([Math]::Round($stopwatch.Elapsed.TotalSeconds)) seconds ellapsed"