powershelljobswrite-host

Why does Write-Host not work when run in a powershell job?


Sorry if I'm being a dumb powershell noob, but what's wrong with jobs apparently being unable to write to the terminal? And how can I fix that?

# test.ps1
function myjob {
    Write-Host "Hello, World!" # doesn't show
}
Start-Job -Name MyJob -ScriptBlock ${function:myjob}
Wait-Job MyJob
Remove-Job MyJob

Solution

  • It sounds like you're trying to use Write-Host to directly, synchronously write to the console (terminal) from a background job.

    However, PowerShell jobs do not allow direct access to the caller's console. Any output - even to the PowerShell host (which in foreground use is the console, if run in one) is routed through PowerShell's system of output streams (see the conceptual about_Redirection help topic).

    Therefore, you always need the Receive-Job cmdlet in order to receive output from a PowerShell job.

    The following example receives the job output synchronously, i.e. it blocks execution until the job finishes (-Wait) and then removes it (-AutoRemoveJob); see the bottom section for an asynchronous (polling, non-blocking) approach.

    $null = Start-Job -Name MyJob -ScriptBlock { Write-Host "Hello, World!" } 
    Receive-Job -Wait -AutoRemoveJob -Name  MyJob
    

    Caveat re use of Write-Host in jobs:


    Waiting for a job to complete in a non-blocking fashion, passing job output through as it becomes available:

    # Start a simple job that writes a "." to the host once a second,
    # for 5 seconds
    $job = Start-Job $job -ScriptBlock { 
             1..5| ForEach-Object { Write-Host -NoNewLine .; Start-Sleep 1 } 
           } 
    
    "Waiting for job $($job.Id) to terminate while passing its output through..."
    
    do {
      $job | Receive-Job  # See if job output is available (non-blocking) and pass it through
      Start-Sleep 1       # Do other things or sleep a little.
    } while (($job | Get-Job).State -in 'NotStarted', 'Running')
    
    "`nJob terminated with state '$($job.State)'."
    
    $job | Remove-Job     # Clean up.