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?
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
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:
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.
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:
Get-Help about_Format.ps1xml
).ToString()
representation is output.Format-Table
; 5 or more? -> Format-List
.Note: Primitive is used loosely here to refer to:
.IsPrimitive
returns $true
, namely [Boolean]
, [Byte]
, [SByte]
, [Int16]
, [UInt16]
, [Int32]
, [UInt32]
, [Int64]
, [UInt64]
, [IntPtr]
, [UIntPtr]
, [Char]
, [Double]
, [Single]
[decimal]
, [bigint]
, and [securestring]
[string]
(strings always print as themselves, in full)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 and 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:
Format-Table
or Format-List
, so will all remaining non-primitive objects.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:
If the first non-primitive object has no formatting data associated with it - which notably applies to [pscustomobject]
- it
can cause subsequent non-primitive 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.
If the first non-primitive object has formatting data associated with it (as reported by Get-FormatData
), all subsequent non-primitive objects of a different type are formatted with Format-List
. That is, you'll get a mix of tabular and list-style output.
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.
When the powershell console formatter sees objects of multiple types, it will default to outputting based on the first element output. For Date
it output as a list, for the custom object output from Select-Object
, it's a table. How the output is formatted depends on the type of the object itself (see help About Format.ps1xml). You can force the output of Select-Object
to be a table using Format-Table
:
get-date; Get-ADPrincipalGroupMembership username | Select-Object name | Format-Table
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With