Home > Blockchain >  Script in powershell not working with array variables
Script in powershell not working with array variables

Time:05-21

I am creating a PowerShell script just to backup my WSL distros, but when I try to run the command with variables it's not working, it displays the usage text as though I provided the incorrect arguments.

$DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
$DistrosArray2 = 'Arch', 'Ubuntu-22.04', 'docker-desktop-data', 'docker-desktop'

$CheckArrayDifference = Compare-Object -ReferenceObject $DistrosArray1 -DifferenceObject $DistrosArray2 -PassThru
echo $CheckArrayDifference

# Does not return anything (there is no difference)

foreach ($Distro in $DistrosArray1) {
    wsl --export $Distro "$Distro.tar"
    # This method is not working
  }

foreach ($Distro in $DistrosArray2) {
    wsl --export $Distro "$Distro.tar"
    # This method is working
  }

CodePudding user response:

This is part of a known issue with wsl.exe output. Here is what I put together from workarounds provided on that issue:

$DistrosArray1 = wsl -l --quiet | wsl iconv -c -f utf16 -t ascii

foreach ($Distro in $DistrosArray1) {
  wsl --export $Distro "$Distro.tar"
}

Unfortunately I could not get this working with a conversion to UTF8 (changing ascii to utf8 produces additional garbage characters although they are consistent and detectable in my limited testing), so only any characters outside of the ASCII range will likely cause problems for you.

CodePudding user response:

It sounds like you are running into complications from issue #4607 -- The wsl.exe command outputs some oddly mangled UTF16 encoding that creates issues when attempting to process it from PowerShell (or even from inside WSL).

Let's simplify the problem and make a "safe" example that doesn't attempt to export:

$DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
wsl -d $DistrosArray1[0]

Results in:

There is no distribution with the supplied name.

I've successfully used the method in this comment to handle it. For this particular example:

$console = ([console]::OutputEncoding)
[console]::OutputEncoding = New-Object System.Text.UnicodeEncoding
$DistrosArray1 =  (wsl -l --quiet) | where {$_ -ne ""}
wsl -d $DistrosArray1[0]

This will run the first distribution in the list correctly.

Reset the encoding after with:

[console]::OutputEncoding = $console

That shouldn't be a problem for most non-interactive scripts since it will just be the final line of the "wrapper", but as @BendertheGreatest pointed out in the comments, it's a critical step.

  • Related