Calculate and enumerate subnets with PSipcalc

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

This PSipcalc program lets you retrieve information about a network in PowerShell, just like ipcalc would do for you on Linux. Most of the same data is there, such as "HostMin", "HostMax", broadcast address in both binary and as an IP, the same for the network address (determined automatically even if you don't supply an actual network address, but an IP in that network, as determined from CIDR/subnet mask), total number of IPs, usable IPs, subnet mask, network length as an int, etc.

Originally, I was going to improve another script I wrote, to make it use runspaces for concurrency, and also implement more nmap-like features like accepting CIDR notation and enumerating subnets. I will update this article with a link to that tool if/when I get around to it. ... I did! Check out my PowerShell nmap-like program.

I researched a bit and found a C# library on CodePlex for performing calculations on subnets, etc., but it wouldn't load in my PowerShell session (v4, Windows 8.1). So, instead, apparently I ended up spending the weekend writing a sort of PowerShell ipcalc clone as a starting point for this other module that I mentioned above.

PSipcalc also lets you enumerate entire IP ranges supplied via CIDR notation or as IP/subnet mask, with the -Enumerate parameter. Beware that a /16 subnet takes about 10 seconds on my computer, while an /8 network took almost exactly an hour - so you will want to remember to assign to a variable or otherwise export when you run it with the -Enumerate parameter against huge IP ranges.

Should work with PowerShell version 2 and up.

It supports the usual variants of syntax for providing a network:

Regular CIDR notation:

10.20.30.40/24

... or with a subnet mask (space or slash between works):

10.20.30.40/255.255.255.0

I also have an article about validating and listing IPv4 subnet masks here. There's an article about validating IPv4 addresses using a regex here, and one for IPv6 addresses here.



PSipcalc Screenshot Example

PSipcalc-example.png

Download PSipcalc

  • PSipcalc.ps1.txt - right-click, download, and unblock. Rename to .ps1 only.
  • You can also download PSipcalc as part of the PSnmap module (you'll also get PSnmap from the same module): PSnmap.zip. It exports the functions Invoke-PSnmap (alias PSnmap) and Invoke-PSipcalc (alias PSipcalc).

If you have WMF 5 or higher (PowerShell version 5 - available for Windows 7 and up), you can also get Invoke-PSipcalc from the PSnmap module, via the PowerShell gallery, simply by running this command:

Install-Module -Name PSnmap

Change history for PSipcalc.ps1:

  • 2015-07-16: v1.2. Standardized the TotalHosts and UsableHosts properties to always be of the type int64. Formerly TotalHosts was a string, except for network lengths of 30-32, when it was an int32. UsableHosts used to be int32.
  • 2015-07-15: v1.1. Added a -Contains parameter that returns a boolean value (true/false) for whether the specified IPv4 address is in the specified subnet. Based on feedback from the Reddit user "real_parbold".


More PSipcalc Examples

Display Network Address

A little trickery to display the network address for various network lengths and the IP "10.20.30.40".

PS C:\temp> 4, 8, 16, 24, 32  | foreach { .\PSipcalc.ps1 -Net "10.20.30.40/$_" } | Select -Expand NetworkAddress
0.0.0.0
10.0.0.0
10.20.0.0
10.20.30.0
10.20.30.40

Enumerate IPs in a Network

Use the -Enumerate parameter.

PS C:\temp> $Results = .\PSipcalc.ps1 -NetworkAddress '192.168.0.10 255.255.255.224' -Enumerate

PS C:\temp> $Results

IP                   : 192.168.0.10
NetworkLength        : 27
SubnetMask           : 255.255.255.224
NetworkAddress       : 192.168.0.0
HostMin              : 192.168.0.1
HostMax              : 192.168.0.30
Broadcast            : 192.168.0.31
UsableHosts          : 30
TotalHosts           : 32
IPEnumerated         : {192.168.0.1, 192.168.0.2, 192.168.0.3, 192.168.0.4...}
BinaryIP             : 11000000101010000000000000001010
BinarySubnetMask     : 11111111111111111111111111100000
BinaryNetworkAddress : 11000000101010000000000000000000
BinaryBroadcast      : 11000000101010000000000000011111

PS C:\temp> $Results.IPEnumerated
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
192.168.0.11
192.168.0.12
192.168.0.13
192.168.0.14
192.168.0.15
192.168.0.16
192.168.0.17
192.168.0.18
192.168.0.19
192.168.0.20
192.168.0.21
192.168.0.22
192.168.0.23
192.168.0.24
192.168.0.25
192.168.0.26
192.168.0.27
192.168.0.28
192.168.0.29
192.168.0.30

Find out if an IP is in a specified network

Use the -Contains parameter. It includes the network address itself and the broadcast address.

If you specify multiple networks, the IP specified with -Contains will be checked against all of them, and a bool will be returned for each network.

PS C:\temp> .\PSipcalc.ps1 -Net '192.168.1.15/29' -Contains "192.168.1.10"
True

PS C:\temp> .\PSipcalc.ps1 -Net '192.168.1.15/29' -Contains "192.168.1.50"
False

A little more trickery:

PS C:\temp> 6..17 | %{ "192.168.1.${_}: " + (.\PSipcalc.ps1 -Net '192.168.1.15/29' -Contains "192.168.1.$_") }
192.168.1.6:  False
192.168.1.7:  False
192.168.1.8:  True
192.168.1.9:  True
192.168.1.10: True
192.168.1.11: True
192.168.1.12: True
192.168.1.13: True
192.168.1.14: True
192.168.1.15: True
192.168.1.16: False
192.168.1.17: False

Find out if an IP is in the enumerated collection

If you enumerate and want to see if an IP is in the usable hosts list returned from PSipcalc, you can do it like this:

PS C:\temp> $Results = .\PSipcalc.ps1 -Net '192.168.1.15/29' -Enumerate

PS C:\temp> $Results.IPEnumerated
192.168.1.9
192.168.1.10
192.168.1.11
192.168.1.12
192.168.1.13
192.168.1.14

# With the -contains operator
PS C:\temp> $Results.IPEnumerated -Contains '192.168.1.11'
True

# from PSv3 and up you can also use "-in" and .Contains on the array.
PS C:\temp> '192.168.1.10' -in $Results.IPEnumerated
True

PS C:\temp> $Results.IPEnumerated.Contains('192.168.1.9')
True

PS C:\temp> $Results.IPEnumerated.Contains('192.168.1.8')
False