【PowerShell】文字化けを直す方法|UTF-8・BOM・Out-File/Get-Content・$OutputEncoding・コンソール出力

【PowerShell】文字化けを直す方法|UTF-8・BOM・Out-File/Get-Content・$OutputEncoding・コンソール出力 PowerShell

PowerShellで日本語を扱うと、ファイルに書き出した文字が「�」や「繧�」のように崩れたり、別のツールで開くと先頭に見えない文字が入っていたり、CSVがすべて「?」になっていたりします。これらはまとめて「文字化け」と呼ばれますが、原因は1つではありません。

文字化けは、どこでどのエンコード(文字コード)が使われているかがかみ合わないときに起こります。PowerShellの場合、原因は大きく「ファイルの読み書き」「コンソール表示と外部コマンド」「BOMの有無」の3つに分かれます。さらにやっかいなことに、Windows PowerShell 5.1とPowerShell 7以降で既定のエンコードが違います

この記事では、実機で挙動を確認しながら、原因別に直し方を整理します。場当たり的に-Encodingを付けるのではなく、なぜ化けるのかを理解して、確実に直せるようにします。

先に結論

  • 文字化けは「書き出し側」と「読み込み側」のエンコード不一致で起こります。両方をUTF-8にそろえるのが基本です。
  • Windows PowerShell 5.1の既定はUTF-8ではありませんOut-FileはUTF-16LE、Set-ContentはShift_JIS、Export-CsvはASCIIです。
  • 5.1の-Encoding UTF8BOM付きUTF-8です。PHPなど他ツールが先頭のBOMで誤動作します。
  • 5.1でBOM無しUTF-8を書くには、.NETのWriteAllTextを使います。
  • 画面表示や外部コマンドの文字化けはchcp 65001[Console]::OutputEncoding$OutputEncodingで対処します。
  • PowerShell 7以降は既定がUTF-8(BOM無し)に統一され、多くの問題が起きにくくなります。

CSVの読み書き全般はCSVを読み書きする方法、スクリプトが実行できないときの対処はps1が実行できない原因と対処もあわせて参照してください。

スポンサーリンク

まず確認:バージョンと既定エンコード

対処の前に、自分のPowerShellのバージョンと、いま使われているエンコードを確認します。バージョンによって既定が違うため、ここを押さえないと対処を間違えます。

check-encoding.ps1
# バージョン(5.1 か 7以降か)
$PSVersionTable.PSVersion

# コンソール出力のエンコード(画面表示・外部コマンド出力の解釈に使う)
[Console]::OutputEncoding

# 外部コマンドへパイプするときのエンコード
$OutputEncoding

PSVersion5.1.xxxxxならWindows PowerShell、7.x.xならPowerShell 7以降です。本記事の対処は、特に断りがなければ5.1を前提に説明し、7以降での違いを補足します。

ファイルの既定エンコードはバージョンで違う

最初に、コマンドごとの既定エンコードを把握します。これは実機で書き出したファイルの先頭バイトを確認した結果です。「思っていたエンコードと違う」ことが、文字化けの最大の原因です。

操作 Windows PowerShell 5.1 の既定 PowerShell 7以降の既定
Out-File / リダイレクト > UTF-16LE(BOM付き) UTF-8(BOM無し)
Set-Content ANSI(日本語環境はShift_JIS) UTF-8(BOM無し)
Get-Content(読み込み) ANSI(Shift_JIS)として解釈 UTF-8として解釈
Export-Csv ASCII(日本語は「?」になり消える) UTF-8(BOM無し)
-Encoding UTF8 の意味 UTF-8(BOM付き UTF-8(BOM無し

5.1ではOut-FileSet-Contentで既定が違う、-Encoding UTF8がBOMを付ける、Export-Csvに至っては日本語が消える、と落とし穴だらけです。1つずつ対処していきます。

ファイル出力が文字化けする(Out-File / Set-Content)

書き出したファイルを他のツールやエディタ(UTF-8前提のもの)で開くと化ける、というケースです。5.1の既定がUTF-8ではないために起こります。対処は、-Encodingで明示的にUTF-8を指定することです。

out-file-encoding.ps1
# 5.1の既定は UTF-16LE / Shift_JIS なので明示する
"こんにちは" | Out-File "C:\work\out.txt" -Encoding UTF8
Set-Content "C:\work\out.txt" "こんにちは" -Encoding UTF8

# ただし 5.1 の -Encoding UTF8 は BOM 付きになる点に注意
# 追記するときも毎回エンコードを合わせる
Add-Content "C:\work\out.txt" "追記行" -Encoding UTF8

これで文字自体は正しく書けますが、5.1では先頭にBOMが付くという別の問題が残ります。BOMが許される相手(多くのテキストエディタやExcel)なら問題ありませんが、許されない相手では次のように壊れます。

UTF-8のBOM問題(先頭に見えない文字が入る)

BOM(Byte Order Mark)は、ファイル先頭に付くEF BB BFという3バイトの目印です。「このファイルはUTF-8です」という宣言の役割ですが、BOMを想定していないツールでは、この3バイトが余計なデータとして扱われ、不具合を起こします。

BOMが引き起こす代表的なトラブル

  • PHPファイルの先頭にBOMが入り、<?phpより前に出力が発生して「headers already sent」になる。
  • Webページの先頭にのような見えない文字が表示され、レイアウトが崩れる。
  • 設定ファイル(JSON・YAMLなど)の読み込みが、先頭のBOMで失敗する。
  • 他のプログラムが1行目の値を読み違える(先頭カラムにBOMが混入する)。

そこで、5.1でBOM無しのUTF-8を書き出すには、.NETのメソッドを直接使います。UTF8Encodingの引数に$falseを渡すと、BOMを付けずに書き出せます。

write-utf8-nobom.ps1
# BOM無し UTF-8 で書き出す(5.1向け)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false

# 文字列をそのまま書き出す
[System.IO.File]::WriteAllText("C:\work\nobom.txt", "こんにちは", $utf8NoBom)

# 配列(複数行)を書き出す
$lines = @("1行目", "2行目", "3行目")
[System.IO.File]::WriteAllLines("C:\work\nobom.txt", $lines, $utf8NoBom)
PowerShell 7以降なら標準で解決

PowerShell 7以降では、-Encoding utf8BOM無しを意味します。BOMを付けたいときだけ-Encoding utf8BOMを使います。.NETのメソッドに頼らなくても、Set-Content -Encoding utf8でBOM無しUTF-8が書けます。BOM問題に頻繁に悩まされるなら、7系への移行が根本的な解決になります。

ファイル読み込みが文字化けする(Get-Content)

今度は逆に、UTF-8で保存されたファイルをGet-Contentで読むと中身が化けるケースです。5.1のGet-Contentは、BOMの無いファイルを既定でShift_JIS(ANSI)として解釈するため、UTF-8ファイルを読むと崩れます。実機でも、BOM無しUTF-8ファイルを既定で読むと繝・せ繝のように化けました。

get-content-encoding.ps1
# NG: 5.1 の既定は ANSI なので UTF-8(BOM無し)ファイルが化ける
$ng = Get-Content "C:\work\utf8.txt"

# OK: 読み込み側でも UTF-8 を明示する
$ok = Get-Content "C:\work\utf8.txt" -Encoding UTF8

ポイントは、書き出すときと読み込むときの両方でエンコードをそろえることです。片方だけUTF-8にしても、もう片方が既定のままなら化けます。BOM付きUTF-8ファイルは先頭のBOMでUTF-8と判別できるため既定でも読めることがありますが、確実を期すなら読み込み側でも-Encoding UTF8を指定してください。

コンソール表示・外部コマンド出力が文字化けする

ファイルではなく、画面に表示される文字や、ipconfignetpythonなどの外部コマンドの出力が化けるケースです。これはファイルのエンコードとは別の、コンソールのエンコード設定が原因です。

console-encoding.ps1
# コードページを UTF-8(65001) に切り替える
chcp 65001

# コンソール出力・外部コマンド出力の解釈を UTF-8 にする
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# PowerShell から外部コマンドへパイプする際のエンコード
$OutputEncoding = [System.Text.Encoding]::UTF8

# 例: UTF-8 で出力する外部コマンドの結果を正しく受け取る
$result = python script.py
$result

役割を整理すると、[Console]::OutputEncoding外部コマンドの出力をどのエンコードとして受け取るか$OutputEncoding外部コマンドへ渡すときにどのエンコードで送るかを決めます。日本語Windowsの既定はShift_JIS系のことが多く、UTF-8で出力する外部コマンド(多くのモダンなCLI)と食い違って化けます。両方をUTF-8にそろえると安定します。

これらの設定はPowerShellのセッションごとにリセットされます。毎回有効にしたい場合は、後述のようにプロファイルに書いておきます。

既定エンコードをまとめて変える

コマンドごとに毎回-Encodingを付けるのは大変です。$PSDefaultParameterValuesを使うと、-Encodingを持つすべてのコマンドの既定をまとめて変更できます。

default-parameter-values.ps1
# -Encoding を持つすべてのコマンドの既定を utf8 にする
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

# コンソール側もまとめて UTF-8 に
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8

この設定を毎回のセッションで自動的に効かせたいときは、プロファイル($PROFILEが示すファイル)に書いておきます。notepad $PROFILEで開いて、上記を追記し保存すれば、次回起動から有効になります。

5.1では「utf8」がBOM付きになる

$PSDefaultParameterValues['*:Encoding'] = 'utf8'は便利ですが、Windows PowerShell 5.1ではutf8がBOM付きを意味するため、BOM無しが必要な用途には使えません。BOM無しが必須の場面では、引き続き.NETのWriteAllTextを使ってください。この一括指定がBOM無しで素直に効くのは7以降です。

CSVの文字化け(Export-Csv / Excelで開く)

最も被害が大きいのがCSVです。5.1のExport-Csvは既定がASCIIのため、日本語がすべて?に置き換わり、元の文字が復元できない形で失われます。実機でも、日本語のセルがすべて?になりました。

export-csv-encoding.ps1
# NG: 5.1 の既定は ASCII。日本語が「?」になって消える
$data | Export-Csv "C:\work\out.csv" -NoTypeInformation

# OK(Excelで開く想定): BOM付きUTF-8 なら Excel が文字コードを正しく判別する
$data | Export-Csv "C:\work\out.csv" -NoTypeInformation -Encoding UTF8

# OK(Shift_JIS が必要な相手向け)
$data | Export-Csv "C:\work\out.csv" -NoTypeInformation -Encoding Default

Excelで開く前提なら、5.1では-Encoding UTF8(BOM付き)が扱いやすい選択です。ExcelはBOMを見てUTF-8と判別するため、ダブルクリックで開いても化けません。逆に、BOM無しUTF-8のCSVをExcelで直接開くと、ExcelがShift_JISと誤解して化けることがあります。PowerShell 7以降の既定はBOM無しUTF-8なので、Excel用途では-Encoding utf8BOMを明示するのが安全です。CSVの読み込みや加工はCSVファイルを読み込んで一括処理する方法も参考になります。

よくある失敗

書き出し側だけUTF-8にして読み込みで化ける

エンコードは書き出しと読み込みの両方をそろえて初めて一致します。Out-File -Encoding UTF8で書いたのにGet-Contentを既定で読めば、5.1では化けます。両方に-Encoding UTF8を付けてください。

5.1の-Encoding UTF8をBOM無しだと思い込む

5.1では-Encoding UTF8はBOM付きです。PHPや一部のCLIツール向けにBOM無しが必要なら、.NETのWriteAllTextでBOM無しを書き出します。

Export-CsvをそのままASCIIで出力して日本語が消える

5.1のExport-Csvは既定ASCIIで、日本語が?になり復元できません。必ず-Encodingを指定してください。これは化けではなくデータ消失なので、特に注意が必要です。

ファイルのエンコードを直したのに画面や外部コマンドが化ける

ファイルとコンソールは別系統です。画面表示や外部コマンドの出力が化けるなら、chcp 65001[Console]::OutputEncoding$OutputEncodingを確認します。

設定がセッションごとに消えるのに気づかない

chcpやエンコード変数の設定は、そのセッション限りです。毎回効かせたいならプロファイル($PROFILE)に書いておきます。

よくある質問

Q結局どうすれば文字化けを防げますか?
A書き出し・読み込み・コンソールのすべてをUTF-8にそろえるのが基本です。Windows PowerShell 5.1では各コマンドに-Encoding UTF8を付け、BOM無しが必要なら.NETのWriteAllTextを使います。可能ならPowerShell 7以降に移行すると、既定がUTF-8(BOM無し)になり大半の問題が消えます。
QBOMは付けるべきですか、付けないべきですか?
A用途によります。Excelで開くCSVや一部のエディタはBOM付きUTF-8を好みます。一方、PHP・Web出力・JSONや多くのCLIツールはBOM無しでないと誤動作します。相手がBOMを許すかどうかで決めてください。迷ったら、まず相手の仕様を確認します。
QWindows PowerShell 5.1と7以降のどちらを使うべきですか?
A文字化けに悩まされているなら7以降をおすすめします。既定がUTF-8(BOM無し)に統一され、-Encoding utf8utf8BOMでBOMの有無も明確に選べます。既存の5.1運用がある場合は、本記事の対処で5.1のまま乗り切ることも可能です。
Q化けてしまったファイルは元に戻せますか?
A化け方によります。エンコードの解釈違い(例:UTF-8をShift_JISとして開いた)なら、正しいエンコードで開き直せば復元できることが多いです。一方、Export-CsvのASCIIで?になった文字は情報が失われており、元には戻せません。出力時のエンコード指定で予防するしかありません。
Qコンソールの設定を毎回やるのが面倒です。
Aプロファイル(notepad $PROFILEで開くファイル)に[Console]::OutputEncoding$PSDefaultParameterValuesの設定を書いておけば、起動のたびに自動で適用されます。チームで配る場合は、このプロファイルを共有すると設定がそろいます。

まとめ

  • 文字化けは書き出しと読み込みのエンコード不一致で起こります。両方をUTF-8にそろえます。
  • Windows PowerShell 5.1の既定はUTF-8ではありません。Out-FileはUTF-16LE、Set-ContentはShift_JIS、Export-CsvはASCIIです。
  • 5.1の-Encoding UTF8はBOM付きです。BOM無しが必要なら.NETのWriteAllTextを使います。
  • 画面や外部コマンドの化けはchcp 65001[Console]::OutputEncoding$OutputEncodingで直します。
  • Export-CsvのASCIIは日本語を消すため、必ず-Encodingを指定します。
  • 根本的に避けたいなら、既定がUTF-8(BOM無し)のPowerShell 7以降へ移行します。

PowerShellの文字化けは、原因が「ファイル・コンソール・BOM」の3系統に分かれ、さらにバージョンで既定が違うため複雑に見えます。しかし、それぞれの既定を把握し、書き出しと読み込みでエンコードをそろえる、という原則さえ押さえれば確実に防げます。