根本原因:コマンドごとに文字コードが違う
日本語版 Windows の Windows PowerShell 5.1 では、Get-Content は BOM のないファイルを ANSI、つまり Shift_JIS(CP932)として読みます。Set-Content も Shift_JIS で書き、Out-File とリダイレクト > は UTF-16、Export-Csv は ASCII で書き出します。ASCII では日本語はすべて ? になります。PowerShell 7 ではこれが統一され、どのコマンドも BOM なしの UTF-8 を使います。
文字化け
繝ヲ繝シ繧カ繝シ,驛ィ鄂イ,蜍、蜍吝慍 螻ア逕ー,蝟カ讌ュ驛ィ,譚ア莠ャ 菴占陸,邨檎炊驛ィ,螟ァ髦ェ
修正後
ユーザー,部署,勤務地 山田,営業部,東京 佐藤,経理部,大阪
ファイルを正しく読み書きする
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 の既定値を避けられます。- PowerShell 7 で Shift_JIS のファイルを読み書きするときは
-Encoding 932を指定します(PowerShell 6.2 以降)。 - すべてのコマンドに一度に設定するなら、スクリプトの先頭に
$PSDefaultParameterValues['*:Encoding'] = 'utf8'と書きます。
スクリプトファイルの日本語
.ps1 を BOM なしの UTF-8 で保存すると、Windows PowerShell 5.1 はそれを Shift_JIS として読みます。Write-Host "こんにちは" の日本語が化けるだけでなく、文字列の区切りが崩れて「文字列に終端記号がありません」というエラーで止まることもあります。.ps1 は BOM 付きの UTF-8 で保存してください。VS Code ではステータスバーの文字コードから、Notepad++ ではエンコードのメニューで UTF-8-BOM を選びます。
Invoke-RestMethod と Invoke-WebRequest
サーバーが Content-Type で文字コードを示さないと、Windows PowerShell 5.1 は応答を ISO-8859-1 として読みます。UTF-8 の日本語は ã“ã‚“ã«ã¡ã¯ のように化けます。応答をバイトのまま受け取り、自分でデコードすれば解決します。たとえば [Text.Encoding]::UTF8.GetString((Invoke-WebRequest $url).RawContentStream.ToArray()) です。
コンソールの表示
日本語版 Windows のコンソールは、コードページ 932(Shift_JIS)で動いています。ファイルは正しいのに、画面に出る外部コマンドの UTF-8 出力だけが化けることもあります。その場合は [Console]::OutputEncoding = [Text.Encoding]::UTF8 で出力を切り替えます。外部プログラムにパイプで渡す文字列には $OutputEncoding = [Text.Encoding]::UTF8 も設定します。
すでに化けて保存されたファイルは、上の枠にドロップしてください。Mojibuster が化けた箇所を直し、Shift_JIS のファイルは UTF-8 に変換します。ただし ? に置き換わった文字は情報が失われているため戻せません。
よくある質問
自分の PowerShell のバージョンを確認するには?
$PSVersionTable.PSVersion で表示されます。5.1 は Windows に標準で入っている Windows PowerShell です。7 以降は単に PowerShell と呼ばれ、標準で UTF-8 を使います。
PowerShell で作った CSV が Excel で文字化けするのはなぜですか?
PowerShell 7 は BOM なしの UTF-8 で書き出しますが、Excel はそれを Shift_JIS として開きます。-Encoding utf8BOM を指定するか、Mojibuster で BOM 付きで保存し直してください。詳しくは Excel の CSV 文字化け をご覧ください。
chcp 65001 は必要ですか?
コンソールのコードページに従う外部プログラムを使う場合だけです。PowerShell の中だけなら [Console]::OutputEncoding の設定で十分です。