TLDR:它的设计初衷是为了解决复杂的问题(请参阅 Github 问题 #4552:在同一管道中启用不同对象类型的格式化).
第一个示例中发生的情况是,每个命令单独输出其对象数据。在这种情况下,PowerShell将引用格式文件"C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetTCPIP\Tcpip.Format.ps1xml"
查看对象的默认格式是什么。在本例中,从格式文件中,PowerShell 被告知根据对象的类型将两个对象格式化为表。
当您将命令链接成一个时,First对象将确定整行的输出格式。在此示例中,它将位于Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_NetTCPConnection
格式。由于第二个命令输出一个类型的对象.../MSFT_NetUDPEndpoint
不能以同样的方式对其进行格式化。虽然它可以共享相同的列,因为定义了特定的对象格式,然后 PowerShell 默认以回退方式输出对象,尽力而为Format-List *
format.
This is 按设计因为很难即时确定单独的格式,尤其是当您开始使用混合类型的数组时。因此,他们决定最好使用第一个对象来确定类型,然后通过后备处理不同的对象。
我们可以做一些测试来看看 PowerShell 处理格式的不同方式:
#For brevity sake, let's assign variables for our examples:
$processName = "outlook"
$processIds = Get-Process $processName
$TCP = Get-NetTCPConnection | ? {$_.OwningProcess -in $processIds.Id}
$UDP = Get-NetUDPEndpoint | ? {$_.OwningProcess -in $processIds.Id}
先单独说一下:
PS> $TCP
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting OwningProcess
------------ --------- ------------- ---------- ----- -------------- -------------
0.0.0.0 65045 0.0.0.0 0 Bound 24200
0.0.0.0 56125 0.0.0.0 0 Bound 24200
PS> $UDP
LocalAddress LocalPort
------------ ---------
:: 5353
0.0.0.0 5353
这正是我们想要的。然而,当我们链接对象时,输出将是:
PS> $TCP; $UDP
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting OwningProcess
------------ --------- ------------- ---------- ----- -------------- -------------
0.0.0.0 65045 0.0.0.0 0 Bound 24200
0.0.0.0 56125 0.0.0.0 0 Bound 24200
Caption :
Description :
ElementName :
InstanceID : ::++5353
CommunicationStatus :
DetailedStatus :
HealthState :
InstallDate :
Name :
OperatingStatus :
OperationalStatus :
PrimaryStatus :
Status :
StatusDescriptions :
AvailableRequestedStates :
EnabledDefault : 2
EnabledState :
OtherEnabledState :
RequestedState : 5
TimeOfLastStateChange :
TransitioningToState : 12
AggregationBehavior :
Directionality :
CreationTime : 2019-04-15 9:05:09 AM
LocalAddress : ::
LocalPort : 5353
OwningProcess : 24200
PSComputerName :
Caption :
Description :
ElementName :
InstanceID : 0.0.0.0++5353
CommunicationStatus :
DetailedStatus :
HealthState :
InstallDate :
Name :
OperatingStatus :
OperationalStatus :
PrimaryStatus :
Status :
StatusDescriptions :
AvailableRequestedStates :
EnabledDefault : 2
EnabledState :
OtherEnabledState :
RequestedState : 5
TimeOfLastStateChange :
TransitioningToState : 12
AggregationBehavior :
Directionality :
CreationTime : 2019-04-15 9:05:09 AM
LocalAddress : 0.0.0.0
LocalPort : 5353
OwningProcess : 24200
PSComputerName :
第一个对象正确显示,第二个对象则回落到Format-List *
。现在,让我们添加一个Select
陈述:
PS> $TCP | Select LocalAddress, LocalPort ; $UDP
LocalAddress LocalPort
------------ ---------
0.0.0.0 65045
0.0.0.0 56125
:: 5353
0.0.0.0 5353
在这里我们看到,由于我们正在将 TCP 对象转换为PSCustomObject
,与Select
声明,我们的$UDP
对象可以“适合”表格格式,它与管道中的其余对象一起流动!(注意:这可能是意外的,因为您不知道一个对象在哪里结束,下一个对象从哪里开始!)
最终的解决方法是通过使用来“冲洗”管道Out-String
:
PS> $TCP | Out-String; $UDP
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting OwningProcess
------------ --------- ------------- ---------- ----- -------------- -------------
0.0.0.0 65045 0.0.0.0 0 Bound 24200
0.0.0.0 56125 0.0.0.0 0 Bound 24200
LocalAddress LocalPort
------------ ---------
:: 5353
0.0.0.0 5353
这为我们提供了我们可能希望看到的输出,但在同一行中链接多个对象类型可能仍然不是最佳实践。