### Calculating TCP/IP Subnets with PowerShell

A PowerShell TCP/IP Subnet Calculator.  If you don't quite understand IP subnets, or even if you do, they can get a little confusing; especially if you've got your network subnetted into extra-large or extra-small chunks, where the boundaries of the subnet don't land neatly at 0 and 255.  The PowerShell script below takes an IP address and a subnet mask as input, and calculates the network ID, the range of addresses, and the broadcast address.

In my previous article, Understanding TCP/IP Subnets, I explained the basics of converting IP addresses and subnet masks to binary to understand what's going on.  Here, we do it with PowerShell.

If you're just looking for an online subnet calculator, try ours: TCP/IP Subnet Calculator

The first thing we do is convert the IP address and subnet mask into binary, so for example, if we input a subnet mask of 255.255.255.0, the binary representation is:

11111111 11111111 1111111 00000000

We then count the number of 1's which gives us the number of bits (netbits) assigned to the network ID (this is the meaning of the subnet mask).  In this case, 24 bits are the network ID, the remaining 8 are the host ID.

Next, we get the actual network ID from our IP address by taking the first 24 (or how ever many netbits) characters from our binary IP address, and the rest of the 32 bits set to zero.  For example, if our IP address is 192.168.1.5, the binary representation is:

11000000 10101000 00000001 00000101

and so our network ID is:

11000000 10101000 00000001 00000000 (192.168.1.0)

The network ID is commonly displayed with the number of netbits at the end, e.g. 192.168.1.0/24

The remaining bits (8 in our example) are used for the host ID portion of the IP address.  As shown above, a host ID of all 0's is the network ID.  A host ID of all 1's is the broadcast address.  The valid range of assignable addresses in a subnet is from all 0's + 1 to all 1's -1.  In our example, that's 00000001 (1) to 11111110 (254).

Try some different subnet masks and see what happens.  For example, if you change the subnet mask to 255.255.255.128 (25 netbits), you'll see the range of assignable addresses get cut in half, and if you change the subnet mask to 255.255.254.0, you'll see the range of assignable addresses double.

The script also does some basic validation of the IP address and subnet mask (making sure that they are 32 bits long and that the host ID is not all 0's nor all 1's).  This is certainly not an exhaustive check, there are lots of reserved addresses that would be considered not valid.

```function toBinary (\$dottedDecimal){
return \$binary
}
```
```function toDottedDecimal (\$binary){
do {\$dottedDecimal += "." + [string]\$([convert]::toInt32(\$binary.substring(\$i,8),2)); \$i+=8 } while (\$i -le 24)
return \$dottedDecimal.substring(1)
}
```
```#read args and convert to binary
\$ipBinary = toBinary \$args
\$smBinary = toBinary \$args
```
```#how many bits are the network ID
\$netBits=\$smBinary.indexOf("0")
```
```#validate the subnet mask
if((\$smBinary.length -ne 32) -or (\$smBinary.substring(\$netBits).contains("1") -eq \$true)) {
Exit
}
```
```#validate that the IP address
if((\$ipBinary.length -ne 32) -or (\$ipBinary.substring(\$netBits) -eq "00000000") -or (\$ipBinary.substring(\$netBits) -eq "11111111")) {
Exit
}
```
```#identify subnet boundaries
```
```#write output
"`n   Network ID:`t\$networkID/\$netBits"
```

Jeff said...

Love the script, I made a slight change. If you are going to use this in a function, you need to reinitialize your variables (one of these gave me a few issues). See new function:

function toDottedDecimal (\$binary){
\$i=0
do {\$dottedDecimal += "." + [string]\$([convert]::toInt32(\$binary.substring(\$i,8),2)); \$i+=8 } while (\$i -le 24)
return \$dottedDecimal.substring(1)
}

Unknown said...

I'm running this on a subnet defined as 10.247.128.0/18. This script returns /19. Any ideas?

Brian said...