powershelltypesreflection

Win32 Executable Output Parsing with PowerShell


my $PSVersionTable output is as follows:

Name                           Value
----                           -----
PSVersion                      7.0.1
PSEdition                      Core
GitCommitId                    7.0.1
OS                             Microsoft Windows 10.0.19041
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

If I enter

wsl -l | Get-Member

the output informs me that the output type is a String.

If I enter

(wsl -l).GetType()

the output informs me that the output type is Array.

The entire reason I'm looking at this is that I was trying to parse the output of that command and for a long, frustrating time, I was thinking that I was working with a single, contiguous string with embedded carriage return / line feeds, but it appears I'm actually working with an array of strings.

So my question: what do the parentheses around the command do to seemingly change the nature of the output of the executable? Is it that without the parentheses the output from 'wsl -l' is being streamed to Get-Member one line (array element) at a time?

Thank you!


Solution

  • If you want to use Get-Member to inspect an object as-is, you mustn't use the pipeline, because the pipeline auto-enumerates arrays (enumerables), and Get-Member then reports the (distinct set of) types among their elements.

    Instead, use Get-Member -InputObject, which reports on arrays (enumerables) as a whole:

    Get-Member -InputObject (wsl -l) # -> shows the members of type System.Object[]
    

    PowerShell streams the stdout output from external programs such as wsl, line by line. That is, it sends each line as it is being received to the pipeline.

    If you assign the command's output to a variable or enclose the command in (), the grouping operator, the stream output is collected:

    If you want to avoid this ambiguity and ensure that the result is always an array, you can use @(), the array-subexpression operator - @(wsl -l) - or, on assigning to a variable, type-constrain that variable as an array - [array] $out = wsl -l


    To get a single, potentially multi-line string representation of the output, use the -join operator:

    # See note re character encoding below.
    (wsl -l) -join "`n"   # or use [Environment]::NewLine instead of "`n"
    

    [Environment]::NewLine returns the platform-appropriate newline char. / sequence, i.e. LF-only ("`n") on Unix-like platforms, CRLF ("`r`n") on Windows. However, PowerShell happily accepts either form on all platforms.

    Note: