An example of how to use New-TaskPool
Those that have been reading my blog for awhile may remember the New-Taskpool script. Basically the script allows me to have multiple runspaces running simultaneously. If we give each runspace an object and a scriptblock... we can run through time consuming operations on several hundred objects a lot faster than doing them one at a time. This is especially helpful on WMI calls to remote machines where the majority of the time is waiting on a response. Just in case anyone has missed it earlier, I've attached the latest version of New-Taskpool to this post. In addition, you can visit the following search results to see the other articles I've written in the past on New-Taskpool.
Here’s a practical example of what I use New-TaskPool for. Generally I have between 300 and 600 computers alive on my LAN. All of these computers are required by policy to have the latest version of Symantec AntiVirus installed and running. To verify this, I use the script found below.
Some things to note about the way New-TaskPool is used. You must pass it a ScriptBlock. You’ll see that I’ve assigned $code the contents of a scriptblock.
Keep in mind that you will not see ANY write-host, write-debug, or write-warning messages from the scriptblock as it’s being executed in a separate runspace and not visible to the current Host. So any output you need, must be in the form of Write-Output. Errors HAVE to be handled (even if you just Trap { continue }) to avoid the runspace becoming stalled with ‘FAILED’ status. I could and probably should clean that up some in the New-Taskpool script – but that’s another blog entry for another day!
You’ll notice in the example, I’m using Get-NBTHosts. I blogged about that function a couple days ago. However, you can use anything that returns a collection of types shown in the switch { … } statement.
For example, any of the 3 would be valid:
$computers = [ADSI]"LDAP://CN=Computers,DC=testlab,DC=com"
$computers.psbase.get_children() | New-TaskPool -script $code -pool 10 | Format-Table Name,AVVersion,AVStatus,AVParent
############################
$computers = "TestMachine01","TestMachine02","TestMachine03"
$computers | New-TaskPool -scriptblock $code | Select-Object Name,AVVersion,AVStatus,AVParent
############################
## If you have PSCX installed:
Get-ADObject -class Computer | New-TaskPool -scriptblock $code | Select-Object Name,AVVersion,AVStatus,AVParent
Function Sweep-Sav {
# Requires:
# new-taskpool v0.8 - Needs to be dot sourced as it's a function
# Expects in Pipeline:
# DirectoryEntry (ADSI), SearchResult (directorysearcher), String with Computer Name or IP, Custom object with NAME property with Computer Name.
# Example:
# Get-ADObject -class Computer | Is-Alive | New-TaskPool -script $code | Format-Table Name,AVVersion,AVStatus,AVParent
# . .\New-TaskPool.ps1
$code = {
$input | % {
$obj = $_
# Accomodate Different Input object types.
switch ($obj.psbase.gettype().name) {
"DirectoryEntry" { $cn = $obj.dnshostname[0] }
"SearchResult" { $cn = $obj.properties['dnshostname'][0] }
"String" { $cn = $obj.replace("IS~","").trim() }
"PSCustomObject" { $cn = $obj.Name }
}
# Add 3 AV Related properties to the object
$obj | add-member -name AVStatus -value $null -membertype NoteProperty -force
$obj | add-member -name AVVersion -value $null -membertype NoteProperty -force
$obj | add-Member -name AVParent -value $null -membertype NoteProperty -force
# Return services that match "'Symantec AntiVirus' or 'Norton AntiVirus',
$serv = get-wmiobject -co $cn -query "Select __SERVER,Name,Status,State from Win32_Service where Name='Symantec AntiVirus' or Name='Norton AntiVirus'" -ea silentlycontinue
## $? = $true if last command completed successfully, $false if unsuccessful.
if (!$?) {
## WMI call failed to complete successfully.
if ( $error[0].tostring() -match "require other privileges" ) {
$obj.AVStatus = "DENIEND"
} elseif ( $error[0].tostring() -match "RPC server is unavailable" ) {
$obj.AVStatus = "OFFLINE" # or Firewalled
}
} elseif ((!$serv) -and $?) {
## WMI completed successfully , but there was no matching service.
$obj.AVStatus = "Not Installed"
} elseif ($serv) {
$obj.AVStatus = $serv.state
# Symantec stores the Version number in a registry key in
# HKLM\Software\Intel\DLLUsage\VP6\ for rtvscan.exe
$rk = [microsoft.win32.registrykey]::openremotebasekey([Microsoft.Win32.RegistryHive]::LocalMachine,$cn)
$rr = $rk.opensubkey("SOFTWARE\INTEL\DLLUsage\VP6")
if ($rr) {
$obj.AVVersion = $rr.getvalue(($rr.getvaluenames() | select-String "rtvscan"))
$rr = $rk.opensubkey("SOFTWARE\INTEL\LANDesk\VirusProtect6\CurrentVersion")
$obj.AVParent = $rr.getvalue("Parent")
} else {
# Try 64bit
$rr = $rk.opensubkey("SOFTWARE\Wow6432Node\INTEL\DLLUsage\VP6")
$obj.AVVersion = $rr.getvalue(($rr.getvaluenames() | select-String "rtvscan"))
$rr = $rk.opensubkey("SOFTWARE\Wow6432Node\INTEL\LANDesk\VirusProtect6\CurrentVersion")
$obj.AVParent = $rr.getvalue("Parent")
}
}
write-Output $obj
trap {
#I'm cheating and just ignoring any errors.
continue
}
}
}
Get-NBTHosts 192.168.10.0/24 | New-TaskPool -scriptblock $code | Select-Object Name,AVVersion,AVStatus,AVParent
}
Comments Welcome as always:
$emailaddress = [string]::join("",("gaurhoth",[char]64,"g","m","a","i","l",".","c","o","m"))