在PowerShell中,Get-ChildItem -Exclude无法与-Recurce参数一起使用

时间:2018-08-03 07:01:11

标签: powershell

enter image description here我想递归搜索所有以_(下划线)开头的目录。

例如:_archive_DO_NOT_DELETE_processing

我使用了下面的代码,但它不起作用。看来exclude不能与递归一起使用。有什么想法吗?

$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\" 
$allitems = Get-ChildItem $source -Directory -Exclude $exclude -Recurse
foreach($myItem in $allitems)
{
  echo $myItem.fullname
} 

输出:

C:\code\Powershell\delete empty folders\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder
C:\code\Powershell\delete empty folders\New folder\_archive\New folder

因此,正如我之前告诉我的那样,我要避免使用下划线开头的目录,因此最后一行不应该出现。

即使我也使用下面的代码,输出仍然相同:

$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory |
            Where {$_.FullName -notlike $exclude}
foreach($myItem in $allitems)
{
    echo $myItem.fullname
}

3 个答案:

答案 0 :(得分:4)

这里发生的是,Get-ChildItem的-exclude参数基于项目的name属性工作。使用通配符时,名称必须与非通配符部分匹配。当目录名以空格开头时,不会发生这种情况。我们来看一个例子:

# Create two files, one starts with a space, the other doesn't
Set-Content -Path " data1.txt" -Value $null
Set-Content -Path "data2.txt" -Value $null

gci -name "data*"
 data2.txt

gci -name " data*"
 data1.txt

结果是一场比赛,使用了通配符。原因是data1.txt的第一个字符是空格,并且与参数的第一个字符d不匹配。

-exclude因棘手而臭名昭著。通过将结果传递到where-object,通常更容易解决。像这样

Get-ChildItem $source -Directory -recurse | ? {$_.fullname -NotMatch "\\\s*_"} | % { $_.fullname }
# "\\\s*_" is regex for \, any amount of whitespace, _ 
C:\code\Powershell\delete empty folders\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder

Get-ChildItem $source -Directory -recurse | ? {$_.fullname -Match "\\\s*_"} | % { $_.fullname }
C:\code\Powershell\delete empty folders\New folder\ _archive
C:\code\Powershell\delete empty folders\New folder\ _archive\New folder

请注意,匹配需要评估FullName属性。仅使用Name只会匹配叶子级别。

答案 1 :(得分:1)

尚未找到第一次尝试的答案。但是,如果要使用Where-Object,则必须将过滤器从_*更改为*_*

这是因为.Fullname显示了完整路径,因此在实际路径_之前还有更多字符。

$exclude = @("*_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory | Where {$_.FullName -notlike $exclude}
$allitems.Fullname

应该给您期望的输出。

答案 2 :(得分:1)

正如@Paxz在评论中所说,该命令正在按预期方式工作,只是没有您希望的那样。它肯定从输出中排除了以_开头的文件夹,但这不适用于-Recurse开关,因此它仍在这些文件夹中查找其他项目,并显示(如果它们的名称确实如此)不是以_开头。

您可以使用自己的过滤器获取所需内容:

Get-ChildItem -Path $source -Directory -recurse |
    Where-Object {$_.FullName -notlike "*\_*"} |
        Format-Table FullName

请注意,这仍然会找到所有带有_的文件夹,但只会丢弃它们(因此,性能没有改善)。另外,使用更简单的过滤器:-notlike "*_*"会排除名称中部或结尾带有下划线的所有文件夹(例如Hello_World),而不仅仅是开头。