Powershell: получение выходных данных из Receive-Job
у меня есть набор заданий, которые выполняются. Когда они завершаются, я использую receive-job, и он записывает вывод на экран. Я хотел бы взять этот вывод и записать его в файл. Я не хочу использовать выходные данные, полученные во время выполнения заданий, потому что при одновременном выполнении нескольких заданий журнал будет перемежаться. Get-Job / Receive-Job печатает вывод в хорошей организованной манере.
Я пробовал все следующие и выходные данные не записываются в файл или храниться в переменной он просто переходит на экран:
#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)
}
изменить: Я удалил дополнительные вызовы Receive-Job в 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 и out-файл по-прежнему не производят вывода.
6 ответов
Примечание: после некоторых экспериментов я обнаружил, что использование write-output или просто вывод переменной напрямую не является хорошим решением. Если у вас есть функция, которая использует любой из этих методов, а также возвращает значение выходной будет связана с возвратом стоимости!
лучший способ, который я нашел для регистрации вывода из заданий, - использовать write-host в сочетании с командлетами Start-Transcript и Stop-Transcript. Есть некоторые недостатки, такие как ISE не поддерживает командлеты расшифровки. Также я не нашел способ вывода в транскрипт без его перехода на хост (я хотел надежный журнал с менее подробным пользовательским опытом), но, похоже, это лучшее решение, доступное в настоящее время. Это единственный способ, которым я смог регистрировать параллельные задания без чередования выходных данных без необходимости править несколько временных файлов журнала для каждого задания, а затем комбинировать их.
ниже был мой предыдущий ответ, который я оставил просто для документации причины:
проблема здесь заключалась не в получении вывода из Receive-Job. Вывод из заданий, которые я ожидал увидеть, записывается в задание с помощью write-host. Когда receive-job был вызван, я увидел весь свой вывод на экране, но ничего не было доступно для трубы в другом месте. Кажется, когда я вызываю receive-job, все эти командлеты write-host выполняются, но мне нечего забрать и передать в out-file. Следующий сценарий демонстрирует это. Вы заметите, что появляется "сонное время" в файл журнала и хозяин, пока "спал" появляется только в хозяине. Таким образом, вместо того, чтобы пытаться передать Receive-Job в write-host, мне нужно изменить мою функцию журнала, чтобы не использовать 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
Если задание использует Write-Host для получения выходных данных, Receive-Job возвращает $null, но результаты записываются на хост. Однако, если задание использует Write-Output для получения выходных данных вместо Write-Host, Receive-Job возвращает строковый массив [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
будет нечего извлекать (при условии, что задание завершено). Если вы не хотите Receive-Job
для удаления результатов используйте -Keep
переключатель. Теперь это не объясняет, почему ваш первый вызов Receive-Job
ничего не выводит в файл журнала ... если нет части скрипта, который вы не показываете, который делает Receive-Job
до этого.
вы можете передать свой Get-Process в Format-Table, чтобы вы могли видеть все выходные данные.
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
Я нашел soulution, как получать результаты записи-Хоста в переменную с помощью командлета Receive-Job, он работает на Powershell 5.1:
$var = Receive-Job $job 6>&1
простое решение проблемы. Пишите-многословно "blabla" - многословно
$s = New-PSSession -ComputerName "Computer"
$j = Invoke-Command -Session $s -ScriptBlock { Write-Verbose "Message" -Verbose } -AsJob
Wait-Job $j
$Child = $j.ChildJobs[0]
$Child.Verbose | out-file d:/job.log -append