如何在 PowerShell 复制脚本中正确过滤多个字符串
Posted
技术标签:
【中文标题】如何在 PowerShell 复制脚本中正确过滤多个字符串【英文标题】:How to properly -filter multiple strings in a PowerShell copy script 【发布时间】: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
?
那么我做错了什么,我该如何纠正呢?
【问题讨论】:
【参考方案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】:
使用包含是最简单的方法
http://www.vistax64.com/powershell/168315-get-childitem-filter-files-multiple-extensions.html
【讨论】:
那行不通。 :(-filter -include *.file, *.types
-filter -include (*.file, *.types)
、-filter -include "*.file", "*.types"
和 -filter -include ("*.file", "*.types")
根据我上面的问题都出错了。消除 -filter
参数并只包括 -include
(引号和括号的相同迭代)没有结果在 runtime 错误,但在目标目录中没有结果集。以上是关于如何在 PowerShell 复制脚本中正确过滤多个字符串的主要内容,如果未能解决你的问题,请参考以下文章
powershell Quick Powershell脚本用于复制文件并使用文件类型过滤保留文件夹结构
powershell Quick Powershell脚本用于复制文件并使用文件类型过滤保留文件夹结构
如何从我的 Powershell 脚本中的 Get-ADUser 过滤器获取结果,以便验证该用户是不是存在?