【问题标题】:Why does "Get-ChildItem -File | Get-FileHash" work?为什么“Get-ChildItem -File | Get-FileHash”有效?
【发布时间】:2020-02-11 20:18:19
【问题描述】:

我对 Bash 比对 Powershell 更熟悉,有时我对后者的对象模型感到困惑。

documentation of Get-FileHash,好像有3种指定输入的方式:

  • Get-FileHash [-Path]
  • Get-FileHash [-LiteralPath]
  • Get-FileHash [-InputStream]

前两个取文件名,第三个取数据流。

现在,Get-ChildItem -File 似乎输出了System.IO.FileInfo 对象,从Get-Member 所说的来看:

$ Get-ChildItem -File | Get-Member
TypeName: System.IO.FileInfo

但管道Get-ChildItem -File | Get-FileHash 工作正常。我的问题是,允许将System.IO.FileInfo 转换为Get-FileHash 期望的输入类型的机制是什么?

【问题讨论】:

标签: powershell


【解决方案1】:

System.IO.FileInfo / System.IO.DirectoryInfo PowerShell cmdlet 输出的实例有一个 .PSPath 属性[*],其中包含实例的完全限定路径,即以 PS 提供程序名称为前缀的完整文件系统路径(例如,Microsoft.PowerShell.Core\FileSystem::C:\windows)。

文件处理 cmdlet 例如Get-FileHash 有一个-LiteralPath 参数有一个别名-PSPath.

因为-LiteralPath 参数(通常)接受来自管道的输入按属性名称,具有.PSPath 属性的输入对象会自动绑定到它,通过凭借PSPath 参数别名。

顺便说一句:

  • 文件处理 cmdlet 还有一个 -Path 参数,它将其参数解释为 wildcard expressions,而不是文字路径。

    • 当您将路径 strings 传递到此类 cmdlet 时,它们会绑定到 -Path,这尤其意味着它们确实被解释为通配符 - 虽然这通常无关紧要,因为大多数文字路径并不包含通配符元字符,它适用于包含 [] 的路径,然后被误解;避免这种误解需要将它们转义为`[`],如this answer 所示。
  • 由于 Windows PowerShell 中的一个错误(自从在 PowerShell (Core) 7+ 中修复),Get-FileHash,具体来说,不接受字符串 通过管道 - 有关详细信息,请参阅this answer


如何发现这种行为:

  • 以编程方式:

    • 注意:Get-Help Get-FileHash -Parameter LiteralPath | Select-Object name, aliases, pipelineinputthis 的情况下也有效,但这种方法通常仅限于目标命令附带基于MAML 的帮助文件,甚至那些可以有帮助文件的命令与实际的命令定义不同步
PS> & {
        Get-Command $args[0] | % Parameters | % $args[1] |
        Select-Object Name, Aliases, @{
            n = 'Accepts pipeline input';
            e = { $(if ($_.Attributes.ValueFromPipeline) { 'by value' }), $(if ($_.Attributes.ValueFromPipelineByPropertyName) { 'by property name' }) -join ', ' -replace '^, ' }
        }
    } Get-FileHash LiteralPath


Name        Aliases      Accepts pipeline input
----        -------      ----------------------
LiteralPath {PSPath, LP} by property name

[*] 添加此属性等的是 PowerShell 的文件系统提供程序。底层 .NET 类型没有拥有它。请参阅this answer 了解更多信息。

【讨论】:

    【解决方案2】:

    来自关于函数高级参数文档,ValueFromPipelineByPropertyName argument section

    ValueFromPipelineByPropertyName 参数表明 参数接受来自管道对象的属性的输入。这 对象属性必须与参数具有相同的名称或别名。

    例如,如果函数具有 ComputerName 参数,并且 管道对象有一个 ComputerName 属性,其值为 ComputerName 属性分配给函数的 ComputerName 参数。

    更新:原来链接了错误的源代码文件。正确的Get-FileHash source code is here。作为@mklement0 correctly answered Get-ChildItem cmdlet 输出一个具有PSPath 属性的对象,这使得这项工作。

    【讨论】:

    • 奇怪的是,路径不起作用。 [pscustomobject]@{path='there'} | get-filehash
    • @js2010 在 Powershell 5.1 中,Accept pipeline input: False 用于参数 Path。另请参阅(Get-Command Get-FileHash).Definition
    • @JosefZ - 感谢您的更正! [pscustomobject]@{LiteralPath='PATH'} | Get-FileHash
    【解决方案3】:

    看起来它使用了 pspath 属性。

    dir there | select pspath | get-filehash
    
    Algorithm  Hash                                                                Path
    ---------  ----                                                                ----
    SHA256     44723DD4D0E0D46A3C7FA8ACA254B61C27B6B5789F96177E82C80700409F1535    C:\users\...
    

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-24
      相关资源
      最近更新 更多