Как правильно отфильтровать несколько строк в сценарии копирования PowerShell

Я использую сценарий PowerShell из этого ответа, чтобы сделать копию файла. Проблема возникает, когда я хочу включить несколько типов файлов, используя фильтр.

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

работает как сон. Однако проблема возникает, когда я хочу включить несколько типов файлов с помощью фильтра.

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 }

Дает мне следующую ошибку:

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

У меня есть различные итерации скобок, без скобок, -filter, -includeопределяя включения как переменные (например, $fileFilter) и каждый раз получаю вышеуказанную ошибку и всегда указываю на то, что следует -filter,

Интересное исключение из этого, когда я кодирую -filter "*.gif,*.jpg,*.xls*,*.doc*,*.pdf*,*.wav*,*.ppt*", Ошибок нет, но я и результатов не получаю и ничего не возвращаю в консоль. Я подозреваю, что непреднамеренно закодировал and с этим утверждением?

Так что я делаю не так, и как я могу это исправить?

5 ответов

Решение

-Фильтр принимает только одну строку. -Include принимает несколько значений, но квалифицирует аргумент -Path. Хитрость заключается в добавлении \* до конца пути, а затем используйте -Include для выбора нескольких расширений. Кстати, строки в кавычках не нужны в аргументах командлета, если они не содержат пробелов или специальных символов оболочки.

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

Обратите внимание, что это будет работать независимо от того, заканчивается ли $ originalPath на обратную косую черту, поскольку несколько последовательных обратных косых черт интерпретируются как один разделитель пути. Например, попробуйте:

Get-ChildItem C:\\\\\Windows

Давайте рассмотрим варианты:

  • -Filterтребуется только один шаблон, поэтому он не работает .

  • работает, но очень медленно (во многих случаях это нормально).

  • Трубопровод к быстрее чем -Includeно по-прежнему требует получения полного списка файлов. Это наиболее эффективный вариант, поскольку он дает вам доступ к сопоставлению шаблонов регулярных выражений (вместо обычного сопоставления глобусов ). Он также, возможно, более читабелен, чем последний вариант ниже, особенно если вы уже используете Where-Object для фильтрации по другим свойствам файла.

            # 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- самый быстрый вариант, но он принимает полные пути, а не имена файлов, что немного неудобно.

            # the basic idea
    Get-ChildItem $dir\*.xls, $dir\*.xlsx, $dir\*.jpg, $dir\*.jpeg
    
    # easier to read
    $extensions = 'xls', 'xlsx', 'jpg', 'jpeg'
    $paths = $extensions | ForEach-Object { Join-Path $dir *.$_ }
    Get-ChildItem $paths
    

Как-то так должно работать (у меня так получилось). Причина желания использовать -Filter вместо -Include является то, что включает в себя огромный удар по производительности по сравнению с -Filter,

Ниже просто циклы каждого типа файлов и несколько серверов / рабочих станций, указанных в отдельных файлах.

##  
##  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
Get-ChildItem $originalPath\* -Include @("*.gif", "*.jpg", "*.xls*", "*.doc*", "*.pdf*", "*.wav*", "*.ppt")

Использовать включение является самым простым способом согласно

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

Другие вопросы по тегам