programing

Powershell: Receive-Job에서 출력 가져오기

minimums 2023. 9. 5. 20:04
반응형

Powershell: 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)
}

편집: 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을 사용하지 않는다는 것을 확인했습니다.write-host $temp 및 out-file은 여전히 출력을 생성하지 않습니다.

작업이 쓰기 호스트를 사용하여 출력을 생성하는 경우 Receive-Job은 $null을 반환하지만 결과는 호스트에 기록됩니다.그러나 작업이 Write-Host 대신 Write-Output을 사용하여 출력을 생성하는 경우 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 개체에는 작업에서 생성된 문자열이 포함되어 있습니다.

참고: 몇 가지 실험을 통해 쓰기 출력을 사용하거나 변수를 직접 출력하는 것도 좋은 해결책이 아니라는 것을 알게 되었습니다.이러한 방법 중 하나를 사용하고 값을 반환하는 함수가 있는 경우 출력은 반환 값과 연결됩니다!

작업 출력을 기록하는 가장 좋은 방법은 쓰기 호스트를 시작-기록 및 중지-기록 cmdlet과 함께 사용하는 것입니다.ISE가 Transcript cmdlet을 지원하지 않는 등의 몇 가지 단점이 있습니다.또한 스크립트가 호스트에게 전달되지 않고 스크립트로 출력할 수 있는 방법을 찾지 못했습니다(사용자 경험이 적은 강력한 로그를 원했습니다). 하지만 현재 사용 가능한 솔루션 중 가장 적합한 솔루션인 것 같습니다.이렇게 하면 각 작업에 대해 여러 임시 로그 파일을 수정한 다음 이를 결합하지 않고도 출력을 중단하지 않고 동시 작업을 기록할 수 있습니다.

아래는 단지 문서화를 위한 이유로 남긴 제 이전 답변은 다음과 같습니다.

여기서 문제는 Receive-Job에서 출력을 가져오지 않는 것이었습니다.기대했던 작업의 출력이 write-host에 의해 작업에 기록되고 있습니다.수신 작업이 호출되었을 때 화면에서 모든 출력을 볼 수 있었지만 다른 곳에서 파이프로 연결할 수 있는 것이 없었습니다.수신 작업을 호출하면 모든 쓰기 호스트 cmdlet이 실행되는 것처럼 보이지만, 내가 픽업하여 파일 외부로 파이프를 연결할 수 있는 것이 없습니다.다음 스크립트는 이를 보여줍니다.로그 파일과 호스트 모두에 "Sleepy Time"이 표시되고 호스트에만 "Sleepy Time"이 표시됩니다.따라서 Receive-Job을 write-host에 파이프로 연결하는 대신 아래와 같이 write-host를 사용하지 않거나 출력을 분할하도록 Log 함수를 수정해야 합니다.

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

Receive-Job CMDlet을 사용하여 Write-Host 결과를 변수로 수신하는 방법에 대한 솔루션을 찾았습니다. 이 솔루션은 Powershell 5.1에서 작동합니다.

$var = Receive-Job $job 6>&1

오래된 거 알아요저는 직업을 잘 사용하지 않기 때문에 이 실마리를 발견했을 때도 분명히 같은 문제를 겪고 있었습니다.어쨌든, 저는 다른 해결책에 도달했기 때문에 저는 그것을 저 밖에 버려야겠다고 생각했습니다.

또한 PowerShell 5.1에서는 작업 개체의 속성을 간단히 참조했습니다. 이 경우 다음과 같이 보였습니다.

$Jobs.ChildJobs.Output | Out-File <LogFile> -Append

모든 스트림이 이런 방식으로 기록된 것 같습니다.단순 에코는 성공 스트림으로 추정되는 출력으로 이동합니다.Write-Host정보 스트림입니다.

Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}
Information   : {}

를 걸 수 .Receive-Job작업이 완료되면 검색할 항목이 없습니다.당신이 원하지 않으면Receive-Job하려면 결를삭사용니다합다음을 합니다.-KeepㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠㅠㅠReceive-Job로그 파일에 아무것도 출력하지 않습니다...당신이 보여주지 않는 스크립트의 부분이 하지 않는 한.Receive-Job

할 때 BTW 시용-OutVariable를 들어 예를들어변아변수이제름공다니합을닌수가.-ov temp그런 다음 나중에 해당 정보에 액세스합니다.$temp.

모든 출력을 볼 수 있도록 Get-Process to Format-Table을 파이프로 연결할 수 있습니다.

    Get-Process -Name "explorer" | format-Table -hidetableheaders -AutoSize

대본의 마지막에 이런 걸 사용할 수도 있고요

    Get-job | Receive-Job 2>&1 >> c:\path\to\your\log\file.log

Get-Job | Receive-Job의 모든 출력을 가져오는 "2>&1 >>"

문제에 대한 간단한 해결책.쓰기-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

제가 한 일은 수신 작업을 전혀 부르지 않는 것입니다.그러나 스크립트를 시작하고 중지하는 래퍼 스크립트 블록을 만듭니다.그런 다음 래퍼 스크립트 블록에서 작업 스크립트 블록을 다음과 같이 부릅니다.

&$ScriptBlock < 파라미터 >

따라서 스크립트는 모든 출력을 파일로 캡처합니다.

언급URL : https://stackoverflow.com/questions/11973775/powershell-get-output-from-receive-job

반응형