Powershell:从接收作业获取输出
我有一个正在运行的作业集合。当他们完成时,我使用接收作业,它将输出写入屏幕。我想获取该输出并将其记录到一个文件中。我不想在作业运行时生成输出,因为如果同时运行多个作业,日志记录将被分散。Get Job | Receive Job以良好的组织方式打印输出 我尝试了以下所有操作,但没有将任何输出写入文件或存储在变量中,它只会显示在屏幕上:Powershell:从接收作业获取输出,powershell,jobs,Powershell,Jobs,我有一个正在运行的作业集合。当他们完成时,我使用接收作业,它将输出写入屏幕。我想获取该输出并将其记录到一个文件中。我不想在作业运行时生成输出,因为如果同时运行多个作业,日志记录将被分散。Get Job | Receive Job以良好的组织方式打印输出 我尝试了以下所有操作,但没有将任何输出写入文件或存储在变量中,它只会显示在屏幕上: #Wait for last job to complete While (Get-Job -State "Running") { Log "Ru
#Wait for last job to complete
While (Get-Job -State "Running") {
Log "Running..." -v $info
Start-Sleep 10
}
Log ("Jobs Completed. Output:") -v $info
# Getting the information back from the jobs
foreach($job in Get-Job){
Receive-Job -Job $job | Out-File c:\Test.log -Append
$output = Receive-Job -Job $job
Log ("OUTPUT: "+$output)
Receive-Job -Job $job -OutVariable $foo
Log ("FOO: "+$foo)
}
编辑:
在看到Keith的评论后,我已将foreach中的额外接收工作电话删除为以下内容:
# Getting the information back from the jobs
foreach($job in Get-Job){
Receive-Job -Job $job -OutVariable temp
Write-Host ("Temp: "+$temp)
$temp | Out-File -FilePath c:\Test.log -Append
}
我还验证了我没有在脚本中的任何其他位置使用Receive Job。写入主机$temp和输出文件仍然不会产生任何输出。当您收到作业的结果时,这些结果将被删除,这样对
接收作业的进一步调用将无法检索(假设作业已完成)。如果不希望接收作业
删除结果,请使用-Keep
开关。现在,这并不能解释为什么您对Receive Job
的第一次调用没有向日志文件输出任何内容。。。除非您没有显示的脚本中有一部分在此之前正在执行接收作业。注意:经过一些实验,我发现使用写输出或直接输出变量也不是一个好的解决方案。如果您有一个函数使用这些方法中的任何一种,并且还返回一个值,那么输出将与返回值连接起来
我发现记录作业输出的最佳方法是将write host与Start-Transcript和Stop-Transcript cmdlet结合使用。存在一些缺点,例如ISE不支持转录cmdlet。此外,我还没有找到一种不将其发送到主机就输出到转录本的方法(我想要一个具有较少详细用户体验的健壮日志),但它似乎是目前可用的最佳解决方案。这是我能够记录并发作业的唯一方法,而无需为每个作业设置多个临时日志文件的权限,然后将它们组合在一起,而无需插入输出
以下是我之前的回答,我离开只是出于文档原因:
这里的问题是无法从接收作业获取输出。我希望看到的作业的输出正在由写入主机写入作业中。当receive job被调用时,我在屏幕上看到了所有的输出,但没有任何东西可用于其他管道。当我调用receive job时,似乎所有的write-host cmdlet都会执行,但我并没有任何东西可以拾取并导出文件。下面的脚本演示了这一点。您会注意到“睡眠时间”同时出现在日志文件和主机中,而“睡眠时间”只出现在主机中。因此,我需要修改日志函数,使其不使用write host或拆分输出,而不是尝试通过管道将接收作业传递给write host,如下所示
下面是一个示例,它将运行并发作业,然后根据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
您可以通过管道将Get进程设置为表格格式,以便查看所有输出
Get-Process -Name "explorer" | format-Table -hidetableheaders -AutoSize
你可以在脚本的结尾使用类似的东西
Get-job | Receive-Job 2>&1 >> c:\path\to\your\log\file.log
“2>&1>>”从Get Job | Receive Job获取所有输出如果作业使用写入主机生成输出,则Receive Job返回$null,但结果会写入主机。但是,如果作业使用写输出代替写主机生成输出,则接收作业将返回作业输出的字符串数组[string[]
要演示,请在PowerShell提示符下输入此无害代码:
$job = Start-Job -ScriptBlock {
[int] $counter = 0
while ($counter -lt 10) {
Write-Output "Counter = $counter."
Start-Sleep -Seconds 5
$counter++
}
}
等待约20-30秒,使作业产生一些输出,然后输入以下代码:
$result = Receive-Job -Job $job
$result.Count
$result
$result | Get-Member
$result对象包含作业生成的字符串。此问题的简单解决方案。写冗长的“废话”-冗长的
我使用receive Job CMDlet找到了如何接收将主机结果写入变量的解决方案,它在Powershell 5.1上运行:
$var = Receive-Job $job 6>&1
我知道这是旧的。我不经常使用作业,所以当我偶然发现这条线索时,我显然也遇到了同样的问题。无论如何,我找到了一个不同的解决方案,所以我想我应该把它扔出去
同样在PowerShell 5.1中,我只是引用了作业对象上的属性,在我的示例中,如下所示:
$Jobs.ChildJobs.Output | Out-File <LogFile> -Append
Keith I修改了我的脚本,因此只调用了一次receive job,并且验证了receive job不会在脚本中的任何其他位置使用。顺便说一句,当您使用-OutVariable
时,请提供变量名而不是变量,例如-ov temp
。然后你以后用$temp
访问该信息。是的,很抱歉这是一个打字错误。。。我已经改变了很多。有没有办法得到你提到的“当前最佳方式”的副本?谢谢我也有同样的问题。我在答案的末尾添加了一个代码示例,希望这是有用的。这是一个很棒的问题。正如您在下面提到的,写输出没有帮助,因为它会干扰函数调用返回的内容。我认为Write Verbose可能会很有帮助,就像您可以在作业的子作业的Verbose字段上执行ReadAll一样,但只有在设置了Verbose首选项时才会填充它,这意味着它也会显示在输出中。真的,我认为我们需要修复这个bug:请参见下面的@Spongebob密码器答案。它可以让您轻松地将子作业的写入主机的输出转换为变量,这非常好。在我的工作中,我将其与开始记录/停止记录结合使用。然后我有每个作业的日志,但是每个作业的日志都可以与每个接收作业一起检查。您的顶级控制台仍然存在被子作业的写主机调用污染的问题,但我在这里看到的任何解决方案都无法解决这个问题。如果有人好奇它是如何工作的:从msdn:&1重定向规范
$var = Receive-Job $job 6>&1
$Jobs.ChildJobs.Output | Out-File <LogFile> -Append
Output : {}
Error : {}
Progress : {}
Verbose : {}
Debug : {}
Warning : {}
Information : {}