"$xyz" 和 "Write-Host "$xyz"" 给出不同的输出

"$xyz" and "Write-Host "$xyz"" giving different output

我正在对一个位置(一个原始文件夹)中的所有文件进行哈希处理,并将哈希值写入一个变量,然后对另一个位置(一个目标文件夹)中的所有文件执行相同的操作:

$origin = Get-ChildItem .\Test1 | Get-FileHash | Format-Table -Property Hash -HideTableHeaders
$destination = Get-ChildItem .\Test2 | Get-FileHash | Format-Table -Property Hash -HideTableHeaders

然后我将它们与 Compare-Object 进行比较,如下所示:

Compare-Object $origin $destination

现在在我的测试中我故意有偏差,所以当上面的代码返回没有差异时我知道我有问题。

然后我发现如果我执行以下操作,哈希值将不存在:

PS> Write-Host "$origin"
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData Microsoft.PowerShell.Commands.Internal.Format.GroupStartData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.GroupEndData Microsoft.PowerShell.Commands.Internal.Format.FormatEndData

但是,如果我只输入以下内容并按回车键,那么哈希值就会出现(就像我想要的那样):

PS> $origin

6B86B273FF34FCE19D6B804EFF5A3F5747ADA4EAA22F1D49C01E52DDB7875B4B
D4735E3A265E16EEE03F59718B9B5D03019C07D8B6C51F90DA3A666EEC13AB35
4E07408562BEDB8B60CE05C1DECFE3AD16B72230967DE01F640B7E4729B49FCE

我假设当我使用 Compare-Object 时,我的变量没有像我预期的那样呈现哈希值。

有谁知道这是怎么回事或者有什么建议吗?这用于确保文件从原始位置移动到目标位置(这是我正在处理的脚本中的一项检查)。我保留这个纯粹的 PowerShell,这意味着没有 xcopyrobocopy.

重新使用 Format-TableCompare-Object 创建输入集合:

仅将 Format-* cmdlet 用于 显示格式;如果数据必须以编程方式处理.

,则切勿使用它们

Format-* cmdlet 输出 格式化指令 ,而不是 数据 - 请参阅 this answer.

因此:

  • 省略 来自输入集合定义命令的 Format-Table 调用:
$origin=Get-ChildItem .\Test1 | Get-FileHash
$destination=Get-ChildItem .\Test2 | Get-FileHash
  • 然后将 属性的名称 传递给 Compare-Object:
  • 来比较对象
Compare-Object $origin $destination -Property Path, Hash

注意需要通过路径和哈希进行比较,以确保只比较同名文件。

顺便说一句:如果您没有指定-Property,默认情况下对象将按它们的.ToString()值进行比较——并且由于Get-FileHash 输出的 Microsoft.PowerShell.Commands.FileHashInfo 个实例只会字符串化为非常 类型的名称 (不管它们的特定 属性 值如何),不会发现任何差异。


至于 $originWrite-Host $orgin

  • 只是执行 $origin 隐含地就像执行 Write-Output $origin - 它写入 成功输出流 (请参阅 about_Redirection),默认情况下 转到控制台。

  • Write-Host,相比之下,有不同的目的 =27=]:

    • 直接写到控制台[1],绕过 PowerShell 的成功输出流及其通常的格式。 其主要目的是将状态消息、交互式提示消息...写入显示器 - 而不是输出数据 .

    • Write-Host 本身应用输出格式,但仅通过简单.ToString() stringification,这通常会产生无用的(仅键入名称)表示,就像您的情况一样。

有关 Write-OutputWrite-Host 之间差异的更多信息,请参阅 this answer


[1] 从技术上讲,从 PowerShell 版本 5 开始,Write-Host 输出通过 information 输出流(编号 6), 但它的主要目的仍然是 写入显示器 而不是 输出数据 .