【问题标题】:How to properly -filter multiple strings in a PowerShell copy script如何在 PowerShell 复制脚本中正确过滤多个字符串
【发布时间】:2013-09-08 02:56:11
【问题描述】:

我正在使用来自this answer 的 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

那么我做错了什么,我该如何纠正呢?

【问题讨论】:

    标签: powershell filter copy powershell-2.0


    【解决方案1】:

    -Filter 只接受单个字符串。 -Include 接受多个值,但限定 -Path 参数。诀窍是将\* 附加到路径的末尾,然后使用-Include 选择多个扩展名。顺便说一句,在 cmdlet 参数中不需要引用字符串,除非它们包含空格或 shell 特殊字符。

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

    请注意,无论 $originalPath 是否以反斜杠结尾,这都会起作用,因为多个连续的反斜杠被解释为单个路径分隔符。例如,尝试:

    Get-ChildItem C:\\\\\Windows
    

    【讨论】:

    • 呜呼! \* 这个技巧刚刚解决了大约六个问题。太棒了,谢谢!
    • 请注意,指定-Recurse时不需要通配符(\*)。
    • 由于某种原因这在搜索目录时不起作用?
    • 添加 -Recurse 允许它访问子文件夹
    • -Recuse 不适用于-Include(关于遍历子目录)。
    【解决方案2】:

    这样的事情应该可以工作(它对我有用)。想要使用-Filter 而不是-Include 的原因是与-Filter 相比,include 对性能造成了巨大影响。

    下面只是循环每个文件类型和在单独文件中指定的多个服务器/工作站。

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

    【讨论】:

    • 这是非常正确的,在 5 个类似的问题中,没有人指出,虽然我们不能做 -filter *.jpg, *.png,但一次做 -filter *.jpg 可能比做更快-过滤 *.png 并加入结果,而不是一个 -Include *.jpg, *.png"。我有一个包含 126k 文件和 18k 文件夹的文件夹。我正在递归地在每个文件夹中搜索一个文件和一个文件夹。使用 -Filter 需要 5 秒,使用 -Include 需要 30 秒。做 - 在 10 秒内过滤两次比一次 - 包括 go 快三​​倍。
    【解决方案3】:

    让我们来看看选项:

    • -Filter 只采用一种模式,因此对于此问题不起作用

    • -Include 有效,但 very slow (在许多情况下完全没问题)。

    • 连接到 Where-Object-Include 快得多。它也是最强大的选项,因为它使您可以访问 regex 模式匹配(而不是普通的通配符匹配)和您可能需要的任何其他逻辑,例如在下面的例子:

      # 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 仍然稍微快一些,但使用完整路径而不是文件名,这很难使用(参见下面的示例)并且仅适用于简单的情况,因为路径模式无法匹配可变数量的目录级别。这与典型的 shell 不同,其中* 匹配单个目录,** 匹配任意数量的嵌套目录。

      # 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
      

    【讨论】:

      【解决方案4】:
      Get-ChildItem $originalPath\* -Include @("*.gif", "*.jpg", "*.xls*", "*.doc*", "*.pdf*", "*.wav*", "*.ppt")
      

      【讨论】:

      • 欢迎来到 Stack Overflow!这个答案出现在低质量审核队列中,大概是因为您没有解释内容。如果你确实解释了这一点(在你的回答中),你更有可能获得更多的支持——提问者实际上学到了一些东西!
      • 此外,它重复了我之前发布的答案中的代码,除了它将扩展列表包含在数组表达式评估运算符 (@()) 中,这是多余的,因为逗号分隔list 本质上被评估为一个数组。
      【解决方案5】:

      【讨论】:

      • 那行不通。 :( -filter -include *.file, *.types -filter -include (*.file, *.types)-filter -include "*.file", "*.types"-filter -include ("*.file", "*.types") 根据我上面的问题都出错了。消除 -filter 参数并只包括 -include (引号和括号的相同迭代)没有结果在 runtime 错误,但在目标目录中没有结果集。
      猜你喜欢
      • 2019-03-25
      • 1970-01-01
      • 1970-01-01
      • 2020-05-08
      • 2019-07-04
      • 2022-09-23
      • 1970-01-01
      • 2010-09-06
      相关资源
      最近更新 更多