14 Multitasking with background jobs
This chapter explains how PowerShell, though fundamentally single‑threaded, can multitask by running commands as background jobs. It contrasts synchronous execution—where you wait for a command to finish—with asynchronous jobs that free the console while work continues in the background. Key implications include no interactive prompting in jobs, deferred error visibility, and results that are retrieved after completion. The authors recommend perfecting commands synchronously first, then running them as jobs, and note that “jobs” are an extensibility point—this chapter focuses on the native, built‑in varieties.
PowerShell offers several ways to create jobs. Process jobs (Start-Job) run in a separate PowerShell process and can take a script block or a script file; use absolute paths or -WorkingDirectory, and expect a parent job with at least one child job. Thread jobs (Start-ThreadJob) run on another thread within the same process, start much faster, and are ideal for short tasks; they observe a throttle limit (10 by default) that you can raise, though returns diminish at high counts. Remoting can also run as a job (Invoke-Command -AsJob), fanning out a script block in parallel across many machines subject to a throttle (32 by default). Because commands execute on the targets, this distributes workload; it requires PowerShell 6+ and SSH-based remoting. Many modules (for example, Az) expose -AsJob to return manageable jobs from their cmdlets.
Managing jobs centers on Get-Job for status and Receive-Job for output. You can target parent or child jobs, note that results are cleared unless you use -Keep, and expect deserialized objects suitable for piping to other cmdlets. Child jobs are first-class and can be listed or received individually; they often explain partial failures in multi-target runs. Control commands include Wait-Job to block until completion, Stop-Job to terminate stuck work, and Remove-Job to free memory once output is collected (HasMoreData helps you decide). The chapter warns against nesting job mechanisms (for example, starting a local job inside a remoting session or wrapping Invoke-Command inside Start-Job) and reminds that jobs are per-session, user-isolated, and vanish when the PowerShell process ends. Exercises reinforce creating thread jobs for long searches, fanning them out to remotes, and preserving results in the job queue.
Lab answers
Start-ThreadJob {gci / -recurse –filter '*.txt'}Invoke-Command –scriptblock {gci / -recurse –filter *.txt}
Receive-Job –id 1 –keep
Of course, you would use whatever job ID was applicable or the job name.
FAQ
What’s the difference between synchronous and asynchronous execution in PowerShell?
Synchronous commands block the shell until they finish. Asynchronous execution uses background jobs so the command runs while you keep using the shell. You must decide to run a job before pressing Enter; you can’t “send” a running command to the background. Background jobs can’t prompt for input and their errors/results are retrieved later.What kinds of jobs can I create, and when should I use each?
- Process job:Start-Job runs in a separate PowerShell process; good for long-running tasks.- Thread job:
Start-ThreadJob runs in another thread of the same process; starts fast, great for short tasks; default throttle is 10 (change with -ThrottleLimit).- Remoting job:
Invoke-Command -AsJob runs on remote computers in parallel (default throttle 32); good for distributing work.How do I start a simple background job?
UseStart-Job -ScriptBlock { ... }. Optional: -Name for a friendly name, -FilePath to run a script file, -WorkingDirectory to set the job’s starting path. Prefer absolute paths inside jobs.How do I check job status and get the output?
UseGet-Job to see status. Retrieve results with Receive-Job -Id or -Name. Add -Keep to leave results cached; otherwise they’re cleared. The HasMoreData column shows whether cached output remains.What are child jobs and why do they matter?
Most jobs have one or more child jobs. Parent results aggregate child output. You can inspect child jobs withGet-Job | Select-Object -Expand ChildJobs and receive output per child using Receive-Job on that child. Remoting jobs create a child per target.How do I stop, wait for, or remove jobs?
- Stop:Stop-Job to terminate a running job.- Wait:
Wait-Job to block until completion in scripts.- Remove:
Remove-Job to delete jobs and their cached output (for example, Get-Job | Where-Object {!$_.HasMoreData} | Remove-Job).How are input prompts and errors handled in background jobs?
Jobs can’t prompt for input; missing required parameters cause immediate failure. Errors don’t surface interactively; retrieve them withReceive-Job. Test commands synchronously first, then run them as jobs after they’re solid.What are the prerequisites and limits for each job type?
- Process jobs may require remoting to be enabled locally.- Thread jobs share the process; default throttle is 10 threads (tune with
-ThrottleLimit).- Remoting jobs need PowerShell 6+ and SSH remoting on targets; default parallelism is 32 (change with
-ThrottleLimit).How do I run a job across many remote computers?
UseInvoke-Command -Command { ... } -HostName/-ComputerName ... -AsJob -JobName NameHere. PowerShell fans out to multiple targets in parallel and returns a single parent job. Returned objects include PSComputerName so you can group/sort by source.What does the -AsJob switch on other cmdlets (like Az) do?
Many modules expose-AsJob (for example, New-AzVM -AsJob) to run their work in the background and return a job you can manage with the same Get-Job/Receive-Job/Stop-Job/Remove-Job tooling.
Learn PowerShell in a Month of Lunches, Fourth Edition ebook for free