Skip to content

Instantly share code, notes, and snippets.

@davidjenni
Created January 7, 2020 18:08
Show Gist options
  • Save davidjenni/7eb707e60316cdd97549b37ca95fbe93 to your computer and use it in GitHub Desktop.
Save davidjenni/7eb707e60316cdd97549b37ca95fbe93 to your computer and use it in GitHub Desktop.
CIDR to IP range conversion using PowerShell
# 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"
@mlhDevelopment
Copy link

great script. I'm using powershell 7 so I change the return to a custom object with named parameters:

return [PSCustomObject]@{
    Start = ([BitConverter]::GetBytes([Net.IPAddress]::HostToNetworkOrder($ipStart)) | ForEach-Object { $_ } ) -join '.'
    End = ([BitConverter]::GetBytes([Net.IPAddress]::HostToNetworkOrder($ipEnd)) | ForEach-Object { $_ } ) -join '.'
}

@tenielg
Copy link

tenielg commented Aug 28, 2024

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
   }

@mlhDevelopment
Copy link

I think the +1/-1 should be removed altogether. That's what I did in my fork after verifying.

@superivoo
Copy link

Thanks, Just what I needed ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment