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;