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;