New-TaskPool.ps1 - Threading the Powershell way
For a while now I've been trying to perfect a script that will let me simulate having multiple threads in powershell. Here's what I've come up with. The entire script is attached to the post. I'll only be discussing a few bits and pieces today. Feel free to leave any questions in the comments section.
The general idea of the script is that you give it a scriptblock as an argument and then pass items to it via the pipeline. It’ll take each input and pass it into an available “runspace pool” if there is one. If not, it waits for an available pool to open up. As each input is processed, the script writes the output back up the pipeline. An example might make things a bit clearer.
Let’s say you want to scan a list of computer names to see if they have a particular hotfix. You can do this remotely using get-wmiobject and the win32_quickfixengeneering class. Something like:
gwmi -co "testmachine" -class win32_quickfixengineering -ea silentlycontinue | ? { $_.HotFixID -eq "KB931836" }
Let’s see how long this takes to run on just 4 computers (yes, I used the same computer over and over… this is just an example):
14# measure-command { "testmachine","testmachine","testmachine","testmachine" | % { gwmi -co $_ -class win32_quickfixeng
ineering -ea silentlycontinue | ? { $_.HotFixID -eq "KB931836" } } }
Days : 0
Hours : 0
Minutes : 0
Seconds : 43
Milliseconds : 662
Ticks : 436625205
TotalDays : 0.000505353246527778
TotalHours : 0.0121284779166667
TotalMinutes : 0.727708675
TotalSeconds : 43.6625205
TotalMilliseconds : 43662.5205
The times are long because I’m scanning the computer across a WAN connection, but considering I work with 7 physical sites…this is a good test.
Now let’s see the same thing but fed to New-TaskPool as a scriptblock:
24# $block = {
>> $input | % {
>> $fixed = gwmi -co $_ -class win32_quickfixengineering -ea silentlycontinue | ? { $_.HotFixID -eq "KB931836" }
>> write-Output $fixed
>> }
>> }
>>
25# "testmachine","testmachine","testmachine","testmachine" | .\New-TaskPool.ps1 -scriptblock $block
Description : Update for Windows Server 2003 (KB931836)
FixComments : Update
HotFixID : KB931836
Install Date :
InstalledBy : SYSTEM
InstalledOn : 2/14/2007
Name :
ServicePackInEffect : SP3
Status :
Description : Update for Windows Server 2003 (KB931836)
FixComments : Update
HotFixID : KB931836
Install Date :
InstalledBy : SYSTEM
InstalledOn : 2/14/2007
Name :
ServicePackInEffect : SP3
Status :
Description : Update for Windows Server 2003 (KB931836)
FixComments : Update
HotFixID : KB931836
Install Date :
InstalledBy : SYSTEM
InstalledOn : 2/14/2007
Name :
ServicePackInEffect : SP3
Status :
Description : Update for Windows Server 2003 (KB931836)
FixComments : Update
HotFixID : KB931836
Install Date :
InstalledBy : SYSTEM
InstalledOn : 2/14/2007
Name :
ServicePackInEffect : SP3
Status :
And does it make any speed difference?
21# measure-command { "testmachine","testmachine","testmachine","testmachine" | .\new-taskpool.ps1 -scriptblock { $input
| % {gwmi -co $_ -class win32_quickfixengineering -ea silentlycontinue | ? { $_.HotFixID -eq "KB931836" } } } }
Days : 0
Hours : 0
Minutes : 0
Seconds : 10
Milliseconds : 410
Ticks : 104106992
TotalDays : 0.000120494203703704
TotalHours : 0.00289186088888889
TotalMinutes : 0.173511653333333
TotalSeconds : 10.4106992
TotalMilliseconds : 10410.6992
4 times faster (which makes sense because all 4 gwmi queries where happening simultaneously). Obviously, this scriptblock is insanely simple so you’ll see the most value of this with scriptblocks that take a little time to complete.
Before I leave, one thing to point out is that your scriptblock needs to be expecting pipeline input, so you have to use something like:
$input | % {
## Do whatever you want here and finally
## output results.
Write-Output $_
}
Obviously, this is just echoing the input back into the output.
I’ll stop here for now, but will continue with some additional entries later that discuss the other arguments (such as –failblock) and give a couple real-world scriptblock examples that I use.
gaurhoth