3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShell 7で外部コマンドのUTF-8出力が文字化けする場合の対処法

Posted at

概要

外部コマンドがUTF-8で日本語(などの非ASCII文字)を出力する場合、それをPowerShell変数として受けると文字化けすることがある。その際は、一時的に[Console]::OutputEncodingを変更する。以下のようになる。

[Console]::OutputEncoding=[Text.Encoding]::UTF8
$result = 外部コマンド
[Console]::OutputEncoding=[Console]::InputEncoding

1liner化するならこんな感じ?

$result = Invoke-Command { [Console]::OutputEncoding=[Text.Encoding]::UTF8; 外部コマンド; [Console]::OutputEncoding=[Console]::InputEncoding }

そのまま後続処理にパイプ渡しもできる。例えば出力がJSON形式なら、次のようにパースまでつなげられる。

$result = Invoke-Command { [Console]::OutputEncoding=[Text.Encoding]::UTF8; 外部コマンド; [Console]::OutputEncoding=[Console]::InputEncoding } | ConvertFrom-JSON

ちなみに筆者は外部コマンドとして、具体的には1password CLIop item listのJSON形式出力をConvertFrom-JSONにつなげたかった。でも文字化けが差し障ったのでこれらを調査して、最終的にこんな感じにした。

$result = Invoke-Command { [Console]::OutputEncoding=[Text.Encoding]::UTF8; op item list --format=json; [Console]::OutputEncoding=[Console]::InputEncoding } | ConvertFrom-JSON

詳細

文字化け対策の基本的な考え方は以下より。本記事タイトルも以下をちょっともじっただけ。

PowerShellで、Unicode出力を正しく受け取るためには、コンソールの出力エンコードをUnicodeにする。これで、PowerShellは外部コマンドの出力がUnicodeエンコードであることを理解し、変換しなくなる。そのためには、一時的にコンソールの出力エンコードをUnicodeにして、コマンドの実行後に元に戻す
ASCII.jp:PowerShellで外部コマンドの出力が文字化けする場合の対処法 (1/2)

示されているコードは以下で、上述のものより丁寧。

$TempMyOutputEncode=[System.Console]::OutputEncoding
[System.Console]::OutputEncoding=[System.Text.Encoding]::Unicode
$x=wsl.exe -l
[System.Console]::OutputEncoding=$TempMyOutputEncode

ここから変更と二つの手抜きをしているのだけど、変更点はUnicodeではなくUTF-8を受け取るため、文字コード指定を変えている。以下「Encoding クラス (System.Text) | Microsoft Learn」からの抜粋にあるように、UnicodeはUTF-16を指す。

プロパティ 概要
Unicode リトル エンディアン バイト順を使用する UTF-16 形式のエンコーディングを取得します。
UTF8 UTF-8 形式のエンコーディングを取得します。

手抜きとして第一に [System.Console][System.Text.Encoding] の部分は、 System. を省略できる。

型がシステム名前空間のルートにない場合は、オブジェクト型の完全な名前を指定します。 "System" は省略できます。
型演算子について - PowerShell | Microsoft Learn

次に、[System.Console]::OutputEncodingは意図的に変えていなければ、[System.Console]::InputEncodingのはず。この着想は以下からの類推。$Output[System.Console]::OutputEncodingは別物なので、この説明があるから正しいというものではないけど、とりあえずうまくいっている。

ほとんどのシナリオでは、 $OutputEncoding の値は [Console]::InputEncodingの値に合わせる必要があります。
基本設定変数について - PowerShell | Microsoft Learn

2番目の手抜きは、意図的に変更している可能性もあるので、しない方が確実ではある。

参考

記事内では言及しなかったが、以下のページも理解のための参考にした。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?