Skip to content

Instantly share code, notes, and snippets.

@aschmidt75
Created November 22, 2023 08:13
Show Gist options
  • Save aschmidt75/36dc929e9b5752c63c820b16804ee03f to your computer and use it in GitHub Desktop.
Save aschmidt75/36dc929e9b5752c63c820b16804ee03f to your computer and use it in GitHub Desktop.
Powershell ipcalc cidrsubnet helper
Function Convert-IpAddressStringToBinString {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$IpAddress
)
$IpAddressFullBin = ""
foreach ($octet in $IPAddress.Split(".")) {
# make sure this is a valid byte octet
$v = [convert]::ToInt32($octet)
if ( ($v -lt 0) -or ($v -gt 255)) {
throw "Invalid ip address octet"
}
$s = [convert]::ToString($octet, 2)
$IpAddressFullBin += $s.PadLeft(8, "0")
}
$IpAddressFullBin
}
Function Convert-IpAddressBinStringToString {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$IpAddressBinString
)
@( 0, 8, 16, 24 ) | ForEach-Object {
$o = $IpAddressBinString.substring($_, 8)
"{0}" -f [convert]::ToInt32($o,2)
} | Join-String -Separator "."
}
Function Test-CidrValid {
<#
.SYNOPSIS
Checks if a given CIDR string is valid
#>
return $false
}
Function Measure-Cidr {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$Prefix,
[Parameter(Mandatory=$true)]
[byte]$NewBits
)
$m = $Prefix -match "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}$"
if (-not $m) {
throw "Prefix not a valid CIDR"
}
$s = $Prefix.split("/")
$IpCidr = $s[0]
$NetmaskBits = [convert]::ToUint16($s[1])
if ($NetmaskBits -gt 32) {
throw "Prefix not a valid CIDR, invalid netmask"
}
if ($NewBits -gt 32) {
throw "NewBits must be <= 32"
}
if ($NewBits -lt $NetMaskBits) {
throw "NewBits must be larger that netmask of prefix"
}
$d = [math]::pow(2, $NewBits - $NetmaskBits)
$res = New-Object PSCustomObject @{
Prefix = $Prefix
IP = $IpCidr
NetmaskBits = $NetmaskBits
NumberOfNetworks = $d
}
$res
}
Function Get-CidrSubnets {
<#
.SYNPOSIS
.EXAMPLE
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$Prefix,
[Parameter(Mandatory=$true)]
[byte]$NewBits
)
$m = Measure-Cidr -Prefix $Prefix -NewBits $NewBits
for ($i = 0; $i -lt $m.NumberOfNetworks; $i++) {
Split-CidrSubnet -Prefix $Prefix -NewBits $NewBits -NetNum $i
}
}
Function Split-CidrSubnet {
<#
.EXAMPLE
> Update-CidrSubnet -Prefix "192.168.10.0/24" -NewBits 26 -NetNum 3
192.168.10.192
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$Prefix,
[Parameter(Mandatory=$true)]
[byte]$NewBits,
[Parameter(Mandatory=$true)]
[byte]$NetNum
)
$m = Measure-Cidr -Prefix $Prefix -NewBits $NewBits
$f = Convert-IpAddressStringToBinString $m.IP
# given the $NewBits parameter, determine the size of the new bits
# begin patched in. bin-format the $NetNum to the length of bits to replace
$d = $NewBits - $m.NetmaskBits
Write-Verbose ("d: {0}" -f $d)
$maxNets = $m.NumberOfNetworks
Write-Verbose ("NetNum: {0}, maxNets: {1}" -f $NetNum, $MaxNets)
if ($NetNum -ge $maxNets) {
throw ("NetNum must be <={0}" -f $maxNets)
}
$patch = ("{0}" -f [convert]::ToString($NetNum,2)).PadLeft($d,"0")
if ($d -eq 0) {
# if the same subnet length is requested, the patch is empty
$patch = ""
}
Write-Verbose ("f: {0}" -f $f)
Write-Verbose ("patch: {0}" -f $patch)
# combine the old net-part, patch and rest into new bitmask
$fPatched = $f.substring(0,$m.NetMaskBits) + $patch + $f.substring($NewBits, 32-$NewBits)
Write-Verbose ("Patch: {0} l:{1}" -f $fPatched, $fPatched.Length)
if ($fPatched.Length -ne 32) {
throw "Internal error"
}
# convert bitmask back into octet IP string
$result = Convert-IpAddressBinStringToString $fPatched
Write-Verbose ("RES: {0}" -f $result)
$result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment