Using PowerShell Workflow to initiate script blocks in parallel

If you're trying to roll something out to a large number of computers, you know how long it takes to do that sequentially in a foreach loop, or similar.

PowerShell will start the command for each item in order, waiting for it to finish before returning the response and moving on to the next one.

Here's a quick way to run your same script, in parallel, using PowerShell workflow.

In this example, I am simply telling a number of servers to run the "gpupdate /force" command, so that they get the latest GPO changes immediately.


#Prompt user for credential that has access to the remote computers
$cred = get-credential

#Set the list of computers on which to run the command
$computerlist = "server01","server02","server03","server04"


#use the workflow keyword (it's very similar to a function)
workflow update-grouppolicy {

#Set the input parameters (again, like a function)
   param([string[]]$computers,
            $cred)

#The foreach -parallel command
   foreach –parallel ($computer in $computers){

#Use the sequence keyword, to ensure everything inside of it runs in order on each computer.
    sequence {

      "Starting $computer"
      
#Use the inlinescript keyword to allow PowerShell workflow to run regular PowerShell cmdlets
      inlineScript{
          $s = New-PSSession -ComputerName $using:computer
          Invoke-Command -Session $s -ScriptBlock {gpupdate /force}
          Remove-PSSession -Session $s
      }

      "$computer done"

    }

   }

} 

update-grouppolicy  -Computers $computerlist



What you'll see when you run this, is that the "Starting $Computer" line gets displayed immediately for every computer in your list. This indicates that the items within the "sequence" block have all initiated. If you have 5 servers in your computer list, then the inlinescript section is running on all 5 of those servers right now.

The "$Computer done" line will display as and when each of those 5 remote servers actually complete their command, which means that "server04 complete" may show up before "server01" complete" does - because it all comes down to how quickly that remote server is able to complete the command.

What's so nice about this, is that one slow remote server doesn't hold up all the others. The others are free to complete, and that one slow server will just finish when it finishes.

Note that the reason the "InlineScript" block is used, is that PowerShell Workflow is not actually Powershell at all - it just looks like it - therefore, if you want to use a number of Powershell cmdlets, they have to be enclosed in an InlineScript block. Also note, that any variables from outside the InlineScript block, but within the Workflow block CAN be used, but to access them from within the InlineScript block, you need to add a $using: to the start of the variable - in this case, $using:computer.

The concept of PowerShell workflow not actually being PowerShell would take way too long to explain, so instead, I'd recommend you go read this for more information.

This post was intended as a quick "how do I do this?" answer, rather than a full explanation - hopefully it helped a few people out! Just replace the InlineScript section with whatever you need to send out to lots of computers at once.