スキップしてメイン コンテンツに移動

PowerShellでStart-Processで起動したアプリケーションのログをファイルとコンソールの両方に出力

はじめに

PowerShell上でStart-Processコマンドを使って起動したアプリケーションは-RedirectStandardOutputRedirectStandardErrorオプションを指定することで、ログをファイルに出力できます(コンソールには出力できないので注意)。
このログを同時にコンソールにも表示させたかったのですが、思いのほか苦戦したので備忘録として共有します。

できた方法

結局出力されたログファイルを、別起動したプロセスでTailするという方法を採用しました。
下記はsomethig.logに書き込みつつ同時にコンソールにもログの内容を出力するPowerShellの例です。

try {
  $logJobObj = Start-Job -ScriptBlock { Get-Content -Path ".\something.log" -Wait }
  $mainProcessObj = Start-Process -PassThru -FilePath process.exe -ArgumentList "-something_argument... -RedirectStandardOutput ".\something.log" RedirectStandardError ".\something.log"

  // アプリケーションが終了するまで待つ
  While (!$mainProcessObj.HasExited)
  {
    // ログをTailしているJobの出力を受け取る
    Receive-Job $logJobObj
    // 適当な秒数待つ
    Start-Sleep -Seconds 1
  }
  Receive-Job $logJobObj
}
finally {
  if ($logJobObj) {
    Receive-Job $logJobObj
    // ログをTailしているJobを終了
    Stop-Job $logJobObj
    Remove-Job $logJobObj
  }
}

※ ログをTailするプロセスでStart-Jobを使うのは、Start-Processで同様のことを実行しようとするとStart-Process powershell -ArgumentList "-NoExit -Command & { Get-Content... }"みたいに書けばよさそうです。ただ今回は起動したプロセスの出力を取得したかったので、Start-Jobを使いました。

この方法は、WindowsのPowerShell上で stdout に出力されるアプリケーションの出力を、コンソールに出力したい場合にも使えます。
※ Windows では、Windows アプリケーションにはデフォルトでstdout ハンドルがないため、これは出力がデフォルトでコンソールに送信されない (らしい)。

余談

Bashとかであれば。。。

tee コマンドを使って、ファイルとコンソールの両方出力は比較的簡単にできます。例えば下記のようにすれば、something_cmdのstdoutstderrの両方をコンソールとsomething.logに出力することができます。

something_cmd 2>&1 | tee ./something.log
somethong_cmd > >(tee  ./something.log) 2>&1

System.Diagnostics.ProcessStartInfoを使う方法

ファイル出力せずにstdoutstderrをコンソールに出力するだけであれば、下記のように、System.Diagnostics.ProcessStartInfoを使う方法もあるようです。
powershell - Capturing standard out and error with Start-Process - Stack Overflow

PoweShellでのファイル出力方法

こちらに分かりやすくまとめてありました。
PoweShellでのファイル出力方法あれこれ #PowerShell - Qiita

コメント