Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.1k views
in Technique[技术] by (71.8m points)

formatting - Why is the output format changed when running two PowerShell commands in one line?

I'm getting unexpected results when executing two PowerShell commands separated by a semicolon. The output of the second command changes. If I run them in reverse order, I don't see the second command output.

Here I'm simply trying to get a time stamp and a list of groups a user belongs to in AD, as a one-liner.

If I run this line, i get the following output:

Get-ADPrincipalGroupMembership username | Select-Object name

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

However if I run the following, this behavior changes:

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

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

name : Domain Users


name : CL-Inventory-Group


...

Stranger yet, If i run the in reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.

Am I improperly separating commands?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

tl;dr:

Submitting multiple ;-separated commands at the prompt (interactively) still sends their output to a single pipeline (you can think of each command line submitted as an implicit script file).

In short: in your case, the first command output's automatic display formatting also determined the display formatting for the 2nd command, so which command comes first matters:

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

    • locked in implicit use of Format-List for all output following Get-Date, which explains the each-property-on-its-own line output from the Get-ADPrincipalGroupMembership ... command.
  • If i run the reverse, meaning i say get-date after the first command, the date stamp never shows up after the groups are listed.

    • Select-Object output instances of type [pscustomobject], which, due to their having just 1 property in this case, locked in tabular display, i.e., implicit use of Format-Table, with the selected property as the only column, i.e., just Name here. Since the [datetime] type output by Get-Date doesn't have a Name property, Get-Date's output was effectively invisible.

Read on for background information and the complete rules.


PowerShell's default display formatting is optimized for objects of the same type, as that is the typical case.

If a pipeline contains a mix of types, the specific formatting that results by default depends on:

  • the order of objects in the pipeline
  • and their default formatting behavior

See the next section for details.

You can use explicit Format-* calls to control the formatting; in your case, you can use Format-Table on your 2nd command to force tabular output:

Get-Date; Get-ADPrincipalGroupMembership username | Select name | Format-Table

Caveat: The output from Format-* cmdlets are formatting instructions rather than the original data, which makes this output unsuitable for further programmatic processing.


How PowerShell formats objects of different types in the same pipeline for display:

In the absence of explicit formatting commands (Format-Table, Format-List, ...), PowerShell automatically chooses a suitable display format, based on a given object's type:

  • If present for a given type, PowerShell uses predefined formatting instructions (see Get-Help about_Format.ps1xml)
  • In their absence:
    • If the type is a primitive type (see below): the object's .ToString() representation is output.
    • Otherwise: the format style is chosen based on the following simple rules: 4 or fewer properties? -> Format-Table; 5 or more? -> Format-List.

Note: Primitive is used loosely here to refer to:

  • all primitive CLR types - those for which .IsPrimitive returns $true, namely
    [Boolean], [Byte], [SByte], [Int16], [UInt16], [Int32], [UInt32], [Int64], [UInt64], [IntPtr], [UIntPtr], [Char], [Double], [Single]
  • types [decimal], [bigint], [string] and [securestring]
  • any other property-less types.

If all objects in a pipeline are of the same type, the above by definition applies to all of them.

By contrast, if there is a mix of types in the pipeline, the following logic applies:

  • Any instances of primitive types always print the same, namely as a representation of the single value that they are (not an as an object with properties), obtained via a call to their .ToString() method; e.g., 12 or 3.0 or hi; primitive types have no bearing on the formatting of subsequent objects in the pipeline.

  • The first non-primitive object in the pipeline:

    • is itself printed based on either its predefined formatting instructions or the default rules stated above (based on the number of properties).

    • locks in the format style - list vs. table - for all remaining non-primitive objects:

      • If the object itself implicitly uses Format-Table or Format-List, so will all remaining non-primitive objects.
      • If the object implicitly uses Format-Custom (e.g, in the case of Get-Date, via predefined formatting), it is Format-List that is locked in.
  • All subsequent non-primitive objects then use the locked-in format style.

    • Caveat: If Format-Table is locked in, the first non-primitive object alone determines the set of properties displayed as table columns, which can cause subsequent objects to seemingly disappear if they don't have these properties - such objects are still in the output stream, however, they're just not displayed - see this answer for a demonstration.

      • On a side note: Since PSv5, implicit use of Format-Table results in asynchronous behavior that may be surprising; see this answer.
    • If it is Format-List that is locked in, no information is "lost", as each object's properties are then listed individually, on their own lines.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...