パイプラインとリダイレクト
PowerShellでは、普通のシェルと同じ方法でリダイレクトやパイプラインを行った場合、ストリームの内容が文字列に変換されて扱われるという特徴があります。
データによってはエンコーディングの変換でデータが欠落し、通常のコマンドプロンプトと異なる動作になります。
欠落例
これらはエンコーディングの変換によってデータが欠落します。
# 欠落例1
.\bin.exe > bin_fail1.bin
# 欠落例2
$bin_fail = .\bin.exe
成功例
次の方法ではエンコーディングの変換なしにデータを取得できます。
# コマンドラインインタプリタで標準出力を処理する
cmd /c "bin.exe > bin_cmd.bin"
# バイナリを読み出す
[byte[]]$bin_gc = Get-Content -Path .\bin_cmd.bin -Encoding Byte
# バイナリを書き出す
Set-Content -Path "out_sc.bin" -Value $bin_gc -Encoding Byte
おまけ
コマンドラインインタプリタを使わずパイプでバイナリを得ます。
invoke.ps1
# コマンド実行時の標準出力をByte Arrayで得る
function Invoke-BinaryPipe {
Param($FileName, $Arguments)
if (-not $FileName) {
Write-Host "Usage Invoke-BinaryPipe <FileName>"
return
}
[System.Diagnostics.ProcessStartInfo]$psi = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$ExecPath = (Convert-Path $FileName)
$psi.WorkingDirectory = (Get-Location).Path
$psi.RedirectStandardOutput = $true
$psi.UseShellExecute = $false
$psi.FileName = $ExecPath
$psi.Arguments = $Arguments
[System.Diagnostics.Process]$proc = [System.Diagnostics.Process]::Start($psi)
if (-not $proc) { return }
$proc.WaitForExit()
[System.IO.MemoryStream]$ms = New-Object System.IO.MemoryStream
$proc.StandardOutput.BaseStream.CopyTo($ms)
$ms.ToArray()
$proc.Dispose()
}
[byte[]]$bin = Invoke-BinaryPipe "./bin.exe"