85 votes

Comment filtrer correctement plusieurs chaînes de caractères dans une copie PowerShell script ?

J'utilise le script PowerShell script de cette réponse pour effectuer une copie de fichier. Le problème se pose lorsque je souhaite inclure plusieurs types de fichiers à l'aide du filtre.

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

fonctionne comme dans un rêve. Cependant, le problème se pose lorsque je veux inclure plusieurs types de fichiers à l'aide du filtre.

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 }

J'obtiens l'erreur suivante :

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

J'ai plusieurs itérations de parenthèses, sans parenthèses, -filter , -include définissant les inclusions comme variables (par ex, $fileFilter ) et obtient à chaque fois l'erreur ci-dessus, en pointant toujours vers ce qui suit -filter .

L'exception intéressante à cette règle est lorsque je code -filter "*.gif,*.jpg,*.xls*,*.doc*,*.pdf*,*.wav*,*.ppt*" . Il n'y a pas d'erreur, mais je n'obtiens aucun résultat et rien dans la console. Je soupçonne que j'ai codé par inadvertance une erreur de codage. and avec cette déclaration ?

Qu'est-ce que je fais de travers et comment puis-je y remédier ?

212voto

Adi Inbar Points 10985

-Filtre n'accepte qu'une seule chaîne de caractères. -Inclure accepte plusieurs valeurs, mais qualifie la valeur -Chemin argument. L'astuce consiste à ajouter \* jusqu'à la fin du chemin, puis utiliser -Inclure pour sélectionner plusieurs extensions. BTW, il n'est pas nécessaire de citer les chaînes de caractères dans les arguments des cmdlets, sauf si elles contiennent des espaces ou des caractères spéciaux de l'interpréteur de commandes.

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

Notez que cela fonctionnera indépendamment du fait que Chemin d'origine se termine par une barre oblique inverse, car plusieurs barres obliques inverses consécutives sont interprétées comme un seul séparateur de chemin. Par exemple, essayez :

Get-ChildItem C:\\\\\Windows

3voto

Kevin Points 31

Quelque chose comme cela devrait fonctionner (c'est ce qui s'est passé pour moi). La raison pour laquelle nous voulons utiliser -Filter au lieu de -Include est que l'inclusion a un impact considérable sur les performances par rapport à l'inclusion de la -Filter .

Ci-dessous, nous passons en boucle chaque type de fichier et plusieurs serveurs/postes de travail spécifiés dans des fichiers distincts.

##  
##  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

2voto

MarredCheese Points 2206

Passons en revue les options :

  • -Filter ne prend qu'un seul modèle, de sorte qu'il ne fonctionne pas pour ce problème.

  • -Include fonctionne mais est très lent (ce qui est tout à fait normal dans de nombreux cas).

  • Tuyauterie vers Where-Object est beaucoup plus rapide que -Include . C'est aussi le le plus puissant car elle vous permet d'accéder à expressions rationnelles (au lieu des caractères génériques normaux) et toute autre logique dont vous pourriez avoir besoin, comme dans l'exemple ci-dessous :

    # checking extension with regex
    Get-ChildItem $dir |
        Where-Object { $_.Extension -match '\.(xlsx?|jpe?g)$' }
    
    # checking extension and creation time
    Get-ChildItem $dir | Where-Object {
        $_.Extension -in '.xls', '.xlsx', '.jpg', '.jpeg' -and
        $_.CreationTime -gt $yesterday
    }
  • -Path est encore un peu plus rapide mais prend les chemins complets plutôt que les noms de fichiers, ce qui est pénible à utiliser (voir les exemples ci-dessous) et ne fonctionne que dans les cas simples car les motifs de chemins ne peuvent pas correspondre à un nombre variable de niveaux de répertoires. Ceci est en contraste avec les shells typiques, dans lesquels * correspond à un seul répertoire et ** correspond à un nombre quelconque de répertoires imbriqués.

    # simpler
    $paths = $dir\*.xls, $dir\*.xlsx, $dir\*.jpg, $dir\*.jpeg
    Get-ChildItem $paths
    
    # less repetitive
    $paths = 'xls', 'xlsx', 'jpg', 'jpeg' | % { Join-Path $dir *.$_ }
    Get-ChildItem $paths

0voto

DPC Points 39
Get-ChildItem $originalPath\* -Include @("*.gif", "*.jpg", "*.xls*", "*.doc*", "*.pdf*", "*.wav*", "*.ppt")

-2voto

capsch Points 108

L'utilisation de l'inclusion est la façon la plus simple de procéder, conformément à l'accord de l'Union européenne.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X