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