anonmous
anonmous

Reputation: 139

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!

Upvotes: 1

Views: 134

Answers (1)

mklement0
mklement0

Reputation: 439647

If you want to use Get-Member to inspect an object as-is, you mustn't use the pipeline, because the pipeline enumerates objects that are collection-like, and Get-Member then reports the (distinct set of) types among the elements of the collection.

Instead, use Get-Member -InputObject, which reports on collections 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 there's only one output line, a (single) [string] instance is returned.

  • If there are multiple output lines, PowerShell collects them in a regular, [object[]]-typed array for you, whose elements are [string] instances in this case.

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:

(wsl -l) -join "`n"   # or use [Environment]::NewLine instead of "`n"

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

Note:

  • While the Out-String cmdlet would return a single, multi-line string too, it invariably adds a trailing newline. (If you were to use -NoNewLine, it wouldn't use any newlines).

If you're using PowerShell [Core] v6.2+, you can alternatively use the Join-String cmdlet:

wsl -l | Join-String -Separator "`n"

Upvotes: 1

Related Questions