Private/Get-SilkSubnetInfo.ps1
|
function Get-SilkSubnetInfo { <# .SYNOPSIS Subnet math for an IPv4 CIDR. Returns the network address, dotted mask and the first usable host. .DESCRIPTION Shared by Set-SilkData1Route and Get-SilkData1InverseRoute. Works on a byte array rather than shifting a uint32 so it behaves the same on 5.1 and 7. The address does not have to be the network address, a host address in the subnet works fine and gets normalized. .EXAMPLE Get-SilkSubnetInfo -subnet 10.10.0.130/28 #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $subnet ) $parts = $subnet.Trim() -split '/' if ($parts.Count -ne 2) { Write-Error "Subnet '$subnet' is not CIDR notation. Expecting something like 10.10.0.128/28" return } $prefix = 0 if (-not [int]::TryParse($parts[1], [ref]$prefix) -or $prefix -lt 0 -or $prefix -gt 32) { Write-Error "Prefix length '$($parts[1])' is not valid, must be 0-32" return } try { $ip = [System.Net.IPAddress]::Parse($parts[0]) } catch { Write-Error "'$($parts[0])' is not a valid IP address" return } if ($ip.AddressFamily -ne 'InterNetwork') { Write-Error "'$($parts[0])' is not IPv4" return } # mask one octet at a time. bits left for this octet, clamped to 0-8 $ipBytes = $ip.GetAddressBytes() $maskBytes = New-Object byte[] 4 $netBytes = New-Object byte[] 4 for ($i = 0; $i -lt 4; $i++) { $bits = [math]::Min(8, [math]::Max(0, $prefix - ($i * 8))) $maskBytes[$i] = [byte](256 - [math]::Pow(2, 8 - $bits)) $netBytes[$i] = [byte]($ipBytes[$i] -band $maskBytes[$i]) } # network + 1, with carry so a /31 or /32 doesnt roll off the end $firstBytes = $netBytes.Clone() for ($i = 3; $i -ge 0; $i--) { if ($firstBytes[$i] -lt 255) { $firstBytes[$i] = [byte]($firstBytes[$i] + 1) break } $firstBytes[$i] = [byte]0 } $network = ($netBytes | ForEach-Object { $_ }) -join '.' $mask = ($maskBytes | ForEach-Object { $_ }) -join '.' $first = ($firstBytes | ForEach-Object { $_ }) -join '.' $return = New-Object psobject $return | Add-Member -MemberType NoteProperty -Name Network -Value $network $return | Add-Member -MemberType NoteProperty -Name PrefixLength -Value $prefix $return | Add-Member -MemberType NoteProperty -Name Mask -Value $mask $return | Add-Member -MemberType NoteProperty -Name Cidr -Value "$network/$prefix" $return | Add-Member -MemberType NoteProperty -Name FirstUsable -Value $first return $return } |