Skip to content

Instantly share code, notes, and snippets.

@davidjenni
Created January 7, 2020 18:08
Show Gist options
  • Select an option

  • Save davidjenni/7eb707e60316cdd97549b37ca95fbe93 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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

@superivoo
Copy link
Copy Markdown

Thanks, Just what I needed ;-)

@andreandradearke
Copy link
Copy Markdown

andreandradearke commented Apr 10, 2025

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

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