Building a Ping Sweep Tool with PowerShell

I think one of the best ways to learn PowerShell is by using it. I’ve often found the best way to use it is to find a project to work on. With that in mind, I’m going to start us on a little PowerShell project. Although the end result will most likely be useful, the journey is more important than the destination.
I’m hoping that as you read the articles in this short series, you’ll learn new PowerShell commands, techniques and concepts. Honestly, I’m not sure where we’ll end up. I know where I want to start and what I want to show you, but I expect that over the course of working on this project, I’ll come up with another idea or concept to add on.
This is the way I work: start with a core concept and get it working, then slowly add additional features. Even if I know in advance everything that I want to include, I rarely create a tool with everything from the very beginning. The more complex the project, then the more likely the need to debug and troubleshoot. I find it easier to take an iterative approach getting each step to work before adding the next. But enough philosophy, let’s get scripting.

PowerShell Ping Sweep Tool Article Series

  1. Building a Ping Sweep Tool with PowerShell
  2. PowerShell Ping Sweep Tool: Adding Parameter Validation
  3. Adding Trace Information to a PowerShell Ping Tool
  4. Identifying a Computer Name with a PowerShell Ping Sweep Tool
  5. Building a PowerShell Ping Sweep Tool: Adding a Port Check

The task is to create a PowerShell tool that can be used to ping a range of IP addresses. Eventually we should end up with a function that we can run just like a cmdlet. But we don’t need to do that just yet. First, I always get the core commands to work at an interactive console prompt. Because there is no difference between commands running in the console versus a script, let’s get the basics sorted out first without the distractions of trying to create a function.
I know that the PowerShell command for the actual pinging will be Test-Connection. I’ll trust that at some point you will look at full help and examples for this command. The cmdlet will take a computername or IP address and ping it.

The test-connection cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)
The test-connection cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)

In looking at the help, I see a –Quiet parameter. When used, the cmdlet will return either True or False depending on whether there was a response or not.
Using the -quiet parameter with the test-connection cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the -quiet parameter with the test-connection cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)

By default, Test-Connection sends four pings. Since I’m testing a local subnet, if the computer doesn’t respond to a single ping, it probably isn’t going to respond to any, so I can improve performance by using the –Count parameter.

​
Next, I need to figure out how to ping a range of addresses such as 172.16.30.200 to 172.16.30.250. I certainly don't want to type all those addresses. There are a few ways to solve this. Here's the first:
​
In this example, I'm using a looping construct that says, "While the value of $a is less than or equal to the value of $z, create a string that looks like an IP address using the current value of $a and then increment $a by 1."
My loop construct in Windows PowerShell. (Image Credit: Jeff Hicks)
My loop construct in Windows PowerShell. (Image Credit: Jeff Hicks)
All I have to do is insert my Test-Connection command:
My loop construct with the test-connection command. (Image Credit: Jeff Hicks)
My loop construct with the test-connection command. (Image Credit: Jeff Hicks)
And here is an alternative:
​
In this example, I am getting all of the numbers between $a and $z using the Range (..) operator. Each value is piped to ForEach-Object, where I am constructing the IP address by using the –Replace operator. The operator's parameters are a regular expression pattern to match and the value to replace on that match.

The pattern is looking for an ending in 0, and it will be replaced with some number between $a and $z. So which is better? On one hand, I would say whichever you find easier to understand. But perhaps some hard data would help. Taking Test-Connection out of the picture, which technique is faster at creating an IP address? To figure this out, we can use Measure-Command.
To use this cmdlet, simply wrap the commands to be tested in a set of curly braces to create a scriptblock.
The Measure-Command in Windows PowerShell. (Image Credit: Jeff Hicks)
The Measure-Command in Windows PowerShell. (Image Credit: Jeff Hicks)
Pretty darn fast. Let's check the other technique.
Another approach to using Measure-Command. (Image Credit: Jeff Hicks)
Another approach to using Measure-Command. (Image Credit: Jeff Hicks)
When using Measure-Command, first make sure the scriptblock runs successfully. As you can see, the first technique is significantly faster at least from the computer's perspective. Personally, there's not much human difference between the two. But you may want to run a few tests and average the results to be sure.
​
This command is looping 10 times and measuring the scriptblock each time through. The results are then piped to Measure-Object to calculate the average.
The Measure-Command results are being piped to Measure-Object. (Image Credit: Jeff Hicks)
The Measure-Command results are being piped to Measure-Object. (Image Credit: Jeff Hicks)
Changing the scriptblock to use the other code I get this result. 021215 1616 BuildingaPi8 Ok. I'll go with the first option. At this point I can start scripting something to test my logic and lay the foundation for an advanced function.
​

I've added a Write-Host line to see what IP address is being tested and to verify my code that defines the variable. I run the script from the console:
Results from pingsweep.ps1 (Image Credit: Jeff Hicks)
Results from pingsweep.ps1 (Image Credit: Jeff Hicks)
Success! Eventually the variables in my script will most likely become function parameters, but I get ahead of myself. For now, I have a rudimentary PowerShell script that pings a range of IP addresses and tells me if they can be pinged or not. Obviously we are far from finished, so I hope you'll watch for the next article and come back for the next steps in our journey.