【问题标题】:Running Line by Line Produces Odd Result Compared to Running Lines as a Single Line with Semicolons与使用分号的单行运行相比,逐行运行会产生奇怪的结果
【发布时间】:2019-04-25 13:52:38
【问题描述】:

我正在尝试创建一个简单的单行 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};

这几乎就像是将最后两个命令通过管道相互传递。或者可能格式已关闭,我不确定。我希望分号会产生与每行一条一条运行相同的结果。

【问题讨论】:

  • 首先,你的两个例子不一样,因为你的第二个例子有$processIds = Get-Process;$processName;而不是$processIds = Get-Process $processName;。除了说“这是 PowerShell 在控制台中为您自动格式化”之外,我无法从技术上解释为什么会发生这种情况。通过运行Get-NetUDPEndpoint | ? {$_.OwningProcess -in $processIds.Id} | format-list *,您可以看到与上一条命令相同的输出。某些东西正在触发格式化以使用所有属性进行列表格式,这是我无法完全解释的。
  • 糟糕,我刚刚在问题中解决了这个问题。这不是它失败的原因,这只是问题中的一个错字:P 感谢您的回复。我也不是很明白,有点奇怪。
  • 在您的第二个示例中,您可以预期事情会略有不同,因为在您按下 Enter 键之前不会向 PowerShell 发送任何内容。因此,发送一个命令,处理它,然后将其输出到控制台与发送所有命令,处理它们,然后等待一个控制台输出是有区别的。好消息是,您可以控制输出的外观,而不是依赖 PowerShell 为您完成。
  • 如果您喜欢第一个输出,您可以使用$processName = "outlook";$processIds = Get-Process $processName;Get-NetTCPConnection | ? {$_.OwningProcess -in $processIds.Id} | ft;Get-NetUDPEndpoint | ? {$_.OwningProcess -in $processIds.Id} | ft; 复制它。只需强制 PowerShell 格式化表格样式。所有的输出数据都是一样的,只是表现不同。
  • 有什么区别?我在我的环境中看不到任何东西。

标签: powershell


【解决方案1】:

TLDR:解决复杂问题是设计使然(请参阅 Github 问题 #4552:Enable formatting of different object types in same pipeline)。

在第一个示例中发生的情况是,每个命令单独输出其对象数据。在这种情况下,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 * 格式。

这是by design,因为很难动态确定单个格式,尤其是当您开始使用混合类型的数组时。他们决定因此最好使用第一个对象来确定类型,然后使用后备处理不同的对象。

我们可以做一些测试来了解 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

这为我们提供了我们可能希望看到的输出,但在同一行中链接多个对象类型可能仍然不是最佳实践。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 2021-06-01
    • 2015-10-04
    • 1970-01-01
    相关资源
    最近更新 更多