Cómo filtrar correctamente varias cadenas en un script de copia de PowerShell

80

Estoy usando el script de PowerShell de esta respuesta para hacer una copia de archivo. El problema surge cuando quiero incluir varios tipos de archivos usando el filtro.

Get-ChildItem $originalPath -filter "*.htm"  | `
   foreach{ $targetFile = $htmPath + $_.FullName.SubString($originalPath.Length); ` 
 New-Item -ItemType File -Path $targetFile -Force;  `
 Copy-Item $_.FullName -destination $targetFile }

funciona como un sueño. Sin embargo, el problema surge cuando quiero incluir varios tipos de archivos usando el filtro.

Get-ChildItem $originalPath ` 
  -filter "*.gif","*.jpg","*.xls*","*.doc*","*.pdf*","*.wav*",".ppt*")  | `
   foreach{ $targetFile = $htmPath + $_.FullName.SubString($originalPath.Length); ` 
 New-Item -ItemType File -Path $targetFile -Force;  `
 Copy-Item $_.FullName -destination $targetFile }

Me da el siguiente error:

Get-ChildItem : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Filter'. Specified method is not supported.
At F:\data\foo\CGM.ps1:121 char:36
+ Get-ChildItem $originalPath -filter <<<<  "*.gif","*.jpg","*.xls*","*.doc*","*.pdf*","*.wav*",".ppt*" | `
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.GetChildItemCommand

Tengo varias iteraciones de paréntesis, sin paréntesis, -filter, -include, definiendo las inclusiones como variable (por ejemplo, $fileFilter) y cada vez que obtener el error anterior, y siempre apuntando a lo que sigue -filter.

La excepción interesante a eso es cuando codifico -filter "*.gif,*.jpg,*.xls*,*.doc*,*.pdf*,*.wav*,*.ppt*". No hay errores, pero no obtengo ningún resultado y nada de regreso a la consola. Sospecho que sin darme cuenta he codificado a un impícito andcon esa declaración.

Entonces, ¿qué estoy haciendo mal y cómo puedo corregirlo?

dwwilson66
fuente

Respuestas:

194

-Filter solo acepta una sola cadena. -Include acepta varios valores, pero califica el argumento -Path . El truco consiste en agregar \*al final de la ruta y luego usar -Incluir para seleccionar varias extensiones. Por cierto, no es necesario citar cadenas en los argumentos de cmdlet a menos que contengan espacios o caracteres especiales de shell.

Get-ChildItem $originalPath\* -Include *.gif, *.jpg, *.xls*, *.doc*, *.pdf*, *.wav*, .ppt*

Tenga en cuenta que esto funcionará independientemente de si $ originalPath termina en una barra invertida, porque varias barras invertidas consecutivas se interpretan como un único separador de ruta. Por ejemplo, intente:

Get-ChildItem C:\\\\\Windows
Adi Inbar
fuente
5
¡WooHoo! Ese \*truco acaba de resolver unos seis problemas. ¡Genial gracias!
dwwilson66
17
Tenga en cuenta que el comodín ( \*) no es necesario cuando -Recursese especifica.
Ohad Schneider
por alguna razón, esto no funciona al buscar directorios?
Ross Presser
Agregar -Recurse permite que esto llegue a las subcarpetas
Derek Evermore
2

Algo como esto debería funcionar (a mí me funcionó). La razón para querer usar en -Filterlugar de -Includees que la inclusión tiene un gran impacto en el rendimiento en comparación con -Filter.

A continuación, se muestra en bucle cada tipo de archivo y varios servidores / estaciones de trabajo especificados en archivos separados.

##  
##  This script will pull from a list of workstations in a text file and search for the specified string


## Change the file path below to where your list of target workstations reside
## Change the file path below to where your list of filetypes reside

$filetypes = gc 'pathToListOffiletypes.txt'
$servers = gc 'pathToListOfWorkstations.txt'

##Set the scope of the variable so it has visibility
set-variable -Name searchString -Scope 0
$searchString = 'whatYouAreSearchingFor'

foreach ($server in $servers)
    {

    foreach ($filetype in $filetypes)
    {

    ## below creates the search path.  This could be further improved to exclude the windows directory
    $serverString = "\\"+$server+"\c$\Program Files"


    ## Display the server being queried
    write-host “Server:” $server "searching for " $filetype in $serverString

    Get-ChildItem -Path $serverString -Recurse -Filter $filetype |
    #-Include "*.xml","*.ps1","*.cnf","*.odf","*.conf","*.bat","*.cfg","*.ini","*.config","*.info","*.nfo","*.txt" |
    Select-String -pattern $searchstring | group path | select name | out-file f:\DataCentre\String_Results.txt

    $os = gwmi win32_operatingsystem -computer $server
    $sp = $os | % {$_.servicepackmajorversion}
    $a = $os | % {$_.caption}

    ##  Below will list again the server name as well as its OS and SP
    ##  Because the script may not be monitored, this helps confirm the machine has been successfully scanned
        write-host $server “has completed its " $filetype "scan:” “|” “OS:” $a “SP:” “|” $sp


    }

}
#end script
Kevin
fuente
esto es muy cierto y en 5 preguntas similares aquí nadie señaló que, aunque no podemos hacerlo -filter *.jpg, *.png, podría ser más rápido hacer -filtrar * .jpg de una vez, que hacer -filtrar * .png y unir los resultados, que haz uno -Include *.jpg, *.png". Tengo una carpeta que contiene 126k archivos y 18k carpetas. Estoy buscando un archivo y una carpeta en cada carpeta de forma recursiva. usar -Filter toma 5 segundos y usar -Incluir 30 segundos. Hacer -Filtrar dos veces en 10 segundos es tres veces más rápido que uno -Incluir ir.
papo
0
Get-ChildItem $originalPath\* -Include @("*.gif", "*.jpg", "*.xls*", "*.doc*", "*.pdf*", "*.wav*", "*.ppt")
DPC
fuente
¡Bienvenido a Stack Overflow! Esta respuesta apareció en la cola de revisión de baja calidad, presumiblemente porque no explicó el contenido. Si explica esto (en su respuesta), es mucho más probable que obtenga más votos a favor, ¡y la persona que pregunta realmente aprende algo!
El chico del sombrero
2
Además, repite el código de la respuesta que publiqué anteriormente, excepto que incluye la lista de extensiones en un operador de evaluación de expresión de matriz ( @()), lo cual es superfluo, porque una lista separada por comas se evalúa inherentemente como una matriz.
Adi Inbar
-2

usar la inclusión es la forma más fácil según

http://www.vistax64.com/powershell/168315-get-childitem-filter-files-multiple-extensions.html

capsch
fuente
1
Eso no funcionó. :( -filter -include *.file, *.types -filter -include (*.file, *.types), -filter -include "*.file", "*.types"y -filter -include ("*.file", "*.types")todo con error a cabo según mi pregunta anterior La eliminación de la. -filterParámetro y simplemente incluyendo los -include(las mismas iteraciones de citas y parens) no resultar en tiempo de ejecución de errores, pero no había ningún conjunto de resultados en el directorio de destino.
dwwilson66