powershell - 与使用分号的单行运行相比,逐行运行会产生奇怪的结果
问题描述
我正在尝试创建一个简单的单行 Powershell 命令,该命令将列出给定进程名称的所有 TCP 和 UDP 端口。
如果我逐行运行,它会产生预期的输出。如果我将所有四行代码放在一行中,并使用分号分隔各行,则会产生不同的结果。请看下面的两个代码示例:
这是设置进程名称的四个单独的行,使用该进程名称来获取基于进程名称的一些 PID。然后使用进程 PID 过滤来自底部两个命令的结果。
$processName = "outlook"
$processIds = Get-Process $processName
Get-NetTCPConnection | ? {$_.OwningProcess -in $processIds.Id}
Get-NetUDPEndpoint | ? {$_.OwningProcess -in $processIds.Id}
以上工作。如果我将所有这些行放在一行中并用分号分隔它们,我会得到不同的结果:
$processName = "outlook";$processIds = Get-Process $processName;Get-NetTCPConnection | ? {$_.OwningProcess -in $processIds.Id};Get-NetUDPEndpoint | ? {$_.OwningProcess -in $processIds.Id};
就好像它将最后两个命令相互传递一样。或者可能格式已关闭,我不确定。我希望分号会产生相同的结果,就好像每一行都在一条一条地运行一样。
解决方案
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 *
格式输出对象。
这是设计使然,因为很难动态确定单个格式,尤其是当您开始使用混合类型的数组时。他们决定因此最好使用第一个对象来确定类型,然后使用后备处理不同的对象。
我们可以做一些测试来看看 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
这为我们提供了我们可能希望看到的输出,但在同一行中链接多个对象类型可能仍然不是最佳实践。
推荐阅读
- c3.js - c3.js条形图:如何对角显示数据标签
- powerbi - 在 D365 中为 Finance and Operations 自定义 Power BI 报表
- javascript - Javascript + Spring Boot + Thymeleaf - 表单验证
- python - 如何将列表中的多个项目与另一个列表中的一个元素匹配?
- c# - API 调用后无法反序列化当前 JSON 数组
- javascript - window.settimeout 功能在 ios safari 和 android 浏览器中无法正常工作
- google-apps-script - GOOGLE FORM - 如何指定我要在 Google 表单中上传文件的文件夹名称?
- javascript - 是否有任何选项可以从对象数组中单独获取键值并将其作为单引号内的单独对象数组
- javascript - 使用 JSON.parse 和 JSON.stringify 的 Javascript 深拷贝
- java - 使用 ODFDOM Java API 编写 ODF 电子表格文档