Search code examples
powershellstart-job

Get child job's child job output


If you start a job (A) and this job, in turn, starts another job (B), is it possible to fetch the output of (B) by using something as such?

(Get-Job -Name A).ChildJobs[0].ChildJobs[0]...

I was hoping I could recursively drill down into the object but curiously (Get-Job -Name A).ChildJobs[0] always has an empty ChildJobs collection. This may be just a misunderstanding on my part of how jobs are created.

One workaround to this is to wait until job B finishes, fetch its output, store it in a variable, and perform a Write-Output on the variable so the parent script can handle it. It works but that means I have to wait until job B finishes which might take 10-40 minutes.

I could perhaps (in job B) write output immediately as it occurs to a flat file or perhaps a SQLite database but I was hoping I could fetch it from the top-most scope of the script.

Here is an example

    Get-Job | Remove-Job

$ErrorActionPreference = "stop"

$Level1Job = {
    $Level2Job = {
        $Level3Job = {
            Write-Output "Level 3, start"

            Start-Sleep -s 5

            Write-Output "Level 3, end"
        }

        Write-Output "Level 2, start"

        # start the third job...
        Start-Job -ScriptBlock $Level3Job -Name "level 3"

        # wait for the job to complete
        while(get-job | where-object { ($_.State -ne "completed") -and ($_.State -ne "failed") }){ Start-Sleep -s 2 }

        Start-Sleep -s 5

        Write-Output "Level 2, end"
    }

    Write-Output "Level 1, start"

    # start the second job on the remote computer...
    Start-Job -ScriptBlock $Level2Job -Name "level 2"

    # wait for the job to complete
    while(get-job | where-object { ($_.State -ne "completed") -and ($_.State -ne "failed") }){ Start-Sleep -s 2 }

    Start-Sleep -s 5

    Write-Output "Level 1, end"
}

# start the first job...
Start-Job -ScriptBlock $Level1Job -Name "level 1"

# wait for the job to complete
while(get-job | where-object { ($_.State -ne "completed") -and ($_.State -ne "failed") }){ Start-Sleep -s 2 }

Start-Sleep –s 5


(get-job)[0].ChildJobs[0] | fl *

Solution

  • ChildJobs are used for remote-jobs. If you use for example Invoke-Command -ScriptBlock { ... } -AsJob -ComputerName YourRemoteComputer you get a remote-job (the ChildJob) and a local job, that handles the remote-job.

    You have the Job-Object from start-Job. if your first job returns this object, you can receive it and read the output