在一行中运行两个PowerShell命令时,为什么更改了输出格式?

时间:2019-04-03 18:33:56

标签: powershell formatting

执行两个以分号分隔的PowerShell命令时,我得到了意外的结果。第二个命令的输出更改。如果以相反的顺序运行它们,则看不到第二个命令输出。

在这里,我只是想获得一个时间戳和一个用户属于AD的组列表(单行)。

如果我运行此行,则会得到以下输出:

Get-ADPrincipalGroupMembership username | Select-Object name

name
----
Domain Users
CL-Inventory-Group
...

但是,如果我运行以下命令,此行为将发生变化:

get-date; Get-ADPrincipalGroupMembership username | Select-Object name

Wednesday, April 3, 2019 2:31:35 PM

name : Domain Users


name : CL-Inventory-Group


...

还很陌生,如果我以相反的方式运行,这意味着我在第一个命令后说了get-date,则列出组之后,日期戳永远不会显示。

我不正确地分隔命令吗?

2 个答案:

答案 0 :(得分:3)

当Powershell控制台格式化程序看到多种类型的对象时,它将默认为根据第一个元素输出进行输出。对于Date,它作为列表输出,对于Select-Object中的自定义对象输出,它是一个表。输出的格式设置取决于对象本身的类型(请参阅帮助About Format.ps1xml)。您可以使用Select-ObjectFormat-Table的输出强制为表格:

get-date; Get-ADPrincipalGroupMembership username | Select-Object name | Format-Table

答案 1 :(得分:3)

tl;博士

在提示符下(交互地)提交多个;分隔的命令仍会将其输出发送到单个管道(您可以将每个命令行视为一个隐式脚本文件提交)。

简而言之:在您的情况下,第一个命令输出的自动显示格式也确定了第二个命令的显示格式,因此哪个命令最重要:

  • get-date; Get-ADPrincipalGroupMembership username | Select-Object name

    • 对于Format-List之后的所有输出,都隐式地使用Get-Date,这解释了Get-ADPrincipalGroupMembership ...命令输出的每个属性行。
  •   

    如果我执行相反的操作,这意味着我在第一个命令后说了get-date,则列出组之后,日期戳永远不会显示。

    • Select-Object类型为[pscustomobject]的输出实例,由于在这种情况下仅具有1个属性,因此它们被锁定在 tabular 显示中,即隐式使用{{ 1}},具有选定的属性作为唯一列,即此处为Format-Table。由于Name输出的[datetime]类型没有Get-Date属性,因此Name的输出实际上是 invisible

请继续阅读以获取背景信息和完整规则。


PowerShell的默认显示格式已针对相同类型的对象进行了优化,这是典型的情况。

如果管道包含类型的 mix ,则默认情况下产生的特定格式取决于

  • 管道中对象的 order
  • 及其默认格式设置行为

有关详细信息,请参见下一节。

您可以使用明确的Get-Date调用来控制格式;您可以在第二个命令上使用Format-*来强制以表格形式输出:

Format-Table

注意事项:来自Get-Date; Get-ADPrincipalGroupMembership username | Select name | Format-Table cmdlet 的输出是格式化说明,而不是原始数据,因此该输出不适合进一步的程序处理


PowerShell如何在同一管道中格式化不同类型的对象以进行显示:

在没有显式格式命令(Format-*Format-Table,...)的情况下, PowerShell根据给定的条件自动选择合适的显示格式对象的类型

  • 如果存在给定类型,PowerShell将使用预定义的格式说明(请参见Get-Help about_Format.ps1xml
  • 如果没有他们:
    • 如果类型是原始类型(请参见下文):输出对象的Format-List表示形式。
    • 否则,将根据以下简单规则选择格式样式:4个或更少的属性? -> .ToString(); 5个或更多? -> Format-Table

注意:原始在这里被宽松地指代:

  • 所有原始CLR类型-.IsPrimitive返回Format-List的那些类型,即
    $true[Boolean][Byte],{{1} },[SByte][Int16][UInt16][Int32][UInt32][Int64][UInt64][IntPtr][UIntPtr][Char]
  • 类型[Double][Single][decimal][bigint]
  • 任何其他无属性类型。

如果管道中的所有对象都属于同一类型,则上述按定义适用于所有对象。

相反,如果管道中存在类型的 mix ,则适用以下逻辑:

  • 任何原始类型的实例总是都打印相同的,即表示它们是单个值(不是通过调用其[string]方法获得的具有属性的对象 );例如[securestring].ToString()12;基本类型与管道中后续对象的格式无关。

  • 管道中的第一个非原始对象

    • 本身是根据其预定义的格式说明或上述默认规则(基于属性的数量)进行打印的。

    • 锁定所有剩余的非原始对象的格式样式-列表与表格

      • 如果对象本身隐式使用3.0hi,那么所有其余非原始对象也将使用。
      • 如果对象隐式使用Format-Table(例如,对于Format-List,通过预定义格式),则锁定的是Format-Custom
  • 所有随后的非原始对象都将使用锁定的格式样式。

    • 注意事项:如果锁定了 Get-Date ,则第一个非原始对象 确定属性集显示为表格列,如果它们没有这些属性,则可能会导致后续对象似乎消失 -这些对象仍在输出流中,但是,它们没有显示 -请参见this answer进行演示。

      • 附带说明:自PSv5以来,Format-List的隐式使用会导致异步行为,这可能令人惊讶。参见this answer
    • 如果锁定的是Format-Table,则不会丢失任何信息,因为每个对象的属性随后会在其各自的行中分别列出。