Here is a Ping sweeper script using Powershell jobs to speed things up.
The script works (at a high level) like this:
- I create an array of IP addresses to scan.
- I loop through each IP
- If I am running the max number of concurrent jobs, wait for some jobs to finish, add the results of those jobs to the $Result array
- If I am not running at the max number of concurrent jobs. start a job to ping the current IP
- When I have looped though all the IPs to scan I should have (the maximum) number of jobs still running.
- wait for all of the jobs to finish, add the results of those jobs to the $Result array
Here is the script. I will explain each section in detail at the end.
# build an array of IP address
$IPsToScan = @()
$Subnet = "192.168.0."
for ($x = 1 ; $x -lt 255 ; $x ++)
{
$IPsToScan += ($Subnet + $x)
}
# get the time at the start (so we can time the script)
$startTime = get-date
# user variables
$maxRunningTasks = 20 # max number of powershell jobs to concurrently run
# script variables
$Result = @()
$CurrentRunningTasks = 0 # number of running jobs (dont change this)
foreach ($IPToScan in $IPsToScan)
{
# loop through each IP to scan
"Jobs running $CurrentRunningTasks, IP to scan $IPToScan"
# if we are at the max number of running jobs, wait for some jobs to finsh.
while ($CurrentRunningTasks -eq $maxRunningTasks)
{
# max number if tasks are running, wait and evaluate task status
"max jobs running, sleeping for 5 seconds"
start-sleep -seconds 5
# loop though jobs
foreach($CurrentJob in get-job)
{
# if a job has finished, get its data and remove it
if ($CurrentJob.state -eq "Completed")
{
# get finished job data, add it to the $result array
$tmpJobObj = Receive-Job $CurrentJob.Id -keep
$Result += $tmpJobObj
# remove the finished job
remove-job -id $CurrentJob.id
$CurrentRunningTasks --
# write some nice output on the screen
if ($tmpJobObj -like "dead")
{
write-host $tmpJobObj -ForegroundColor red
}else{
write-host $tmpJobObj -ForegroundColor green
}
}
}
}
# run the job
$CurrentRunningTasks ++
Start-Job -Name PingTest -Scriptblock {
param($TargetIP)
test-connection $TargetIP -Count 1 -ErrorAction SilentlyContinue > $Null
if ($?)
{
return $TargetIP + " is OK"
}else{
return $TargetIP + " is dead"
}
} -Arg $IPToScan
}
# we have now run out of jobs to run so there should be $maxRunningTasks still running. wait for them
while ($CurrentRunningTasks -gt 0)
{
# max number if tasks are running, wait and evaluate task status
"max jobs running, sleeping for 5 seconds"
start-sleep -seconds 5
foreach($CurrentJob in get-job)
{
if ($CurrentJob.state -eq "Completed")
{
# get finished job data, add it to the $result array
$tmpJobObj = Receive-Job $CurrentJob.Id -keep
$Result += $tmpJobObj
# remove the finished job
remove-job -id $CurrentJob.id
$CurrentRunningTasks --
# write some nice output on the screen
if ($tmpJobObj -like "dead")
{
write-host $tmpJobObj -ForegroundColor red
}else{
write-host $tmpJobObj -ForegroundColor green
}
}
}
}
# get the time at the end and then display the difference
$endTime = get-date
[int]$SecondsToRun = ($endTime - $startTime).totalSeconds
"This Script took $SecondsToRun seconds to run with $maxRunningTasks concurrent jobs"
Running this script will scan the 192.168.0.0/24 IP range with 20 concurrent jobs running at once. by increasing that number the script will complete faster but at the cost of more memory and CPU usage.
Lines 1 – 7. I am creating an array of all the IPs I want to ping. A simple for do loop adding the loop number to the string “192.168.0.”
Lines 8 – 9. Get the time so I can time the script
Lines 12 – 13. User variables. Set the maximum number of powershell jobs to run at once.
Lines 20 – 23. Loop though each IP to scan.
Lines 25- 30. If we are running the max number of concurrent jobs wait 5 seconds
Lines 31 – 35. Loop though all the jobs
Lines 36 – 40. if the Job has finished get its return value and add it to the $Result array
Lines 42 – 45. remove the finished job
Lines 46 – 54. write the result of the job to the screen.
Lines 58 – 72. at his point we should not be running the maximum number of concurrent jobs. so we define the job ad run it.
I have job the job as simple as possible. it will return a test string and nothing else.
Lines 74 – 102. This is the same peace of code to wait, check and get job results as lines 25 – 54.
Then the foreach loop has looped through the IP array there will still be up to the max number of jobs still running. This section will wait for those jobs to finish and add the results to the $Result array
Lines 104 – 107. Get the time at the end. and show the difference in seconds.
That is a simple(ish) script to manage Powershell jobs.
The other posts about jobs are:
Part 1, what is a job
Part 3, Getting data out of a job.