Posey's Tips & Tricks

How To Execute Parallel Script Blocks in PowerShell

One of the most welcome new features in PowerShell 7 is the ability to perform parallel execution of script blocks. This new parallel execution capability can drastically reduce the amount of time it takes to process ForEach-Object loops.

In PowerShell, the ForEach-Object cmdlet is used to create a loop that takes action on a series of items. Admittedly, that's a really vague description of what this cmdlet does, but the reason for that is that an "item," as I used the word in the previous sentence, can be almost anything. For example, I often use ForEach-Object loops to manage my servers. In that context, the loop is based on a collection of server names (the server name is the item).

To give you a more concrete example of how this works, let's pretend I have several Hyper-V servers and that I want to get a list of the virtual machines residing on each server. The first thing I would typically do is create a variable that stores the names of the Hyper-V host servers. There are ways to automatically populate such a variable, but that's beyond the scope of what I want to talk about in this article, so I will just manually assign the server names to the variable. Here is what such a command might look like:

$Hosts = 'Hyper-V-1','Hyper-V-2','Hyper-V-3','Hyper-V-4','Hyper-V-5'

Now the variable $Hosts contains the names of five different Hyper-V servers. Here is what the rest of the code might look like:

$Hosts | ForEach-Object { 
Get-VM -ComputerName $_
}

The first line of code listed above creates a ForEach-Object loop based on the list of Hyper-V hosts that I created earlier using the $Hosts variable. This loop will execute once for each host listed within the variable.

The second line of code uses the Get-VM cmdlet to retrieve a list of virtual machines. Normally, the cmdlet's -ComputerName parameter is used to specify a specific host server name. In this case, though, I am using $_ in place of the server name. This tells PowerShell that I want to use the current host name (from the loop based on the contents of the $Hosts variable) in place of a literal host name.

The end result is that the loop uses the Get-VM cmdlet to retrieve a list of virtual machines residing on a host named Hyper-V-1. Once it has done that, it gets a list of the virtual machines on Hyper-V-2. The process is repeated until all of the Hyper-V hosts have been queried.

As you can see from the sequence of events described in the previous paragraph, the script performs a series of serial operations. PowerShell must finish retrieving the list of virtual machines running on one host before it moves on to the next. This probably isn't a big deal since querying a list of virtual machines isn't normally a time-consuming operation, but other looping operations such as retrieving log entries can be quite resource-intensive.

With that in mind, let's take a look at how we can adapt this simple script to perform parallel operations. This will allow the script to query all of the hosts at the same time rather than querying one host at a time. Here is what such a script might look like:

$Hosts = 'Hyper-V-1','Hyper-V-2','Hyper-V-3','Hyper-V-4','Hyper-V-5'
$Hosts | ForEach-Object -Parallel  { 
Get-VM -ComputerName $_
} -ThrottleLimit 5

As you can see, this script is almost identical to the one I showed you before. However, there are two differences. The first difference is that I added the -Parallel switch to the ForEach-Object cmdlet. This is how you tell PowerShell that you want to perform the looping instructions in parallel. Remember, this only works in PowerShell 7.

The other thing I did was add a throttle limit to the end of the script. The throttle limit tells PowerShell how many script blocks it is allowed to run at once. Setting a throttle limit helps keep PowerShell from consuming excessive system resources. If you neglect to specify a throttle limit, PowerShell will set the limit to five for you.

That's all there is to it. Making these two simple changes allows the script to query multiple servers at the same time.

About the Author

Brien Posey is a 22-time Microsoft MVP with decades of IT experience. As a freelance writer, Posey has written thousands of articles and contributed to several dozen books on a wide variety of IT topics. Prior to going freelance, Posey was a CIO for a national chain of hospitals and health care facilities. He has also served as a network administrator for some of the country's largest insurance companies and for the Department of Defense at Fort Knox. In addition to his continued work in IT, Posey has spent the last several years actively training as a commercial scientist-astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space. You can follow his spaceflight training on his Web site.

Featured

comments powered by Disqus

Subscribe on YouTube