PowerShell Start-Job

The Start-Job Cmdlet is a fast and extremely simple means of spawning asynchronous threads. Why do we care? Because performing parallel work is faster and our time is important. If I want to inventory the Windows services running on every server in my company, I don’t want to wait for each one to return data, one at a time. Before I move on with the Start-Job Cmdlet, there are two other notable concurrency methods that I won’t be covering in this post; runspaces, and work-flows.

To demonstrate I will use the Windows services task that I mentioned above. Here is how we can find a list of all of the Windows services running on a single server.

[sql]Get-Service | Where-Object { $_.Status -eq ‘Running’ }[/sql]

The simplest form of this Cmdlet is to pass in a script block.

[sql]$jobs = @();
$jobs += Start-Job -ScriptBlock `
{ Get-Service | Where-Object { $_.Status -eq ‘Running’ } }[/sql]

The Start-Job Cmdlet returns a System.Management.Automation.Job object which can be used for receiving the job output, waiting for thread completion, and disposing of the thread.

[sql]#wait for all threads in the array to complete and print their output.
$jobs | Wait-Job | Receive-Job
#dispose of your jobs
$jobs | Remove-Job[/sql]

If you would like to pass in parameters to your script block you can create an argument array. In the script block you must use the $arg[n] syntax, as shown.

[sql]$args = @()
$args += ‘Running’
$jobs += Start-Job -ScriptBlock { Get-Service | Where-Object { $_.Status -eq “$($args[0])” } } -ArgumentList $args[/sql]

Finally, I will demonstrate how to initialize the job with a script. This is often used to pre-load functions to be used in the script block. Let us say that I’ve created a function and saved it as a scriptblock.

[sql][scriptblock]$func = {
function Get-RunningService
Get-Service | Where-Object { $_.Status -eq “Running” }

Then we can create our job like so.

[sql]$jobs += Start-Job -ScriptBlock { Get-RunningService } `
-InitializationScript $func[/sql]

When we bring this all together we have an easy to remember asynchronous process.

[sql]$jobs = @();
$sb = [scriptblock] { write-host “args = $($args[0])”; Invoke-Command -ComputerName ($args[0]) -ScriptBlock { Get-RunningService } }

foreach ($svr in ($servers.Name))
$args = @($svr);
$jobs += Start-Job -ScriptBlock $sb `
-InitializationScript $func `
-ArgumentList $args
$jobs | Wait-Job | Receive-Job
$jobs | Remove-Job[/sql]






2 responses to “PowerShell Start-Job”

  1. […] Understanding Cross-Database Transactions in SQL Server The Read Uncommitted Isolation Level PowerShell Start-Job Forced parameterization to the rescue SQL Server Query Performance After Index Maintenance for […]

  2. […] is very important, especially if your server list is quite large. To achieve this, we will use the Start-Job […]

Leave a Reply

%d bloggers like this: