[Powershell] UTF-8 でエンコードされた標準出力を受け取る

Pocket

2バイト目に ASCII コードがくることを想定していないコンソールアプリなど、標準出力を UTF-8 として使用するコンソールアプリは少なくない。
しかし、PowerShell は標準では UTF-8 の標準出力をそのまま読み取ることができない。

そういった場合でも、.NET Framework を駆使すれば、ちゃんと文字列として取得できる。

たとえば、以下のようなバッチファイルを、 utf8out.bat などとして用意しておく。
(ちゃんと標準ストリームを使用していることを明確にするため、あえてバッチで書いた)

@echo off
powershell -Nologo -Command "$binutf8 = [Text.Encoding]::UTF8.GetBytes('((いろはに))'); [Console]::OpenStandardOutput().Write($binutf8, 0, $binutf8.Count);"

これをそのまま実行すると、

((縺・m縺ッ縺ォ))

などと文字化けしてしまうことだろう。

これを、 System.Diagnostics.Process クラスを使って、標準出力をリダイレクトさせ、それを UTF-8 エンコードで取り込ませる。

$psi = New-Object Diagnostics.ProcessStartInfo
$psi.FileName = "utf8out.bat"
$psi.UseShellExecute = $false	# プロセス起動時にシェルを使わず、標準出力をリダイレクト可能にする
$psi.StandardOutputEncoding = [Text.Encoding]::UTF8	# 文字コードを指定
$psi.RedirectStandardOutput = $true
$p = [Diagnostics.Process]::Start($psi)
$s = $p.StandardOutput.ReadToEnd()
$s
$p.WaitForExit()

そうすれば、出力は以下のように文字化けせずに表示されるはずだ。

((いろはに))

これで、UTF-8 を使うアプリとの連携もばっちりだ。

ちなみに、 FileName プロパティで指定するファイルの相対パスは、 PowerShell の カレントディレクトリではなく、 .NET のカレントディレクトリ ([System.IO.Directory]::GetCurrentDirectory() / [System.IO.Directory]::SetCurrentDirectory(...) で取得/設定できる物) である点に注意。

PowerShell v3 以上であれば、以下のように もうちょっときれいに書くこともできる。

#Requires -Version 3
$p = [System.Diagnostics.Process]::Start(
    [System.Diagnostics.ProcessStartInfo]@{
        FileName = 'utf8out.bat';
        UseShellExecute = $false;
        StandardOutputEncoding = [Text.Encoding]::UTF8;
        RedirectStandardOutput = $true;
    }
);
$p.WaitForExit();
$s = $p.StandardOutput.ReadToEnd();
$p.Dispose();
$s;

コメントを残す

メールアドレスが公開されることはありません。