Coding Agents & Terminal · recorded 2026-08-29 · applies to 1 tool(s) ✓ Verified

Problem: Garbled output when calling wsl.exe from PowerShell (UTF-16LE / every character spaced) —— Trove problem library

Verified 2026-08-29garbled wsl output in PowerShell — set WSL_UTF8=1 at the top of the script (or `cmd /c set WSL_UTF8=1 && wsl ...`).

Quick fix

# One-liner (inside a PowerShell script): set the official UTF-8 switch, wsl output returns to normal
$env:WSL_UTF8 = "1"

Put it at the script start; or temporarily cmd /c "set WSL_UTF8=1 && wsl ...".

What you will run into

Calling wsl.exe ... from PowerShell (5.1 and 7) garbles the output: w s l : ... with a space between every character (UTF-16LE 00 bytes shown as characters), wsl --help | more prints one character per line (official issue microsoft/WSL#13093), Chinese content becomes �.

Direct wsl echo hi > file (cmd redirection) bytes are fine; the broken cases are pipe/capture scenarios: PowerShell script assignment, CI capture, | pipelines.

Why this happens

In pipe/non-TTY scenarios wsl.exe outputs UTF-16LE (no BOM); PowerShell captures it and writes downstream per its own stdout encoding (measured: both PS 5.1 and pwsh 7 -Command chains get UTF-16LE no BOM);

downstream decodes as UTF-8/single-byte → every ASCII char separated by 00, Chinese all �.

This is wsl.exe's known behavior, still present in 2025's #13093 (WSL 2.5.7).

wsl.exe is a Windows program, and it decides output encoding by where the output goes: connected to a terminal it emits UTF-8;

connected to a pipe/non-TTY it emits Windows-native wide characters, UTF-16LE without BOM — this is wsl.exe's defined behavior, not bash's choice.

PowerShell captures it and forwards it using its own stdout encoding, and downstream programs that assume UTF-8/single-byte decode every ASCII byte followed by a 00 as a character — Chinese becomes mojibake and ASCII gets padded with nulls.

Deterministic takeaway: never rely on wsl.exe output for text parsing in pipeline scenarios; two correct paths — wsl.exe -e bash -lc "..." so the bash layer controls output encoding, or declare [Console]::OutputEncoding=[Text.Encoding]::UTF8 in PowerShell;

for file output, redirect inside Linux (wsl bash -lc 'cmd > file') to bypass wsl.exe's encoding decision entirely.

Step by step

1. Set $env:WSL_UTF8 = "1" — Required

Official Microsoft switch; measured: under pwsh -File, wsl output becomes normal UTF-8; if you don't want global change, put it at the script start.

2. Don't hand-build complex/long command lines — Required

Escaping and length both blow up. Write the script to a file inside WSL and execute it:

wsl bash /tmp/x.sh

PowerShell writes files via UNC: Set-Content \\wsl.localhost\Ubuntu\tmp\x.sh.

3. Use base64 transport for very long/special-char content — Required

wsl bash -lc "echo <base64> | base64 -d | bash"

Measured working; dodges the quoting/escaping/length pitfalls.

4. Route output through files — Required

Have the in-WSL command write results to /tmp/out.txt, then read with Get-Content \\wsl.localhost\Ubuntu\tmp\out.txt — UTF-8 files read directly with no encoding issues, more reliable than pipes.

5. Auxiliary measures — Required

[Console]::OutputEncoding = [Text.Encoding]::UTF8 affects PowerShell's console-output encoding; can combine with #1. The WSL startup banner ("Detected localhost proxy configuration...

") is stderr noise: with WSL_UTF8 set it's not garbled; if you mind it, ignore it or add 2>$null.

How to confirm it works

Byte-level verification (measured output shape):

After $env:WSL_UTF8="1" in a ps1, & wsl.exe echo hi → bytes 77 73 6C 3A 20 E6 A3 80 (normal UTF-8, Chinese intact)

Reproduction baseline: pwsh -NoProfile -Command "wsl echo hi" → bytes 77 00 73 00 6C 00 ... (UTF-16LE no BOM, measured).

Other environments

EnvironmentNotes
cmd redirectionBytes fine (UTF-8, measured control)
PowerShell pipe/captureUTF-16LE no BOM (reproduced on both PS 5.1 and pwsh 7; same as #13093)
base64 channel`wsl bash -lc "echo <b64>base64 -d"` measured working
File relay/tmp/out.txt + UNC read; no encoding issues (used daily)
stderr bannerNot garbled after WSL_UTF8; add 2>$null if it bothers you

Symptom

Calling wsl.exe ... from PowerShell (5.1 and 7) produces garbled output:

w s l :  �hKm0R ...   # spaces between every character (UTF-16LE 00 bytes rendered as characters)
wsl --help | more     # one character per line (microsoft/WSL#13093 official issue)
Chinese content becomes � replacement chars

Key traits: direct wsl echo hi > file (cmd redirection) is fine (UTF-8 bytes); the damage is in pipe/capture scenarios: PowerShell variable assignment, CI capture, | pipes; WSL also prints a proxy-detection banner (stderr) at startup, making it worse.

Cause

wsl.exe emits UTF-16LE (no BOM) when its stdout is a pipe/non-TTY; PowerShell captures it and writes it out with its own stdout encoding (measured: both PS 5.1 and pwsh 7 -Command paths produce UTF-16LE without BOM); the downstream consumer decodes it as UTF-8/single-byte → every ASCII char is separated by 00, Chinese becomes �. This is known wsl.exe behavior, still present in #13093 (WSL 2.5.7, 2025).

Solution

  1. Set $env:WSL_UTF8 = "1" in the script before calling wsl (official Microsoft switch; measured: under pwsh -File, wsl output becomes proper UTF-8);

put it at the top of the script, or use cmd /c "set WSL_UTF8=1 && wsl ..." for one-offs.

  1. Do not hand-build complex/long command lines (escaping and length will bite): write the script into a file inside WSL and run it:

wsl bash /tmp/x.sh; from PowerShell write via UNC: Set-Content \\wsl.localhost\Ubuntu\tmp\x.sh.

  1. Base64 transport for long/special-char content: wsl bash -lc "echo <base64> | base64 -d | bash" (verified; bypasses quoting/escaping/length).
  2. Route output through files: have the WSL command write to /tmp/out.txt, then read with Get-Content \\wsl.localhost\Ubuntu\tmp\out.txt —

reading a UTF-8 file directly avoids the pipe encoding problem entirely.

  1. Auxiliary: [Console]::OutputEncoding = [Text.Encoding]::UTF8 affects how PowerShell writes to the console; combine with 1.
  2. The WSL startup banner ("localhost proxy detected...") is stderr noise: with WSL_UTF8 it stops garbling; ignore or 2>$null it.
Verification Evidence
  • Local repro (2026-08-29, Windows 11 + WSL Ubuntu, PowerShell 5.1 and pwsh 7):
  • Control: wsl.exe echo hi > file from cmd → bytes 68 69 0A (UTF-8, fine);
  • Repro: pwsh -NoProfile -Command "wsl echo hi" > file → bytes 77 00 73 00 6C 00 ... (UTF-16LE without BOM),

displayed as "w s l :" garbage when decoded as UTF-8 — same as #13093; PowerShell 5.1 reproduces identically;

  • Fix: with $env:WSL_UTF8="1" in a ps1, & wsl.exe echo hi → bytes 77 73 6C 3A 20 E6 A3 80 (proper UTF-8, Chinese intact);
  • Base64 channel: wsl bash -lc "echo dGVzdA== | base64 -d" → test (exit 0);
  • File relay: write /tmp/out.txt inside WSL, read via UNC — no encoding issues (used daily in practice).

Evidence details kept locally (2026-08-29)

Applicable tools (1)

This problem is linked from the tool pages below — reachable from either side.

wsl

Source & evidence

Recorded Verified ✓ VerifiedApplies to 1 tool(s)
Entries contain locally measured or reviewable-source solutions; unmeasured items are explicitly labeled.

Source: https://github.com/microsoft/WSL/issues/13093

← Coding Agents & Terminal domain | Problem Catalog Experience | Facing another issue? Go to the Helpdesk