Creating a Port Scanner with Windows PowerShell

Summary: Microsoft Scripting Guy, Ed Wilson, talks about creating a port scanner with Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. The other day, I needed to access my printer. Unfortunately, after several networking changes, I did not remember the IP address of my printer. However, I did know that the printer sets up a web server. It was this web server that I needed to access so I could make some changes to the way the printer was handling default forms.

But dude, I did not know the IP address, and I did not want to have to rummage around in my network documentation to find the particular printer in question. So what to do? I figured it would be easier to write a port scanner. By using Windows PowerShell, this was actually a pretty simple task. I simply needed to look for a device listening on Port 80.

Create a range of IP addresses

First I will admit that my solution is not the cleanest solution possible. I will also admit it is not the fastest solution possible. I think my solution might simply be useful to show something that I could do. And like I said in my introduction, it met my need at the time. Perhaps one of the cool things about Windows PowerShell is that it permits this sort of ad-hoc solution to be easily created.

So, I needed to create a range of IP addresses. Actually, the only range I needed to create was a range of host addresses for a class A network. Therefore, I used the range operator and created an array of numbers that go from 1 to 254. As I mentioned earlier, I am only interested in Port 80, so I assign that as a value to the variable $port. My class A network address is 192.168.0, so I assign that as a value to the $net variable. This is shown here:

$port = 80

$net = “192.168.0”

$range = 1..254

Note  I highly recommend using meaningful variables when you write a script—even a quick script such as this. Using the Hungarian Notation is not required, but I think that calling a port $port certainly is. It makes the script easier to read and understand.

Create the IP addresses

Now, I am going to walk through my array of numbers (1..254) and create a whole bunch of IP addresses. Of course, I will create them one at a time. After an IP address is created, I ping the address to see if it responds. If it does, I will attempt a connection to Port 80 to see if I find a web server for my printer. But first the IP address…

To walk through the array, I use the ForEach command. Following the word ForEach, I create a new variable, $r, to hold the individual number from the array. Therefore, the first time through, $r will be equal to 1.

I then open a script block, and create my IP address, and store it in the variable $ip. There are two parts to my IP address, the first part is my network address, 192.168.0, the second part is the individual number I get from my $range of numbers. I want to put them together in order, first the $net address followed by a period, and then the number ($r).

I use a format specifier to do this. “{0}.{1}” tells Windows PowerShell to take the first value following the –F and put it in position {0}. In this case, it is the value that is stored in the $net variable. Next we have the “.” And then the second thing to substitute, which goes into position {1}. This value will be the second value following the –F, which is the value stored in the $r variable. Here is the script that does all this:

foreach ($r in $range)

{

 $ip = “{0}.{1}” -F $net,$r

Ping…

After I have created my IP address, it is time to ping the remote computer. I use the Test-Connection cmdlet to do this. I am using –Quiet mode, and therefore it will return $true or $false depending on whether it receives a return. I specify a buffer size of 32, and I want to send one ping only. Then I specify the destination as the IP address stored in the $IP variable. The command is shown here:

if(Test-Connection -BufferSize 32 -Count 1 -Quiet -ComputerName $ip)

   {

If I get a return, I attempt to make a connection to Port 80. To do this, I use a .NET Framework class, TcpClient from the System.Net.Sockets assembly. The TcpClient class lets me specify a port number and an IP address. I store any returned socket in the $socket variable. This command is shown here:

{

     $socket = new-object System.Net.Sockets.TcpClient($ip, $port)  

Did we make a connection?

Now I need to see if I made a connection to Port 80. To do this, I can check the Connected property. If I am connected to the remote socket, I print a string that the device at that IP address is listening to Port 80. I then close the connection. This script is shown here:

If($socket.Connected)

       {

        “$ip listening to port $port”

        $socket.Close() }

        }

}

That is it. I did not need to check anything else, nor do I need an ELSE condition. I was simply looking for devices listening to Port 80. Interestingly enough, I found out that one of my switches had also set up a web server. This, I am afraid to admit, I did not know. So this also becomes a useful network security technique.

Here is the completed script—not much to it, but it worked for me.

# —————————————————————————–

# Script: PoshPortScanner.ps1

# Author: ed wilson, msft

# Date: 02/19/2014 15:17:33

# Keywords: Security, Networking, Tcp/IP, Monitoring

# comments: This script scans a range of IP addresses for web servers listening

# to port 80. It is a useful audit tool, because there are lots of software and

# devices that setup web servers for management, but that do not necessarily

# inform about them.

#

# —————————————————————————–

$port = 80

$net = “192.168.0”

$range = 1..254

foreach ($r in $range)

{

 $ip = “{0}.{1}” -F $net,$r

 if(Test-Connection -BufferSize 32 -Count 1 -Quiet -ComputerName $ip)

   {

     $socket = new-object System.Net.Sockets.TcpClient($ip, $port)

     If($socket.Connected)

       {

        “$ip listening to port $port”

        $socket.Close() }

         }

 }

Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy