2

I am attempting to use PowerShell to grab useful output from wsl.exe. For the life of me, I cannot seem to match for strings in the output (see below). I get the same behavior in both PowerShell 5 and 7. Does anyone have a reliable means to capture the output of wsl.exe?

Thanks

PS C:\Users\gsamuel> $foo = (wsl -l -v)
PS C:\Users\gsamuel> $foo
  NAME            STATE           VERSION

* Ubuntu-20.04    Running         2


PS C:\Users\gsamuel> $foo | Select-String -Pattern 'Ubuntu'
PS C:\Users\gsamuel> $foo -match 'Ubuntu'
PS C:\Users\gsamuel>
PS C:\Users\gsamuel>
PS C:\Users\gsamuel> [string]$foo | Select-String -Pattern 'Ubuntu'
PS C:\Users\gsamuel> [string]$foo -match 'Ubuntu'
False
IMSoP
  • 89,526
  • 13
  • 117
  • 169
gsamuel
  • 23
  • 2
  • @Bill_Stewart While true, that doesn't explain why this output is _silent_. The example in the help page of `"Hello","HELLO" | Select-String -Pattern "HELLO" -CaseSensitive` outputs `HELLO` if run directly. `"NAME STATE VERSION", "", "* Ubuntu-20.04 Running 2", "" | Select-String -Pattern 'Ubuntu'` also outputs the matched line as I'd expect. – IMSoP Feb 09 '21 at 21:20
  • uh, weird. Output I get from running `wsl -l -v` and putting into a variable has a bunch of spaces in between all of the letters. Looks fine when displayed but when checking the variable it looks like `U b u n t u - 1 8 . 0 4 S t o p p e d` – Daniel Feb 09 '21 at 21:24
  • `https://www.powershellgallery.com/packages?q=WSL` Just look how others do it, or use a premade module. – filimonic Feb 09 '21 at 21:37
  • Try and do `$foo = "$(wsl -l -v)"` to catch it as a string and see if it behaves different. Also do `$foo[0]` and/or `$foo | gm` to double-check it's really a normal string that you're getting and not some console-formatting stuff. – Cpt.Whale Feb 09 '21 at 21:38

2 Answers2

1

This appears to be an encoding issue of some sort: there is a null between each letter of the output, probably because a UTF-16 output is being interpreted as UTF-8.

You can see this by replacing all null characters with @:

$foo = (wsl -l -v)
$foo -Replace "`0", '@'

Which gives this:

 @ @N@A@M@E@ @ @ @ @ @ @ @ @ @ @ @ @S@T@A@T@E@ @ @ @ @ @ @ @ @ @ @ @V@E@R@S@I@O@N@
@
@*@ @U@b@u@n@t@u@-@2@0@.@0@4@ @ @ @ @R@u@n@n@i@n@g@ @ @ @ @ @ @ @ @ @2@
@
@

So the output doesn't actually contain the string "Ubuntu"!

A simple workaround would be to replace those with empty strings:

$foo -Replace "`0", '' | Select-String 'Ubuntu'

Which outputs the expected match:


* Ubuntu-18.04    Stopped         2


IMSoP
  • 89,526
  • 13
  • 117
  • 169
0

This is now fixed in the latest WSL Preview release 0.64.0, but you do have to "opt-in" to the fix so that older workarounds don't inadvertently break.

Adding the environment variable WSL_UTF8 with a value of 1 (and only that value) will now prevent wsl.exe from generating this "mangled" UTF-16 that was causing the issue.

For your example:

> $env:WSL_UTF8=1
> $foo = (wsl -l -v)

> $foo | Select-String -NoEmphasis -Pattern 'Ubuntu'


  Ubuntu20.04_WSL1       Stopped         1
  Ubuntu20.04_WSL2       Stopped         2
  Ubuntu_21.10_WSL2      Stopped         2
  Ubuntu-22.04           Stopped         2
  Ubuntu                 Running         2

> $foo -match 'Ubuntu'

# Same

I'll also point to another solution in this answer for those who can't yet upgrade to Windows 11 and/or the WSL Preview. That solution changes the console's OutputEncoding in PowerShell to force wsl.exe's output to be usable.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70