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!
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 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:
# 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:
wsl.exe
meta commands such as -l
, i.e. commands that provide information about or relate to managing distributions (as opposed to interacting with a given distribution) by default output "Unicode", i.e. UTF-16LE-encoded strings; in order for PowerShell to interpret them correctly, additional work is needed - see this answer. In the simplest case, make sure that $env:WSL_UTF8 = 1
is in effect.
If you're using PowerShell (Core) 7, you can alternatively use the Join-String
cmdlet:
wsl -l | Join-String -Separator "`n"
While the Out-String
cmdlet would return a single, multi-line string too, it invariably adds a trailing newline (and if you were to use -NoNewLine
, it wouldn't use any newlines); this surprising behavior is the subject of GitHub issue #14444.