根本原因:每個指令的預設編碼都不同
在 Windows PowerShell 5.1 中,Get-Content 把沒有 BOM 的檔案當成 ANSI 讀取,在繁體中文 Windows 上就是 Big5(字碼頁 950);Out-File 和 > 寫出 UTF-16;Set-Content 寫出 Big5;Export-Csv 預設用 ASCII,中文全部變成 ?。PowerShell 7 統一改成不含 BOM 的 UTF-8。
用 Big5 讀取 UTF-8 檔案時,你好 會變成 雿末,而且常夾雜 �:UTF-8 的許多位元組組合在 Big5 中不存在,會被直接取代。這種結果如果又被存檔,被取代的字就救不回來了;原始檔案本身沒有問題,用 -Encoding UTF8 重新讀取即可。
反過來也一樣:在英文版 Windows Server 上,ANSI 是西歐語系的 Windows-1252,Big5 檔案讀進來就成了 ³¯¤j¤å 這類符號。這種亂碼的位元組都還在,可以完整修復。
亂碼
©m¦W,³¡ªù,«°¥« ³¯¤j¤å,·~°È,¥x¥_ ªL¤p¬ü,±ÄÁÊ,°ª¶¯
修復後
姓名,部門,城市 陳大文,業務,台北 林小美,採購,高雄
正確讀寫檔案
Get-Content data.csv -Encoding UTF8:沒有 BOM 的 UTF-8 檔案也能正確讀取。Set-Content、Out-File、Add-Content加上-Encoding UTF8寫出 UTF-8,在 5.1 中一定含 BOM。Export-Csv data.csv -Encoding UTF8 -NoTypeInformation:避免預設的 ASCII 把中文換成?。- 要寫檔案給只接受 Big5 的舊系統時,在 5.1 中用
-Encoding Default,也就是系統的 ANSI 編碼。 - 一次設定所有指令:在指令碼開頭寫
$PSDefaultParameterValues['*:Encoding'] = 'utf8'。
指令碼裡的中文變成亂碼或出錯
.ps1 指令碼存成不含 BOM 的 UTF-8 時,Windows PowerShell 5.1 會用 Big5 讀取它。Write-Host "你好" 會輸出 雿末,有時 Big5 還會把引號「吃」進一個亂碼字裡,造成字串缺少結束字元之類的語法錯誤。把指令碼存成含 BOM 的 UTF-8 就能解決:VS Code 中按狀態列右下角的編碼,Notepad++ 中在 編碼 選單裡選擇 UTF-8-BOM。
Invoke-WebRequest 和 Invoke-RestMethod
如果伺服器的 Content-Type 沒有寫明字元集,Windows PowerShell 5.1 會用 ISO-8859-1 解碼回應,UTF-8 的中文就變成 ä½ å¥½。解決方法是取出原始位元組自行解碼,例如 [Text.Encoding]::UTF8.GetString((Invoke-WebRequest $url).RawContentStream.ToArray())。
主控台顯示亂碼
如果只是主控台視窗顯示亂碼,檔案本身通常沒有問題。用 [Console]::OutputEncoding = [Text.Encoding]::UTF8 切換輸出編碼;輸出要透過管線傳給外部程式時,再設定 $OutputEncoding = [Text.Encoding]::UTF8。命令提示字元常用的 chcp 65001 作用類似。
Windows 的地區設定中還有一個「使用 Unicode UTF-8 提供全球語言支援」的 Beta 選項,會把系統的 ANSI 編碼改成 UTF-8。它能減少這類亂碼,但一些只認 Big5 的舊軟體反而可能出現亂碼,開啟前請先測試。
檔案已經寫壞了?把它拖到上方的框中,Mojibuster 會修復亂碼,並把 Big5 檔案轉換成 UTF-8(請見 Big5 轉 UTF-8)。如果檔案裡已經是 ? 或 �,文字就遺失了,只能從原始檔案重新匯出。
常見問題
怎麼查看 PowerShell 的版本?
執行 $PSVersionTable.PSVersion。5.1 是 Windows 內建的 Windows PowerShell;從 7 開始叫做 PowerShell,預設使用 UTF-8。
PowerShell 匯出的 CSV 用 Excel 開啟為什麼是亂碼?
PowerShell 7 寫出的是不含 BOM 的 UTF-8,繁體中文版 Excel 會用 Big5 開啟。請使用 -Encoding utf8BOM,或在 Mojibuster 中儲存時加入 BOM。詳見 Excel 開啟 CSV 亂碼。
一定要執行 chcp 65001 嗎?
只有跟著主控台字碼頁走的外部程式才需要。在 PowerShell 內部,設定 [Console]::OutputEncoding 就夠了。