注意:经过一些实验,我发现使用 write-output 或直接输出变量也不是一个好的解决方案。如果您有一个函数使用这些方法中的任何一个并且还返回一个值,则输出将与返回值连接!
我发现记录作业输出的最佳方法是将 write-host 与 Start-Transcript 和 Stop-Transcript cmdlet 结合使用。有一些缺点,例如 ISE 不支持 Transcript cmdlet。此外,我还没有找到一种在不发送到主机的情况下输出到脚本的方法(我想要一个具有较少冗长用户体验的健壮日志),但它似乎是目前可用的最佳解决方案。这是我能够在不散布输出的情况下记录并发作业的唯一方法,而不必为每个作业纠正多个临时日志文件然后将它们组合起来。
以下是我之前出于文档原因留下的答案:
这里的问题是没有从 Receive-Job 获得输出。我期望看到的作业的输出正在由 write-host 写入作业。当调用接收作业时,我在屏幕上看到了我的所有输出,但在其他地方没有可用管道。似乎当我调用接收作业时,所有这些写入主机 cmdlet 都会执行,但我没有什么可以获取并通过管道传输到输出文件。以下脚本演示了这一点。您会注意到“Sleepy Time”同时出现在日志文件和主机中,而“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