Public/Read-Job.ps1
function Read-Job { <# .DESCRIPTION Continuously reads the various output streams from a ThreadJob. .PARAMETER Job The job(s) from which to read output streams. .PARAMETER TimeoutMS Stop polling if no new data has been received in `x` milliseconds (default=0; no timeout). .PARAMETER PollMS The number of milliseconds to wait in between each poll (default=250ms; 4 times per sec). .PARAMETER Tee When specified, output written to standard output as well as passed down the pipeline. .PARAMETER AutoRemoveJob When specified, job(s) will be stopped and disposed of upon completion. .OUTPUTS An array of output (if any) from the ThreadJob(s). .EXAMPLE Start-ThreadJob { ... } | Read-Job -TimeoutMS 5000 -AutoRemoveJob #> [cmdletbinding()] param( [Parameter(ValueFromPipeline=$true)] [object[]]$Job, [uint64]$TimeoutMS = 0, [uint32]$PollMS = 250, [switch]$Tee, [switch]$AutoRemoveJob ) begin { [System.Collections.ArrayList]$jobs = New-Object System.Collections.ArrayList } process { foreach ($j in $Job) { if ($j -isnot [ThreadJob.ThreadJob] -and $j -isnot [System.Management.Automation.Job]) { throw [System.InvalidOperationException]::new('Job must be ThreadJob or PSRemotingJob') } else { $null = $jobs.Add($j) } } } end { [uint16]$n_alive = 0 $timer = New-Object System.Diagnostics.Stopwatch $timer.Start() try { do { $n_alive = 0 Start-Sleep -Milliseconds $PollMS foreach ($j in $jobs) { if ($j.HasMoreData) { $j | Read-JobStreams -Tee:$Tee $timer.Restart() } if ($j.State -eq [System.Management.Automation.JobState]::Running) { $n_alive++ } } } while ($n_alive -gt 0 -and ($TimeoutMS -eq 0 -or $timer.ElapsedMilliseconds -lt $TimeoutMS)) $timer.Stop() if ($TimeoutMS -eq 0) { $null = $jobs | Wait-Job -Force } if ($AutoRemoveJob) { $jobs | Stop-Job } $jobs | Read-JobStreams -Tee:$Tee } finally { if ($timer -and $timer.IsRunning) { $timer.Stop() } if ($AutoRemoveJob) { $null = $jobs | Remove-Job -Force } } } } |