2

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
  }
codewario
  • 19,553
  • 20
  • 90
  • 159
Antonio Costa
  • 101
  • 1
  • 6

2 Answers2

3

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).

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 (like the ones @Bender and I provided) don't inadvertently break.

Simply set:

$env:WSL_UTF8=1

... before your code, and WSL will no longer spit out the "mangled UTF16."

Other examples in my answers to:

Older solution:

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.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
  • 2
    Nice find on that workaround :) PSA for all readers though; it's *especially important you change the console encoding back as suggested*. Particularly before you display anything else or start processing additional strings. – codewario May 20 '22 at 21:03
  • hehe got it. I am facing this error using this approach "Error mounting one of the file systems. Run 'dmesg' for more details". I have excluded docker-desktop and docker-desktop-data from the array. – Antonio Costa May 20 '22 at 21:20
  • @AntonioCosta Hmm - With `docker-desktop` and `docker-desktop-data` excluded, we need to find which instance is having the issue, so I'd recommend putting a `echo $Distro` inside the loop to determine that. – NotTheDr01ds May 20 '22 at 21:54
  • I found the distro that's having the problem. Actually, I am just using Ubuntu-22.04 and Arch. The Arch Linux is the one that's having the problem. When I write "Arch" string works normally. – Antonio Costa May 20 '22 at 22:08
  • @AntonioCosta Just to make sure I understand -- "Arch" in the `foreach` loop gives the error, but running it as a hardcoded string is fine? And that happens with both my workaround and Bender's? – NotTheDr01ds May 20 '22 at 22:16
  • Yep, exactly. The literal string "Arch" works, but inside the foreach loop no. – Antonio Costa May 20 '22 at 22:20
  • @AntonioCosta Hmmm - does it give the same error if you use `$DistrosArray2`? *Edit* -- Nevermind. I see you said that worked in the original question .... Hmmm. – NotTheDr01ds May 20 '22 at 22:30
  • Yep. I spent some hours trying to solve this hehe. – Antonio Costa May 20 '22 at 22:34
  • @AntonioCosta Sorry to leave you hanging on this. Any progress on your end? If not, a few things to try -- (a) Make sure to `wsl --shutdown` before running the script, (b) Is there any custom kernel in play, or is the stock WSL2 kernel? (c) Is the kernel the latest? (`wsl --update`), (d) Might be worth trying with Docker Desktop not running, (e) Might be worth putting a `Start-Sleep -Seconds 10` at the beginning of the loop to see if a delay helps. – NotTheDr01ds May 23 '22 at 18:39
  • Hehe, that's okay. You really helped me a lot in answering the questions. Actually, I didn't have any progress after that, but I will try these things. Answering the questions, a) I will try this; b) The distro that I am running is Arch and Ubuntu. 22-04. Actually, Arch, it's not an official distro from Microsoft, but I didn't have any problems. c) Ubuntu is 22.04 and Arch is 5.10.16.3. d) I will try to do this as well. e) I didn't think about this. I will try as well. – Antonio Costa May 24 '22 at 18:36
  • @AntonioCosta No worries - And (b) and (c) are actually about the *kernel* being used, but trust me, you'd have answered differently if you had swapped out the WSL2 kernel ;-). So I'm fairly confident you are using the stock kernel that comes from Microsoft. Still, worth a `wsl --update`, which will pull in the latest kernel from Microsoft just to be sure. – NotTheDr01ds May 24 '22 at 18:49
1

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.

codewario
  • 19,553
  • 20
  • 90
  • 159
  • How about `-t UTF8` instead? That's what I typically use *inside* WSL, at least. If that doesn't work from PowerShell, though my guess would be that we're then seeing the "normal" PowerShell side-effect of adding carriage returns when piping through an external command. – NotTheDr01ds May 20 '22 at 20:55
  • @NotTheDr01ds I already covered that case. I've already tried with `-f utf16` along with LE and BE variants, as well as tried converting all of those attempts to `-t ascii` and `-t utf8`. The only mixes I found that results in the expected output is `-f utf16 -t ascii` or `-f utf16le -t ascii` (which `UTF-16` on windows defaults to little-endian anyways so that's little surprise both work) – codewario May 20 '22 at 21:00
  • 1
    Oops - Missed that. Actually, misread it. – NotTheDr01ds May 20 '22 at 21:02
  • Oh, got it. I tried to run these commands and this is the message that's appearing: "Error mounting one of the file systems. Run 'dmesg' for more details." – Antonio Costa May 20 '22 at 21:05
  • 1
    @AntonioCosta That's likely the `docker-desktop` and/or `docker-desktop-data` images. I'd recommend skipping those. Trying adding something like `$DistrosExcluded = "docker-desktop-data","docker-desktop"; $DistrosArray1 = $DistrosArray1 | ? {$_ -notin $DistrosExcluded }` – NotTheDr01ds May 20 '22 at 21:06
  • A reminder too that problems with the `wsl --export` command itself are off topic here, @AntonioCosta. But what you've asked about not being able to consume the output from the command is totally fine. – codewario May 20 '22 at 21:08
  • Oh, got it @BendertheGreatest. Maybe I need to change the question title? – Antonio Costa May 20 '22 at 21:15
  • I have tried use this to consume the output $DistrosArray3 = (wsl -l --quiet | wsl iconv -c -f utf16 -t ascii) | where {$_ -ne "" -And $_ -ne "docker-desktop-data" -And $_ -ne "docker-desktop"} and I am getting the same error /: – Antonio Costa May 20 '22 at 21:16
  • Did you check `$DistrosArray3` contains what you are expecting? – codewario May 20 '22 at 21:31
  • Yep, this has worked :) but now I am having another problem :(. In the for each loop, My Ubuntu Distro worked, but when Arch comes it's showing this error: "The network name cannot be found." But when I use "Arch" instead works normally. – Antonio Costa May 20 '22 at 21:37
  • Honestly I would recommend a new question for that problem, since it's distinct from your original question, but it'll likely be found off topic for Stack Overflow. I recommend asking about that particular issue with `wsl --export` over at [su] or [sf]. – codewario May 20 '22 at 22:14
  • I saw your comment on the other answer, that's odd it works with the hard-coded string and not the wsl-provided one for arch. I would still recommend asking about that behavior on one of the other sites though, or chime in on the Github issue both NotTheDr01ds and I linked to. – codewario May 20 '22 at 22:27
  • That's okay. I will try asking in another forum. Thank you for the help. – Antonio Costa May 20 '22 at 22:55