-
-
Save davidjenni/7eb707e60316cdd97549b37ca95fbe93 to your computer and use it in GitHub Desktop.
# calculate IP address range from CIDR notation | |
# https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing | |
function cidrToIpRange { | |
param ( | |
[string] $cidrNotation | |
) | |
$addr, $maskLength = $cidrNotation -split '/' | |
[int]$maskLen = 0 | |
if (-not [int32]::TryParse($maskLength, [ref] $maskLen)) { | |
throw "Cannot parse CIDR mask length string: '$maskLen'" | |
} | |
if (0 -gt $maskLen -or $maskLen -gt 32) { | |
throw "CIDR mask length must be between 0 and 32" | |
} | |
$ipAddr = [Net.IPAddress]::Parse($addr) | |
if ($ipAddr -eq $null) { | |
throw "Cannot parse IP address: $addr" | |
} | |
if ($ipAddr.AddressFamily -ne [Net.Sockets.AddressFamily]::InterNetwork) { | |
throw "Can only process CIDR for IPv4" | |
} | |
$shiftCnt = 32 - $maskLen | |
$mask = -bnot ((1 -shl $shiftCnt) - 1) | |
$ipNum = [Net.IPAddress]::NetworkToHostOrder([BitConverter]::ToInt32($ipAddr.GetAddressBytes(), 0)) | |
$ipStart = ($ipNum -band $mask) + 1 | |
$ipEnd = ($ipNum -bor (-bnot $mask)) - 1 | |
# return as tuple of strings: | |
([BitConverter]::GetBytes([Net.IPAddress]::HostToNetworkOrder($ipStart)) | ForEach-Object { $_ } ) -join '.' | |
([BitConverter]::GetBytes([Net.IPAddress]::HostToNetworkOrder($ipEnd)) | ForEach-Object { $_ } ) -join '.' | |
} | |
$start, $end = cidrToIpRange "192.168.100.14/24" | |
Write-Host "Start: $start, end: $end" | |
$start, $end = cidrToIpRange "10.77.1.1/18" | |
Write-Host "Start: $start, end: $end" |
Is the script supposed to support /32?
I apologize if I am missing something!
When I tried it returned for 13.95.147.65/32 the start IP of 13.95.147.66 and end IP of 13.95.147.64
I "hacked" it by replacing lines 28 and 29 with
if ($maskLen -eq 32) {
$ipStart =$ipNum
$ipEnd=$ipNum
}
else
{
$ipStart = ($ipNum -band $mask) + 1
$ipEnd = ($ipNum -bor (-bnot $mask)) - 1
}
I think the +1/-1 should be removed altogether. That's what I did in my fork after verifying.
Thanks, Just what I needed ;-)
The script is really good but does not work well when the mask is 31 or 32.
For an input 13.105.220.108/31 it will produce a result like:
Start Host: 13.105.220.109
End Host: 13.105.220.108
To fix that just replace lines 28 and 29
$ipStart = ($ipNum -band $mask) + 1 $ipEnd = ($ipNum -bor (-bnot $mask)) - 1
By this
` $ipStart = $ipNum -band $mask
$ipEnd = $ipNum -bor (-bnot $mask)
if ($maskLength -lt 31) {
$ipStart += 1
$ipEnd -= 1
}`
I've tested this with more than 4000 cidr
great script. I'm using powershell 7 so I change the return to a custom object with named parameters: