事情是这样的。我正在对一些代码进行故障排除,我注意到一个奇怪的行为。如果我使用以下代码:
$UpdateHistory = Get-WUHistory -last 1
$TodaysDate = (Get-Date)
$UpdateHistory.Date
$TodaysDate.DateTime
我得到了输出:
Sunday, April 17, 2022 10:01:13 AM
Thursday, April 21, 2022 11:23:00 AM
但是,如果我使用以下代码:
$UpdateHistory = Get-WUHistory -last 1
$TodaysDate = (Get-Date)
$UpdateHistory
$UpdateHistory.Date
$TodaysDate.DateTime
我得到这样的输出:
ComputerName Operationname Result Date Title
------------ ------------- ------ ---- -----
RedactedComputerName Installation Succeeded 4/17/2022 3:01:1... Windows Malicious Software Removal Tool x64 - v5.100 (KB890830)
Date : 4/17/2022 12:00:00 AM
Day : 17
DayOfWeek : Sunday
DayOfYear : 107
Hour : 10
Kind : Unspecified
Millisecond : 0
Minute : 1
Month : 4
Second : 13
Ticks : 637857864730000000
TimeOfDay : 10:01:13
Year : 2022
DateTime : Sunday, April 17, 2022 10:01:13 AM
Thursday, April 21, 2022 11:23:56 AM
这到底是怎么回事?在第4行中使用$Updatehistory的原因只是为了查看条目列表,但它似乎从根本上改变了对象。这让我大吃一惊。
这个问题类似于为什么在一行中运行两个PowerShell命令时会改变输出格式?
长话短说:管道中的第一个对象输出可能会影响后续对象的呈现方式,特别是当它们不是同一类型时。
要获得一致的输出,要么在输出之前显式地转换它,要么将输出管道到format-table或format-list。
这不是改变对象,而是改变对象的显示方式:
smartiprefect的回答提供了一个伟大而简洁的总结;让我再深入一点:
具体来说,你会看到PowerShell的for-display输出格式化系统的以下行为:
-
您正在向主机(显示)输出不同类型的多个对象。
-
第一个输出对象
$UpdateHistory
包含一个数据类型,为其定义了显式格式化数据,该数据默认为表视图(隐式Format-Table
使用)。 -
因为第二个输出对象是不同的类型(
[datetime]
),第一个对象的格式化数据不能应用,PowerShell默认为Format-List
格式化(就好像你已经调用了$UpdateHistory.Date | Format-List
)-
警告:
如果第一个输出对象(非基本类型)有没有与其类型相关的格式化数据,如果对象有4个或更少(公共)属性,PowerShell默认为
Format-Table
格式化,如果对象有5个或更多,则默认为Format-List
,显示所有这些属性。当选择
Format-Table
格式时,显示列根据第一个对象的属性被锁定在中。如果后续对象没有这些属性,它们可能在输出中看起来完全缺失:它们仍然存在,但不产生可见的输出。
一个简单的例子,一个
[pscustomobject]
实例后面跟着一个[datetime]
实例([pscustomobject]
类型没有预定义的格式化数据与之关联):# !! Note how the Get-Date output appears to be missing. PS> [pscustomobject] @{ one = 1; two = 2; three = 3 }; Get-Date one two three --- --- ----- 1 2 3
更多信息请看答案
-
警告:
-
第三个输出对象是另一种类型
[string]
,字符串总是输出与值相同的。
解决方案是至少对您的第一个对象单独强制立即格式化输出到主机,这在Out-Host
中是最简单的:
$UpdateHistory | Out-Host # Force instant formatted output to the host.
$UpdateHistory.Date
$TodaysDate.DateTime
但是,请注意,这绕过了成功输出流,因此以这种方式发送到显示的对象不再是脚本数据输出的一部分。
同样,如果你使用Format-*
cmdlet而不是Out-Host
,它是表示格式化指令的对象被发送到成功输出流;虽然它们在主机(显示)中按预期呈现,但它们作为数据是无用的。(但是,您可以将格式化cmdlet与Out-Host
结合使用;例:Get-ChildItem | Format-Table | Out-Host
).