Powershell: получать результаты от приема-работы
13 Justin Holbrook [2012-08-15 20:06:00]
У меня есть набор заданий, которые выполняются. Когда они заканчиваются, я использую прием-работу и записываю вывод на экран. Я хотел бы взять этот вывод и записать его в файл. Я не хочу получать результаты, созданные во время выполнения заданий, потому что с несколькими заданиями, запущенными сразу, запись будет чередоваться. 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)
}
EDIT: Я удалил дополнительные вызовы Receive-Job в foreach следующим образом, увидев комментарий Keith:
# 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 где-нибудь еще в script. Записи $temp write-host и out-file все равно не выдают результат.
powershell jobs
6 ответов
6 Решение Justin Holbrook [2012-08-16 19:41:00]
ПРИМЕЧАНИЕ. После некоторых экспериментов я обнаружил, что использование write-output или просто вывод переменной напрямую не является хорошим решением. Если у вас есть функция, которая использует любой из этих методов, а также возвращает значение, результат будет конкатенирован с возвращаемым значением!
Лучший способ найти выход из заданий - использовать write-host в сочетании с командлетами Start-Transcript и Stop-Transcript. Есть некоторые недостатки, такие как ISE не поддерживает командлеты Transcript. Кроме того, я не нашел способ вывода в расшифровку без его хостинга (мне нужен надежный журнал с менее подробным пользовательским интерфейсом), но, похоже, это лучшее решение, доступное в настоящее время. Это единственный способ, с помощью которого я мог регистрировать параллельные задания без вставки вывода без необходимости перебора нескольких временных файлов журнала для каждого задания, а затем их объединения.
Ниже был мой предыдущий ответ, который я оставил только по причинам документации:
Проблема здесь не была получена из Receive-Job. Вывод из заданий, которые я ожидал увидеть, записывается в задание с помощью write-host. Когда была получена задание на получение, я видел весь свой вывод на экране, но ничего не было доступно для прокладки в другом месте. Кажется, когда я вызываю get-job, все эти командлеты write-host выполняются, но мне нет ничего, что можно было бы забрать и вывести из файла. Это демонстрирует следующий script. Вы заметите, что "Сонное время" появляется как в файле журнала, так и на хосте, а "Спящий" появляется только на хосте. Поэтому вместо того, чтобы пытаться подключить 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
4 doer [2015-01-28 22:41:00]
Если задание использует 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 содержит строки, созданные заданием.
1 T.CK [2013-12-20 04:40:00]
Вы можете подключить Get-Process к Format-Table, чтобы вы могли видеть весь вывод.
Get-Process -Name "explorer" | format-Table -hidetableheaders -AutoSize
И вы можете использовать что-то вроде этого в конце script...
Get-job | Receive-Job 2>&1 >> c:\path\to\your\log\file.log
"2 > & 1 → " с захватом всего вывода из Get-Job | Receive-Job
1 Keith Hill [2012-08-15 20:17:00]
Когда вы получаете результаты задания, эти результаты удаляются так, что дальнейшие вызовы Receive-Job
не смогут ничего извлечь (при условии, что задание выполнено). Если вы не хотите, чтобы Receive-Job
удалял результаты, используйте переключатель -Keep
. Теперь это не объясняет, почему ваш первый вызов Receive-Job
не выводит ничего в файл журнала... если только часть script вы не показываете, что делает Receive-Job
до этого.
1 SpongeBob the codder [2017-02-16 08:30:00]
Я понял, как получать результаты Write-Host в переменную с CMDlet Receive-Job, он работает над Powershell 5.1:
$var = Receive-Job $job 6>&1
0 Dr Coyo [2016-11-09 17:18:00]
Простое решение проблемы. Запись-Verbose "blabla" -Verbose
$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