PowerShellから別のプログラムへ渡した日本語や、CSVに保存した値が「???」になる場合は、送信と保存を分けて調べます。外部プログラムへの送信は$OutputEncoding、CSV保存はExport-Csvの-Encodingが確認対象です。
この記事では、Windows PowerShell 5.1の実測から、元データの再出力が必要な場合と、開くアプリの読込み方法を見直す場合を説明します。例を試すには、Windows PowerShell 5.1、Node.js、新しいフォルダーを作れる作業場所が必要です。
先に結論
- 外部プログラムへの送信は$OutputEncoding、CSV保存はExport-Csvの-Encodingで文字コードを指定します。
- データ自体が疑問符になっていたら、設定を直し、日本語が残る元データから出力し直します。
- 正しい日本語のバイトが残っていれば、開くアプリの文字コード指定や取込み方法を確認します。
まず、疑問符への置換と読込みの問題を分ける
文字が失われた場合は元データから再出力し、日本語が残っている場合は読込み側を確認します。
文字コードは、文字を数値のデータで表す決まりです。UTF-8もその一つです。読む側が別の決まりで解釈する場合と、送信・保存の時点で日本語が疑問符に置き換わる場合では、必要な対処が異なります。
パイプは、左の処理結果を右へ渡す縦棒の記号です。今回はPowerShellから外部プログラムへ文字を送ります。CSVは、表の列をカンマで区切って保存するファイル形式です。
検証には、JavaScriptを実行するソフトであるNode.jsを使いました。実行環境はWindows PowerShell 5.1.26100.9818、Node.js v24.11.0です。実行日は2026年11月14日です。
- バイト:データの大きさの単位です。文字を表すバイトを調べると、画面表示に頼らず日本語が届いたか確認できます。
- 16進数:数値を0〜9とA〜Fで表す書き方です。掲載結果では2桁が1バイトです。英字の大文字と小文字は同じ数値を表します。
- ASCII:今回の既定設定で使われた文字コードです。日本語を表せません。
- BOM:ファイルの先頭に付く識別情報です。読む側が文字コードを判断する手掛かりになります。
PowerShell 7の動作とExcelの画面表示は、今回実測していません。Node.jsを利用できない場合も掲載結果は読めますが、利用中の環境で再現を確認したことにはなりません。
Windows PowerShellを開き、作業場所を準備する
版を確認してから、新しい検証用フォルダーを作ります。各行を順に実行し、失敗したら止めます。
Windowsのスタートメニューで「Windows PowerShell」を検索し、通常の権限で開きます。管理者としての起動は不要です。Node.jsは事前に利用できる必要があります。この記事では導入操作を扱いません。
例は、現在の場所にencoding-demoという新しいフォルダーを作ります。入力待ちの行に表示された場所を確認してください。ファイルを作成してよい場所か判断できない場合は、ここで止めます。
- Windows PowerShellを開き、現在の場所が作業に適しているか確認します。
- 最初の2行を実行します。1行目が5.1で始まり、2行目にNode.jsの版が表示されることを確認します。別の版やエラーなら先へ進みません。
- 残りを1行ずつ実行します。同名フォルダーがあるなどの理由で作成に失敗したら止め、既存データを消さずに別の作業場所を選びます。
- 最後にencoding-demoと表示されたら準備完了です。以降の例は同じ画面で実行します。
版を確認し、サンプル専用の新しいフォルダーへ移動する
$PSVersionTable.PSVersion.ToString()
node --version
New-Item -ItemType Directory -Path ".\encoding-demo" -ErrorAction Stop | Out-Null
Set-Location -LiteralPath ".\encoding-demo"
Split-Path -Leaf (Get-Location).Path
実行結果
5.1.26100.9818
v24.11.0
encoding-demo
最初の2行はPowerShellとNode.jsの版を表示します。掲載した細かな版番号は検証環境のもので、利用中の端末とは異なる場合があります。
New-ItemのDirectory指定はフォルダー作成、Out-Nullは詳細表示を省く処理です。-ErrorAction Stopは作成失敗時に処理を止めます。1行ずつ実行する場合、失敗後の行は自分で実行しないでください。
Set-Locationはフォルダーの移動、-LiteralPathは名前をそのまま扱う指定です。最後に移動先の末尾名が表示されます。画面を閉じても、作成したフォルダーとファイルは残ります。
症状に合わせて、送信設定と保存設定を選ぶ
パイプ送信とCSV保存は別の設定です。日本語が崩れる経路に合わせて確認します。
外部プログラムへ渡した直後に日本語が崩れるなら、パイプの送信設定を確認します。保存したCSVの値が崩れるなら、CSVの書出し設定を確認します。送信設定の変更だけでは、CSVの保存設定まで変わりません。
次の表は、同じ「日本語」を送信・保存した実測結果です。今回のWindows PowerShell 5.1環境では、どちらも既定設定で疑問符になり、それぞれにUTF-8を指定すると日本語が保持されました。
| 検証した経路 | 指定 | 得られたデータ | 判定 |
|---|---|---|---|
| PowerShell 5.1 → Node.jsへのパイプ | 既定の$OutputEncoding(ASCII) | 3f 3f 3f 0d 0a | 日本語が???へ置換 |
| PowerShell 5.1 → Node.jsへのパイプ | $OutputEncodingをUTF-8へ変更 | e6 97 a5 e6 9c ac e8 aa 9e 0d 0a | 日本語を保持 |
| Export-Csvによる保存 | エンコード指定なし | 値の部分が3f 3f 3f、BOMなし | 日本語が???へ置換 |
| Export-Csvによる保存 | -Encoding UTF8 | 先頭ef bb bf、値に日本語のUTF-8バイト | 日本語を保持 |
$OutputEncodingは外部プログラムとの通信に使う文字コードの設定です。Export-CsvはCSVを保存する命令で、-Encodingは保存する文字コードを指定します。以下では経路ごとに結果を読み取ります。
パイプ先へ届いたデータを調べる
受信直後のバイトが疑問符なら、表示方法を変えるだけでは日本語に戻せません。
PowerShellの画面に日本語が見えていても、外部プログラムへ同じ文字が届くとは限りません。次の例は「日本語」をNode.jsへ送り、受信データを16進数で表示します。ファイルは作成しません。
準備したWindows PowerShell 5.1の画面で実行します。nodeの-eは、後ろの文字列をJavaScriptとして実行する指定です。標準入力というデータの受信口を読み、hexの指定で16進数の文字列に変換します。
既定のパイプで受信バイトを調べる
"日本語" | node -e "const fs = require('node:fs'); console.log(fs.readFileSync(0).toString('hex'));"
実行結果
3f3f3f0d0a
出力の3fは疑問符「?」、末尾の0d0aは改行です。3fが3つ並ぶため、受信時点で「日本語」が3つの疑問符になっています。このデータを別の文字コードで読み直しても、元の日本語には戻せません。
実測環境の$OutputEncodingはus-ascii、つまりASCIIでした。利用中の環境で設定が変更されていれば結果は異なる場合があります。掲載結果との一致ではなく、実際に届いたデータで判断してください。
パイプ送信だけを一時的にUTF-8へ変える
相手側がUTF-8を受け付ける場合に変更し、確認後は元の設定へ戻します。
受信直後に疑問符になっていたら、送信側の設定を見直します。次の例は現在の$OutputEncodingを保存し、UTF-8へ切り替えてから、先ほどと同じ「日本語」をNode.jsへ送ります。
New-Objectは設定に使う値を作る命令です。UTF8Encodingの$falseは、BOMを付けない指定です。tryの中で送信し、finallyの中で保存した設定へ戻すため、確認後に送信設定の変更を残しません。
外部コマンドへ渡すときだけUTF-8を使う
$savedOutputEncoding = $OutputEncoding
try {
$OutputEncoding = New-Object System.Text.UTF8Encoding($false)
"日本語" | node -e "const fs = require('node:fs'); console.log(fs.readFileSync(0).toString('hex'));"
} finally {
$OutputEncoding = $savedOutputEncoding
}
実行結果
e697a5e69cace8aa9e0d0a
出力の前半9バイトが「日本語」のUTF-8表現で、最後の2バイトが改行です。変更前の3つの疑問符と異なり、日本語を表すデータが届いたことを確認できます。
実際の処理でも、相手側が受け付ける文字コードに合わせます。設定変更で既に失われた文字が復元されるわけではありません。日本語が残っている元データから、改めて送信してください。
CSVはExport-CsvでUTF-8を指定する
Windows PowerShell 5.1のExport-Csvは、文字コードの指定を省くとASCIIで保存します。
今回の検証では、指定を省いて保存したCSVの値が3f3f3fとなり、「日本語」が疑問符へ置き換わりました。CSVでは$OutputEncodingではなく、Export-Csvの-Encodingを指定します。
次の例は、準備したencoding-demoフォルダーで実行します。nameという列に「日本語」を入れた1行のデータをUTF-8で保存し、保存後のバイトを表示します。同名ファイルがあると上書きされるため、先に確認してください。
[pscustomobject]は、名前付きの項目を持つデータを作る記法です。@{ }の中に項目名と値を記し、ここではCSVの1行として扱います。$rowは、そのデータに付けた名前です。
- -LiteralPathは保存先を文字どおりの名前で指定します。先頭のドットと区切り文字は、現在のフォルダーを表します。
- -NoTypeInformationは、データの種類を示す追加行を省く指定です。
- -Encoding UTF8は、Windows PowerShell 5.1ではBOM付きUTF-8で保存する指定です。
Windows PowerShell 5.1でBOM付きUTF-8のCSVを作る
$row = [pscustomobject]@{ name = "日本語" }
$row | Export-Csv -LiteralPath ".\encoding-utf8-demo.csv" -NoTypeInformation -Encoding UTF8
[BitConverter]::ToString([IO.File]::ReadAllBytes((Join-Path (Get-Location) "encoding-utf8-demo.csv")))
実行結果
EF-BB-BF-22-6E-61-6D-65-22-0D-0A-22-E6-97-A5-E6-9C-AC-E8-AA-9E-22-0D-0A
最後の行は、現在の場所とファイル名を組み合わせ、保存したファイルの全バイトを16進数で表示します。先頭のEF-BB-BFはBOM、E6-97-A5-E6-9C-AC-E8-AA-9Eは「日本語」です。
22は引用符、0D-0Aは改行です。列名nameに続く値に日本語のバイトが残っていれば、保存時に保持できています。疑問符になったCSVを保存し直すだけでは戻らないため、日本語が残る元データから作り直します。
確認後、例で作成したCSVが不要なら作業用フォルダーから削除できます。上書きした内容は、この処理では元に戻せません。実データでは元ファイルを残し、別名で出力してください。
日本語が残っていれば、開くアプリを確認する
BOMは文字コードの手掛かりであり、失われた日本語を復元する情報ではありません。
今回の検証では、疑問符へ変わったデータにBOMを付け足しても日本語は戻りませんでした。送信や保存の時点で文字が失われた場合は、その経路の設定を直し、元データから出力し直します。
一方、正しいUTF-8の日本語がファイルに残っていれば、開くアプリの読込み方法が次の確認対象です。Microsoftは、UTF-8のCSVはBOM付きなら通常の方法で開けると案内しています。BOMなしではデータ取込みを使う方法があります。
- データ自体が疑問符の場合:送信・保存の設定を直し、日本語が残る元データから再出力します。
- 正しい日本語のバイトが残っている場合:読込み側の文字コード指定や取込み方法を確認します。
Excelについては公式資料による確認で、画面操作と表示結果は今回実測していません。元ファイルを保持したうえで、利用中のExcelの読込み方法を確認してください。
版の違いと、スクリプト読込み時の文字化けに注意する
5.1での実測結果と、PowerShell 7についての資料確認は分けて扱います。
Microsoftの資料では、PowerShell 6以降のテキスト出力は既定でBOMなしUTF-8です。一方、Windows PowerShell 5.1のUTF8指定はBOM付きです。同じ指定名でも版による違いがあり、5.1の結果をそのまま当てはめられません。
拡張子.ps1は、PowerShellの命令を保存するスクリプトファイルです。5.1はBOMなしのスクリプトを、従来の文字と数値の対応表であるANSIコードページで読みます。日本語を含むUTF-8ファイルは、読む段階で文字が崩れる場合があります。
掲載例を5.1で試す場合は、入力画面へ貼り付けるか、UTF-8 BOM付きのスクリプトファイルへ保存します。PowerShell 7の動作は今回実測していません。
文字コードへの対処として、実行ポリシーを無条件に緩める必要はありません。実行ポリシーはスクリプト実行の制限に関する設定です。端末の既存ルールに従ってください。
元データ、送信・保存、読込みの順に確認する
最初に日本語が失われた箇所を直し、元データから再出力した結果を確かめます。
原因を絞るには、元データを残し、「日本語」のような短い文字列で受け渡しの前後を比べます。入力、パイプ、保存、読込みを一度に変更せず、次の順番で確認してください。
疑問符への置換が見つかったら、その箇所の設定を直して再出力します。日本語が保持されたことを確認してから次へ進むと、送信・保存の問題と、読込みの問題を分けて判断できます。
- 元データに日本語が残っているか確認します。残っていなければ、変更前のデータを探します。
- 利用中のPowerShellの版を確認し、5.1の実測と区別します。
- パイプなら受信直後、CSVなら保存直後のバイトを確認します。
- 疑問符になった箇所の設定を直し、元データから再出力して比較します。
- 日本語のバイトが残っている場合は、読込み側の文字コード指定や取込み方法を確認します。
「UTF-8を指定したか」に加え、送信・保存・読込みのどこへ指定したかを確認すると、症状に合った対処を選べます。
