3

I need to find my wsl kernel version in a script, so I'm trying to run wsl --status to find it out, but when I try to -match it, PowerShell won't find what I'm looking for:

$wsl = wsl --status
(Invoke-Command { wsl --status | Out-String }) -match 'kernel'
False

I was able to find a workaround using IndexOf:

$wsl = wsl --status
(Invoke-Command { wsl --status | Out-String }).IndexOf('kernel')
412

That workaround definitely solves my problem, but I'd like to understand what's going on, because it makes no sense to me.

Maybe it's a character encoding issue, I don't know... So far, I tried changing [Console]::OutputEncoding and using [System.Text.Encoding]::Convert, [System.Text.Encoding]::UTF8.GetString and [System.Text.Encoding]::UTF8.GetBytes with no success.

Thanks in advance!

Zé Cláudio
  • 113
  • 5
  • 1
    Does this answer your question? [Script in powershell not working with array variables](https://stackoverflow.com/questions/72323974/script-in-powershell-not-working-with-array-variables). I believe what you are seeing here is a known issue with `wsl`'s output being somewhat garbled UTF16. – NotTheDr01ds May 27 '22 at 23:27
  • 2
    Note that, encoding issues aside, your `.IndexOf()` call fundamentally cannot work, because it case-sensitively looks for _lowercase_ `kernel`, whereas the output contains `Kernel` – mklement0 May 28 '22 at 00:28
  • 2
    @mklement0, my language is PT-br, so the word "kernel" comes lowercase here. Tanks for your response, anyway! – Zé Cláudio May 30 '22 at 16:06
  • 1
    Good to know, @ZéCláudio, but with the case-sensitivity problem out of the way, you _would_ run into the encoding issue. Simplifying your command to the following (there's no good reason to use `Invoke-Command` for _local_ commands), `(wsl --status | Out-String).IndexOf('ernel')` yields `-1` for me. Solving this problem indeed requires setting `[Console]::OutputEncoding = [System.Text.Encoding]::Unicode` first in order to match the UTF-16LE encoding that `wsl` outputs with meta commands such as `--status` an `--list`, as shown in the linked duplicates and at the bottom of Doug's answer. – mklement0 May 30 '22 at 20:41

1 Answers1

2

For some reason there is a null character after each character.

(wsl --status) -match "k`0" | Format-Hex

   Label: String (System.String) <216842AD>

          Offset Bytes                                           Ascii
                 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
          ------ ----------------------------------------------- -----
0000000000000000 00 4B 00 65 00 72 00 6E 00 65 00 6C 00 20 00 76  K e r n e l   v
0000000000000010 00 65 00 72 00 73 00 69 00 6F 00 6E 00 3A 00 20  e r s i o n :
0000000000000020 00 35 00 2E 00 31 00 30 00 2E 00 31 00 30 00 32  5 . 1 0 . 1 0 2
0000000000000030 00 2E 00 31 00                                   . 1

I haven't figured out why it is there. You can remove it like this.

(wsl --status) -replace "`0"

Not sure why you are using Invoke-Command, you can simplify to this.

(wsl --status) -replace "`0" -match 'kernel'

Now this will return the matching line since the left hand side is an array. This is equivalent to $true in a true/false check. To force a boolean you could use Out-String like you did before, cast to boolean, etc

(wsl --status | Out-String) -replace "`0" -match 'kernel'

[bool]((wsl --status) -replace "`0" -match 'kernel')

Edit

As Santiago pointed out in the comments, setting the encoding to

[Console]::OutputEncoding = [System.Text.Encoding]::Unicode

resolves this particular issue.

(wsl --status) -match "kernel"
Doug Maurer
  • 8,090
  • 3
  • 12
  • 13