Jak prawidłowo filtrować wiele ciągów w skrypcie kopiowania programu PowerShell

80

Używam skryptu PowerShell z tej odpowiedzi, aby wykonać kopię pliku. Problem pojawia się, gdy chcę uwzględnić wiele typów plików za pomocą filtru.

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

działa jak sen. Jednak problem pojawia się, gdy chcę dołączyć wiele typów plików za pomocą filtru.

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 }

Daje mi następujący błąd:

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

Mam różne iteracje nawiasach, bez nawiasów -filter, -includedefiniującą inkluzje jako zmienna (na przykład $fileFilter) i za każdym razem pojawia się błąd powyżej, i zawsze wskazując co następuje -filter.

Ciekawym wyjątkiem jest sytuacja, gdy koduję -filter "*.gif,*.jpg,*.xls*,*.doc*,*.pdf*,*.wav*,*.ppt*". Nie ma błędów, ale ja i nie otrzymuję wyników i nic nie wracam do konsoli. Podejrzewam, że nieumyślnie zakodowałem nielegalne andoświadczenie?

Więc co robię źle i jak mogę to poprawić?

dwwilson66
źródło

Odpowiedzi:

194

-Filter akceptuje tylko jeden ciąg. -Include akceptuje wiele wartości, ale kwalifikuje argument -Path . Sztuczka polega na tym, aby dołączyć \*do końca ścieżki, a następnie użyć -Include, aby wybrać wiele rozszerzeń. Przy okazji, cytowanie łańcuchów nie jest konieczne w argumentach poleceń cmdlet, chyba że zawierają spacje lub znaki specjalne powłoki.

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

Zauważ, że zadziała to niezależnie od tego, czy $ originalPath kończy się ukośnikiem odwrotnym, ponieważ wiele następujących po sobie ukośników odwrotnych jest interpretowanych jako pojedynczy separator ścieżki. Na przykład spróbuj:

Get-ChildItem C:\\\\\Windows
Adi Inbar
źródło
5
WooHoo! Ta \*sztuczka właśnie rozwiązała około sześciu problemów. Wielkie dzieki!
dwwilson66
17
Zauważ, że symbol wieloznaczny ( \*) nie jest potrzebny, gdy -Recursejest określony.
Ohad Schneider,
z jakiegoś powodu to nie działa podczas wyszukiwania katalogów?
Ross Presser,
Dodanie -Recurse pozwala na dotarcie do podfolderów
Derek Evermore
2

Coś takiego powinno działać (mi się udało). Powodem, dla którego chcesz używać -Filterzamiast tego, -Includejest to, że włączanie ma ogromny wpływ na wydajność w porównaniu z -Filter.

Poniżej po prostu zapętla każdy typ pliku i wiele serwerów / stacji roboczych określonych w oddzielnych plikach.

##  
##  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
źródło
jest to bardzo prawdziwe i w 5 podobnych pytaniach nikt nie wskazał, że chociaż nie możemy tego zrobić -filter *.jpg, *.png, może być szybsze wykonanie -filter * .jpg za jednym razem, niż wykonanie -filter * .png i dołączenie wyników, niż zrób jeden -Include *.jpg, *.png". Mam folder zawierający 126 tys. Plików i 18 tys. Folderów. Szukam rekursywnie jednego pliku i jednego folderu w każdym folderze. użycie -Filter zajmuje 5 sekund, a użycie -Include 30 sekund. Wykonanie -Filter dwa razy w 10 sekund jest trzy razy szybsze niż jedno -Włącz go.
papo
0
Get-ChildItem $originalPath\* -Include @("*.gif", "*.jpg", "*.xls*", "*.doc*", "*.pdf*", "*.wav*", "*.ppt")
DPC
źródło
Witamy w Stack Overflow! Ta odpowiedź pojawiła się w kolejce recenzji niskiej jakości, prawdopodobnie dlatego, że nie wyjaśniłeś treści. Jeśli wyjaśnisz to (w swojej odpowiedzi), jest o wiele bardziej prawdopodobne, że otrzymasz więcej głosów pozytywnych - a osoba pytająca faktycznie się czegoś nauczy!
The Guy with The Hat
2
Ponadto powtarza kod z odpowiedzi, którą opublikowałem wcześniej, z tym wyjątkiem, że zawiera listę rozszerzeń w operatorze oceny wyrażenia tablicowego ( @()), co jest zbędne, ponieważ lista oddzielona przecinkami jest z natury oceniana jako tablica.
Adi Inbar,
-2

użyj dołączenia jest najłatwiejszy, zgodnie z

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

capsch
źródło
1
To nie zadziałało. :( -filter -include *.file, *.types -filter -include (*.file, *.types), -filter -include "*.file", "*.types"i -filter -include ("*.file", "*.types")wszystko z błędami, jak na moje pytanie powyżej Wyeliminowanie. -filterParametr i właśnie w tym -include(tych samych iteracjach cytatów i parens) nie skutkują uruchomieniowych błędów, ale nie było zestaw wyników w katalogu docelowym.
dwwilson66