PowerShell

ジョブのアウトプットをリアルタイム(?)に取得する

Start-Job とか Invoke-Command -AsJob で実行したジョブは Completed になってから Receive-Job で結果を
受け取ることができるけど、処理途中で内容をつまみ食いする方法について。

利用するケース

CLIで処理に時間のかかるリモートジョブを実行中に結果を確認したい時とか?
→まさにこれがやりたくていろいろ試してみた。

スクリプトをタスク実行などではあまり意味なさそう。
ジョブでログを監視して該当ログ来たら止めるとかやる人いるのかな。。

対応方法

普通に Receive-Job で受け取ると一番最後にまとめて取得される。

Reveice-Jobで受け取る
$job = Start-Job {
  (1..10) | % { sleep 1; (date).ToString() }
}

while ($job.State -ne "Completed") {
    Wait-Job $job -Timeout 1 > $null
}

"after wait"
Receive-Job $job
出力結果
after wait
2017/10/20 20:23:27
2017/10/20 20:23:28
2017/10/20 20:23:29
2017/10/20 20:23:30
2017/10/20 20:23:31
2017/10/20 20:23:32
2017/10/20 20:23:33
2017/10/20 20:23:34
2017/10/20 20:23:35
2017/10/20 20:23:36

途中で中身を見る場合は $job.ChildJobs[0].Output を参照する。

途中で中身を見る
$job = Start-Job {
  (1..10) | % { sleep 1; (date).ToString(); }
}

sleep 1

# Outputのデータ型の確認
$job.ChildJobs[0].Output.GetType()

while ($job.State -ne "Completed") {
    ""
    $job.ChildJobs[0].Output
    sleep 1
}
出力結果
IsPublic IsSerial Name                                     BaseType                           
-------- -------- ----                                     --------                           
True     True     PSDataCollection`1                       System.Object                      


2017/10/20 20:24:00

2017/10/20 20:24:00
2017/10/20 20:24:01

2017/10/20 20:24:00
2017/10/20 20:24:01
2017/10/20 20:24:02

2017/10/20 20:24:00
2017/10/20 20:24:01
2017/10/20 20:24:02
2017/10/20 20:24:03
        :

$job.ChildJobs[0].OutputPSObject のコレクションでインデックスアクセスも可能なので、
中身を順次呼び出し元で垂れ流すことで、ジョブ完了前に出力経過を確認することもできる。


なんで $job 直下じゃなくて $job.ChildJobs[0] なのかとかはよくわかってないので、
この辺りは偉い人のツッコミ待ちです(●´ω`●)