dutchrebel
dutchrebel

Reputation: 23

Powershell SetEnvironmentVariable not setting the variables as expected

I'm attempting to save some environment variables based on the output of the command "wsl --list" using Powershell, when I debug this code it seems to be flowing as expected however when I inspect my environment variables I'm unable to find the expected keys and values.

When I use the same SetEnvironmentVariable method with any other hardcoded value it seems to work. Write-Host on $distroName results in the expected string too so I'm honestly lost on this. Any help would be appreciated! Here is my code:

$wslListOutput = wsl --list
((Get-ChildItem env:*).Name | Select-String -Pattern "(SINDAGAL_INIT_DISTRO_([a-zA-Z=])*)|SINDAGAL_DEFAULT_DISTRO")
foreach ($line in $wslListOutput)
{
  $lineIsEmpty = ("" -eq $line) -or ([string]::IsNullOrWhiteSpace($line))
  $Introline = $line -eq "Windows Subsystem for Linux Distributions:"

  if($lineIsEmpty -or $Introline){ continue } 
  
  if($line -Match "(([a-zA-Z]*) ([(Default)])*)"){
     $distroName = ($line -split ' ',2)[0]    
     [System.Environment]::SetEnvironmentVariable("SINDAGAL_DEFAULT_DISTRO",$distroName)
  } else{
     $distroName = $line.ToUpper()
     $variablePath = "Env:SINDAGAL_INIT_DISTRO_${distroName}"
     [System.Environment]::SetEnvironmentVariable("SINDAGAL_INIT_DISTRO_${distroName}",$true)
  }
}

# Cannot see the variables which are supposed to be set in here at all
((Get-ChildItem env:*).Name)

my wsl --list output:

┖[~]> wsl --list
Windows Subsystem for Linux Distributions:
Debian (Default)
Alpine

Upvotes: 2

Views: 1180

Answers (1)

zett42
zett42

Reputation: 27756

Cause

This is an encoding issue. Redirected output of wsl is UTF-16 LE encoded, which is not automatically recognized by PowerShell (as of PS 7.1.5). Instead it always interprets the output using the encoding stored in [Console]::OutputEncoding, which on Windows defaults to the given system's legacy OEM code page (e.g. 437 on US-English systems).

As UTF-16 is a two-byte encoding we typically end up with embedded \0 characters (code points below 256, such as the ASCII character set). These cause the string to be clipped, when calling SetEnvironmentVariable, because the API expects null-terminated strings.

Solution

Set [Console]::OutputEncoding to match the output encoding of the process, before launching it and restore the original encoding afterwards.

$oldEncoding = [Console]::OutputEncoding
[Console]::OutputEncoding = [Text.Encoding]::Unicode  # on Windows: UTF-16 LE

$wslListOutput = wsl --list

[Console]::OutputEncoding = $oldEncoding

Another common output encoding used by some programs is [Text.Encoding]::UTF8.

See this answer for more in-depth information and an Invoke-WithEncoding cmdlet, which automates the process of temporarily changing and restoring the encoding.

Upvotes: 3

Related Questions