上週介紹過用 PowerShell 串接 EXE 輸出結果的技巧,後續遇到一個問題 - 有些 EXE 程式輸出的中文會變亂碼。

例如,findstr 與 pktmon 在未加參數時會顯示中文說明:

同樣用 | ForEach-Object { $_ } 串接顯示,findstr 沒問題,pktmon 的中文說明卻會變亂碼:

原以為跟 DOS CodePage 有關,試過切換 cpch 65001 無效。

找到一篇微軟 PowerShell 部落格,得知有個 $OutputEncoding 可以排除 PowerShell Pipeline 輸出到 EXE 的編碼問題 (例如:test.txt 內容為"中文",Get-Content test.txt | findstr /c:中 會比對不到,需將 $OutputEncoding 改為中文語系),但加了 $OutputEncoding = [Console]::OutputEncoding (中文 Windows 的 [Console]::OutputEncoding 預設為 Big5 950) 一樣沒用。

我想起之前還學過一招 $PSDefaultParameterValues['*:Encoding'] = 'utf8' 可修改 Cmdlet 編碼,理論上影響與外部程式溝通的是 $OutputEncoding,但我已進入病急亂投醫模式,雖然心虛還是先試再說,果然,沒有科學根據亂試會成功都是奇蹟。

還是回歸科學分析吧! 我找到 pktmon 亂碼有段「help 憿舐內?孵??賭誘...」原文為「help 顯示特定命令的說明文字。」,試著剖析它是怎麼錯亂的。

花了點時間,我找出它錯亂的來源:

上面程式成功重現 憿舐內?孵??賭誘... 這段亂碼,方法是硬把 UTF-8 內容當成 BIG5 解析。

由這個結果,我有個猜想,莫非 pktmon 輸出的是 UTF-8 編碼,但 [Console]::OutputEncoding 預設值為 BIG5(950),硬把 UTF-8 當 BIG5 解才搞出亂碼。那如果把 [Console]::OutputEncoding 改成 UTF-8 呢? 薑薑薑薑~~~ 就這麼成功了!

但我觀察到另一個現象,findstr、ping 原本說明文字為中文,在設定 [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 之後,兩支程式都改顯示英文。

關於這點,我的推論是 - findstr、ping 這些存在多年的程式比較成熟,有能力偵測 Console.OutputEncoding 自動切換語系編碼,而 Pktmon 剛出道還很青澀,只會統一輸出 UTF-8。不過,既然我們已知道上述技巧,未來遇到 Pipeline 接 EXE 輸出變成亂碼,就知道該怎麼做囉~

Tips of setting [Console]::OutputEncoding to fix currupted encoding when receiving output of EXE from pipeline.


Comments

# by Huang

可能和windows register的語系有關?

# by Bruce

黑大,我找到一個系統層級的設定,可以一次解決Console亂碼問題,可以參考一下:https://blog.kkbruce.net/2021/10/solved-console-garbled-code-for-win10-win11.html

# by Jeffrey

to Bruce, 感謝分享,實用!

# by 123

請問要怎麼改回 BIG5(950)?

# by Jeffrey

to 123, [System.Text.Encoding]::UTF8 換成 [System.Text.Encoding]::GetEncoding(950)

# by 123

重開之後還是變回UTF-8 有解嗎?

# by Jeffrey

to 123, 變回 UTF-8 發生在什麼程式上?去找出修改它預設值的方法,有些是依據作業系統設定決定的。

Post a comment