PowerShell,使用-Depth输出的Get-ChildItem

3

我对 Get-ChildItem 的 -Depth 标志有些困惑。以下示例很好地工作(在“C:\Program Files”下查找所有一级深度的文件和文件夹):

dir 'C:\Program Files\' -Depth 1

但是,如果我想要扩展它以仅查找*.txt类型的文件,则找不到如何实现此目标的方式(下面的命令将忽略-Depth 1并执行相当于对所有子文件夹进行递归搜索):
dir 'C:\Program Files\*.txt' -Depth 1
dir 'C:\Program Files\' -Include *.txt -Depth 1
dir 'C:\Program Files\*' -Include *.txt -Depth 1

如何使用-Depth参数来获取特定深度和所需文件模式的Get-ChildItem命令?

4个回答

3
您所看到的行为是 Windows PowerShell 中的一个bug,但在 PowerShell [Core] 6+ 中已经解决了 - 可以查看此 GitHub 问题

由于 Windows PowerShell 已不再积极开发,因此很可能不会修复此错误。

换句话说,在以下情况下,Windows PowerShell 忽略了 -Depth 的深度约束:

  • 使用 -Include-Exclude
  • 如果(隐含的)-Path 参数包含通配符字符。

虽然仍会执行 递归,但没有施加深度限制;实际上,在这些情况下,-Depth 的行为类似于单独使用 -Recurse

解决方法:

  • 对于使用-Include和基于通配符的-Path参数,其中通配符仅限于最后一个路径组件的情况:

    • 请改用-Filter,如Wasif Hasan的回答所示。
    • 注意-Filter通常比较优越,因为其性能更好,但其通配符语言不如PowerShell强大,并且有遗留问题 - 特别是,字符集和范围([...])不受支持,在Windows PowerShell中,诸如*.xls之类的过滤器也会匹配*.xlsx文件,例如,请参见此回答
  • 对于-Exclude

    • 仅使用-Depth,并在之后使用Where-Object调用进行过滤;例如:
      Get-ChildItem -File 'C:\Program Files\' -Depth 1 | Where-Object Name -NotLike *.txt
  • [可能很少需要] 对于基于通配符的-Path参数,其通配符字符(同样)出现在不是最后一个组件中的情况(例如,C:\foo*\bar

    • 使用-Recurse并在之后使用Where-Object进行过滤; 在这种情况下,您还必须通过计算其组件数来清除太深的路径。

1
好知道,谢谢Michael。是的,我无法理解这种不直观的行为。如果微软能够为PS 5.1发布错误修复,那将是很好的。我们将长期使用PS 5.1,因为它具有许多仅在PS 6和7中没有的Windows特定功能。希望在某个时候微软能够认识到这一点。不需要将任何6/7功能移植回5.1,但至少修复错误会很有用。(PS v5.1 SP1!) - YorSubs
1
明白了,@YorSubs;即将推出的v7.0是为v5.1的可行替代而努力,但它永远无法提供Windows PowerShell所能提供的“一切”。如果更多的修复程序被回溯,那确实会很好,但只有安全关键问题才有可能得到解决。UserVoice是Windows PowerShell错误报告的官方位置,但不幸的是,那里报告的大多数问题似乎从未得到解决。 - mklement0
在PS v7上,(Get-WMIObject win32_operatingsystem).name 的结果是 Get-WMIObject: The term 'Get-WMIObject' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.。如果PS v7缺少WMI,那真的是一个致命问题。是否有模块可以重新添加WMI,以便在Windows上运行PS v7时使用,否则我就无法在我的工作或个人项目中使用它? :-( - YorSubs
1
@YorSubs,这是标准建议:CIM cmdlets(例如Get-CimInstance)在PowerShell v3(于2012年9月发布)中取代了WMI cmdlets(例如Get-WmiObject)。因此,应避免使用WMI cmdlets,尤其是因为所有未来的工作都将在PowerShell _Core_上进行,而它们已经不再拥有。有关更多信息,请参见此答案 - mklement0
1
哦,我明白了,那就太好了。我想我有点记得听说过一段时间,但我猜我从来没有真正跟上这些事情(如果它有效,那就行!)。非常感谢,我会尝试将所有的WMI转换为CIM,希望不会太困难。 - YorSubs

2
当您使用Filter而不是Include时,问题得以解决。过滤器参数将以正确的深度模式返回文件。(已测试)
dir 'C:\Program Files\' -Filter *.txt  -Depth 1

一个有效的解决方法; 值得注意的两件事:在 PowerShell [Core] 6+ 中,不再需要这个解决方法,因为已经修复了潜在错误-Filter通常更适用于提高性能,但它的行为与 PowerShell 自己的通配符匹配有所不同 - 参见此答案 - mklement0

1
在早期版本的PowerShell中,没有深度限制,这种情况下上述内容也可以使用。
Get-ChildItem -Path "C:\DIRECTORY\*","C:\DIRECTORY\*\*"

如果这仅涉及文件名,则为纯文本。
(Get-ChildItem -Path "c:\program files" -file -Depth 3 -Force -erroraction SilentlyContinue).FullName

与古代的技巧相同,即。
(cmd.exe /c dir "c:\program files" /b /a-d /s)|foreach {if ($_.split("\").length -le 5){$_}}

令人惊讶的是,PowerShell甚至比上述代码更快!我记得几年前并非如此,但我刚刚测试了一下,它快了3-4倍。


0

为了进一步澄清Wasif Hasan的答案,我查看了Get-ChildItem的官方文档,其中指出:

当使用-Include参数时,如果在路径中不包含星号,则命令不返回任何输出。

这意味着Depth将自动被忽略,因为Include所需的行为是递归的。此外,-Include的一些细节揭示了以下几点。

如果将Recurse参数添加到命令中,则Path参数中的尾随星号(*)是可选的。Recurse参数从Path目录及其子目录获取项目。例如,-Path C:\Test\ -Recurse -Include *.txt

因此,您要寻找的行为位于Get-ChildItemFilter标志中,不需要任何通配符。

对我来说,深度标志与任何其他接受路径中通配符的标志一起使用是没有意义的,因为深度标志的目的是限制在项目中搜索的深度,而指定通配符则排除了该特定目的。 您可以通过使用以下命令来尝试此操作,并将看到如果您在路径中指定通配符,则深度参数无效,例如:
Get-ChildItem -Path C:\DIRECTORY\* -Depth 1

Get-ChildItem -Path C:\DIRECTORY\* -Depth 2

将会返回相同的结果。

希望这能澄清一些问题。


1
是的,谢谢,我也正要说这个不合理。给我一个错误,或者一个有意义的警告来指示我的语法可能有误,不要给我奇怪的、意料之外的结果。我看不出为什么 Depth 不能被编写成在这些其他情况下运行如预期。这似乎有点反效果。我想知道这个 Cmdlet 的作者对这个奇怪的输出结果在想什么。 - YorSubs
1
该行为是Windows PowerShell中的一个错误,已在PowerShell [Core] 6+中修复 - 请参见此GitHub问题。是的,-Filter不需要以*结尾的-Path参数才能生效,但是如果也执行递归,则-Include也不需要,而使用-Depth则意味着-Recurse。正是这个错误使得您的两个具有不同深度的C:\DIRECTORY\*命令输出相同的结果 - -Depth限制再次被忽略。 - mklement0
@mklement0 对报告的问题表示同意,但不确定为什么 -Include 的官方文档会声明需要在路径中使用通配符,否则将返回空值。 - DevX
1
@DevX,这是由于一个_无关的问题_,即不幸的事实是 _没有递归_,-Include 模式首先与 _输入路径本身_匹配,这意味着通常 _什么也不匹配_。将 \* 添加到输入路径可解决该问题-请参见此答案的底部部分。按照现有写法,您的答案会导致分散注意力,因为它增加了混淆,请考虑修改它。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接