Symptom
On a French Windows Server 2022, accented characters in command output come back mangled:
$ winrm-java -h tc-win2022 -u Administrateur -pf pass.txt cmd "dir /A"
Le volume dans le lecteur C n'a pas de nom.
Le num‚ro de s‚rie du volume est E6B6-D774
R‚pertoire de C:\Users\Administrateur
...
23/07/2026 15:46 786ÿ432 NTUSER.DAT
7 fichier(s) 2ÿ324ÿ500 octets
é becomes ‚ (U+201A) and the thousands separator (a non-breaking space) becomes ÿ. This is not
a console-rendering artifact: the String the library returns already holds the wrong characters.
Hex-dumping the CLI output shows L e n u m 202 r o — byte 0x82 is é in CP437, decoded here
as windows-1252 ‚.
Root cause
Two halves of the code disagree about which code page the remote shell speaks:
-
Shell creation pins the console code page to OEM 437:
Envelopes.createShell sends
<wsman:Option Name="WINRS_CODEPAGE">437</wsman:Option>. Verified on the host — running chcp
through the library reports Page de codes active : 437.
-
Output decoding follows the ANSI code page:
WindowsRemoteProcessUtils.getWindowsEncodingCharset() runs
SELECT CodeSet FROM Win32_OperatingSystem, which returns 1252 on this host, and decodes
stdout/stderr as windows-1252.
Win32_OperatingSystem.CodeSet is the ANSI code page, never the console (OEM) one, so the two
settings can only ever agree on a US-English host where 437 and 1252 happen to share the ASCII
range. On any non-English locale the mapping is wrong:
| byte |
CP437 (what the shell emits) |
windows-1252 (how we decode) |
| 0x82 |
é |
‚ U+201A |
| 0xFF |
NBSP |
ÿ |
Fix
Stop juggling code pages: create the shell with WINRS_CODEPAGE=65001 and decode command output as
UTF-8 unconditionally. This is what winrs and other WinRM clients do on supported Windows
versions, it is lossless for every locale (including CJK, which no single-byte OEM page can carry),
and it removes the SELECT CodeSet FROM Win32_OperatingSystem round trip currently made before
every command just to guess the charset.
Scope:
Envelopes.createShell: WINRS_CODEPAGE 437 → 65001.
- Default the command-output charset to UTF-8 instead of detecting it over WMI
(WinRMClient.detectCharset, WinRMCommandExecutor, WsmanClient.executeCommand).
- Deprecate
WindowsRemoteProcessUtils.getWindowsEncodingCharset() — no longer used by the
library, and it answers a question (ANSI code page) that never matched the shell's output.
CommandRequest.charset(Charset) stays as an explicit override; document that the remote shell
now emits UTF-8, so overriding is only needed for a shell whose code page was changed by the
command itself.
- Note the encoding behaviour in
README.md.
WQL is unaffected: results travel as UTF-8 in the SOAP envelope and never went through this path.
Verification
Rerun dir /A against a French host and check the accented output is intact, plus a round trip of
non-Latin-1 characters (e.g. echo of CJK text) that CP437 could not represent at all.
Symptom
On a French Windows Server 2022, accented characters in command output come back mangled:
ébecomes‚(U+201A) and the thousands separator (a non-breaking space) becomesÿ. This is nota console-rendering artifact: the
Stringthe library returns already holds the wrong characters.Hex-dumping the CLI output shows
L e n u m 202 r o— byte0x82iséin CP437, decoded hereas windows-1252
‚.Root cause
Two halves of the code disagree about which code page the remote shell speaks:
Shell creation pins the console code page to OEM 437:
Envelopes.createShellsends<wsman:Option Name="WINRS_CODEPAGE">437</wsman:Option>. Verified on the host — runningchcpthrough the library reports
Page de codes active : 437.Output decoding follows the ANSI code page:
WindowsRemoteProcessUtils.getWindowsEncodingCharset()runsSELECT CodeSet FROM Win32_OperatingSystem, which returns1252on this host, and decodesstdout/stderr as windows-1252.
Win32_OperatingSystem.CodeSetis the ANSI code page, never the console (OEM) one, so the twosettings can only ever agree on a US-English host where 437 and 1252 happen to share the ASCII
range. On any non-English locale the mapping is wrong:
é‚U+201AÿFix
Stop juggling code pages: create the shell with
WINRS_CODEPAGE=65001and decode command output asUTF-8 unconditionally. This is what
winrsand other WinRM clients do on supported Windowsversions, it is lossless for every locale (including CJK, which no single-byte OEM page can carry),
and it removes the
SELECT CodeSet FROM Win32_OperatingSystemround trip currently made beforeevery command just to guess the charset.
Scope:
Envelopes.createShell:WINRS_CODEPAGE437 → 65001.(
WinRMClient.detectCharset,WinRMCommandExecutor,WsmanClient.executeCommand).WindowsRemoteProcessUtils.getWindowsEncodingCharset()— no longer used by thelibrary, and it answers a question (ANSI code page) that never matched the shell's output.
CommandRequest.charset(Charset)stays as an explicit override; document that the remote shellnow emits UTF-8, so overriding is only needed for a shell whose code page was changed by the
command itself.
README.md.WQL is unaffected: results travel as UTF-8 in the SOAP envelope and never went through this path.
Verification
Rerun
dir /Aagainst a French host and check the accented output is intact, plus a round trip ofnon-Latin-1 characters (e.g.
echoof CJK text) that CP437 could not represent at all.