注:いくつかの実験の結果、書き込み出力を使用したり、変数を直接出力したりすることも適切な解決策ではないことがわかりました。これらのメソッドのいずれかを使用し、値も返す関数がある場合、出力は戻り値と連結されます。
ジョブからの出力をログに記録するための最良の方法は、write-hostをStart-TranscriptおよびStop-Transcriptコマンドレットと組み合わせて使用することです。ISEがトランスクリプトコマンドレットをサポートしていないなど、いくつかの欠点があります。また、ホストに送信せずにトランスクリプトに出力する方法を見つけられませんでした(より冗長なユーザーエクスペリエンスを備えた堅牢なログが必要でした)が、現在利用可能な最善のソリューションのようです。これは、ジョブごとに複数の一時ログファイルを修正してそれらを結合することなく、出力を散在させることなく同時ジョブをログに記録できる唯一の方法です。
以下は、ドキュメント上の理由で残した以前の回答です。
ここでの問題は、Receive-Jobから出力を取得していませんでした。私が期待していたジョブからの出力は、write-hostによってジョブに書き込まれています。receive-jobが呼び出されたとき、画面にすべての出力が表示されましたが、他の場所にパイプするために利用できるものはありませんでした。receive-jobを呼び出すと、これらすべてのwrite-hostコマンドレットが実行されるように見えますが、ピックアップして出力ファイルにパイプするものは何もありません。次のスクリプトはこれを示しています。「SleepyTime」はログファイルとホストの両方に表示されますが、「Slept」はホストにのみ表示されます。したがって、Receive-Jobをwrite-hostにパイプしようとするのではなく、Log関数を変更して、write-hostを使用しないようにするか、以下に示すように出力を分割する必要があります。
cls
rm c:\jobs.log
$foo = @(1,2,3)
$jobs = @()
foreach($num in $foo){
$s = { get-process -name "explorer"
Start-Sleep $args[0]
$x = ("Sleepy Time: "+$args[0])
write-host $x
$x
write-host ("Slept: "+$args[0])
}
$id = [System.Guid]::NewGuid()
$jobs += $id
Start-Job -Name $id -ScriptBlock $s -args $num
}
While (Get-Job -State "Running") {
cls
Get-Job
Start-Sleep 1
}
cls
Get-Job
write-host "Jobs completed, getting output"
foreach($job in $jobs){
Receive-Job -Name $job | out-file c:/jobs.log -append
}
Remove-Job *
notepad c:\jobs.log
以下は、並行ジョブを実行し、mbourgonの要求に従ってそれらを順番にログに記録するサンプルです。タイムスタンプは作業が散在していることを示していますが、ログはジョブごとに順番に表示されます。
#This is an example of logging concurrent jobs sequentially
#It must be run from the powershell prompt as ISE does not support transcripts
cls
$logPath = "c:\jobs.log"
rm $logPath
Start-Transcript -Path $logPath -Append
#Define some stuff
$foo = @(0,1,2)
$bar = @(@(1,"AAA"),@(2,"BBB"),@(3,"CCC"))
$func = {
function DoWork1 {
Log "This is DoWork1"
return 0
}
function DoWork2 {
Log "This is DoWork2"
return 0
}
function Log {
Param([parameter(ValueFromPipeline=$true)]$InputObject)
$nl = [Environment]::NewLine.Chars(0)
$time = Get-Date -Format {HH:mm:ss}
Write-Host ($time+">"+$InputObject+$nl)
}
}
#Start here
foreach($num in $foo){
$s = { $num = $args[0]
$bar = $args[1]
$logPath = $args[2]
Log ("Num: "+$num)
for($i=0; $i -lt 5; $i++){
$out = ([string]::$i+$bar[$num][1])
Log $out
start-sleep 1
}
Start-Sleep $num
$x = DoWork1
Log ("The value of x is: "+$x)
$y = DoWork2
Log ("The value of y is: "+$y)
}
Start-Job -InitializationScript $func -ScriptBlock $s -args $num, $bar, $logPath
}
While (Get-Job -State "Running") {
cls
Get-Job
Start-Sleep 1
}
cls
Get-Job
write-host "Jobs completed, getting output"
Get-Job | Receive-Job
Remove-Job *
Stop-Transcript
notepad $logPath