functions/Get-IPCalc.ps1
<#
.SYNOPSIS Advanced IP subnet calculator that provides detailed network information. .DESCRIPTION IP Calculator for calculation IP Subnet. Provides comprehensive network information including binary representations, subnet boundaries, and advanced subnet manipulation methods. .PARAMETER CIDR Specifies the network in CIDR notation (e.g., "192.168.1.0/24") .PARAMETER IPAddress Specifies the IP address to analyze .PARAMETER Mask Specifies the subnet mask (e.g., "255.255.255.0") .PARAMETER PrefixLength Specifies the network prefix length (0-32) .PARAMETER WildCard Specifies the wildcard mask .EXAMPLE Get-IPCalc -CIDR 192.168.0.0/24 Shows complete subnet information including: IP : 192.168.0.0 Mask : 255.255.255.0 PrefixLength : 24 WildCard : 0.0.0.255 IPcount : 256 Subnet : 192.168.0.0 Broadcast : 192.168.0.255 CIDR : 192.168.0.0/24 ToDecimal : 3232235520 IPBin : 11000000.10101000.00000000.00000000 MaskBin : 11111111.11111111.11111111.00000000 SubnetBin : 11000000.10101000.00000000.00000000 BroadcastBin : 11000000.10101000.00000000.11111111 .EXAMPLE Get-IPCalc -IPAddress 192.168.3.0 -PrefixLength 23 Demonstrates calculation with IP address and prefix length, showing a larger subnet (512 IPs) .EXAMPLE (Get-IPCalc 192.168.99.58/30).GetIPArray() Returns all IP addresses in the specified subnet: 192.168.99.56 192.168.99.57 192.168.99.58 192.168.99.59 .EXAMPLE (Get-IPCalc 192.168.99.56/28).Compare('192.168.99.50') Demonstrates the Compare method to check if an IP belongs to a subnet .EXAMPLE (Get-IPCalc 192.168.0.0/25).Overlaps('192.168.0.0/27') Shows how to check for overlapping subnets .NOTES Advanced Methods Available: - Add(): Add IP addresses within the subnet - Compare(): Compare IP addresses within the subnet - Overlaps(): Check for overlapping subnets - GetIParray(): Get all IP addresses in the range - isLocal(): Check if IP is on local network - GetLocalRoute(): Get routing information for specific IPs #> Function Get-IPCalc { [CmdletBinding(DefaultParameterSetName = 'CIDR')] param( [Parameter(Mandatory = $true, ParameterSetName = 'CIDR', ValueFromPipelineByPropertyName = $true, Position = 0)] [ValidateScript({ $Array = ($_ -split '\\|\/'); ($Array[0] -as [IPAddress]).AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork -and [string[]](0..32) -contains $Array[1] })] [Alias('DestinationPrefix')] [string]$CIDR, [parameter(ParameterSetName = 'Mask')][parameter(ParameterSetName = ('PrefixLength'), ValueFromPipelineByPropertyName = $true)][parameter(ParameterSetName = ('WildCard'))] [ValidateScript({ ($_ -as [IPAddress]).AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork })] [Alias('IP')] [IPAddress]$IPAddress, [Parameter(Mandatory = $true, ParameterSetName = 'Mask')] [IPAddress]$Mask, [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'PrefixLength')] [ValidateRange(0, 32)] [int]$PrefixLength, [parameter(Mandatory = $true, ParameterSetName = 'WildCard')] [IPAddress]$WildCard ) if ($CIDR) { [IPAddress]$IPAddress = ($CIDR -split '\\|\/')[0] [int]$PrefixLength = ($CIDR -split '\\|\/')[1] [IPAddress]$Mask = [IPAddress]([string](4gb - ([System.Math]::Pow(2, (32 - $PrefixLength))))) } if ($PrefixLength -and !$Mask) { [IPAddress]$Mask = [IPAddress]([string](4gb - ([System.Math]::Pow(2, (32 - $PrefixLength))))) } if ($WildCard) { [IPAddress]$Mask = $WildCard.GetAddressBytes().ForEach({ 255 - $_ }) -join '.' } if (!$PrefixLength -and $Mask) { $PrefixLength = 32 - ($Mask.GetAddressBytes().ForEach({ [System.Math]::Log((256 - $_), 2) }) | Measure-Object -Sum).Sum } [int[]]$SplitIPAddress = $IPAddress.GetAddressBytes() [int64]$ToDecimal = $SplitIPAddress[0] * 16mb + $SplitIPAddress[1] * 64kb + $SplitIPAddress[2] * 256 + $SplitIPAddress[3] [int[]]$SplitMask = $Mask.GetAddressBytes() $IPBin = ($SplitIPAddress.ForEach({ [System.Convert]::ToString($_, 2).PadLeft(8, '0') })) -join '.' $MaskBin = ($SplitMask.ForEach({ [System.Convert]::ToString($_, 2).PadLeft(8, '0') })) -join '.' if ((($MaskBin -replace '\.').TrimStart('1').Contains('1')) -and (!$WildCard)) { Write-Warning 'Mask Length error, you can try put WildCard'; break } if (!$WildCard) { [IPAddress]$WildCard = $SplitMask.ForEach({ 255 - $_ }) -join '.' } if ($WildCard) { [int[]]$SplitWildCard = $WildCard.GetAddressBytes() } [IPAddress]$Subnet = $IPAddress.Address -band $Mask.Address [int[]]$SplitSubnet = $Subnet.GetAddressBytes() [string]$SubnetBin = $SplitSubnet.ForEach({ [System.Convert]::ToString($_, 2).PadLeft(8, '0') }) -join '.' [IPAddress]$Broadcast = @(0..3).ForEach({ [int]($SplitSubnet[$_]) + [int]($SplitWildCard[$_]) }) -join '.' [int[]]$SplitBroadcast = $Broadcast.GetAddressBytes() [string]$BroadcastBin = $SplitBroadcast.ForEach({ [System.Convert]::ToString($_, 2).PadLeft(8, '0') }) -join '.' [string]$CIDR = "$($Subnet.IPAddressToString)/$PrefixLength" [int64]$IPcount = [System.Math]::Pow(2, $(32 - $PrefixLength)) $Object = [pscustomobject][ordered]@{ IPAddress = $IPAddress.IPAddressToString Mask = $Mask.IPAddressToString PrefixLength = $PrefixLength WildCard = $WildCard.IPAddressToString IPcount = $IPcount Subnet = $Subnet Broadcast = $Broadcast CIDR = $CIDR ToDecimal = $ToDecimal IPBin = $IPBin MaskBin = $MaskBin SubnetBin = $SubnetBin BroadcastBin = $BroadcastBin PSTypeName = 'NetWork.IPCalcResult' } [string[]]$DefaultProperties = @('IPAddress', 'Mask', 'PrefixLength', 'WildCard', 'Subnet', 'Broadcast', 'CIDR', 'ToDecimal') Add-Member -InputObject $Object -MemberType AliasProperty -Name IP -Value IPAddress Add-Member -InputObject $Object -MemberType:ScriptMethod -Name Add -Value { param([int]$Add, [int]$PrefixLength = $This.PrefixLength) Get-IPCalc -IPAddress ([IPAddress]([String]$($This.ToDecimal + $Add))).IPAddressToString -PrefixLength $PrefixLength } Add-Member -InputObject $Object -MemberType:ScriptMethod -Name Compare -Value { param ([Parameter(Mandatory = $true)][IPAddress]$IP) $IPBin = -join (($IP)).GetAddressBytes().ForEach({ [System.Convert]::ToString($_, 2).PadLeft(8, '0') }) $SubnetBin = $This.SubnetBin.Replace('.', '') for ($i = 0; $i -lt $This.PrefixLength; $i += 1) { if ($IPBin[$i] -ne $SubnetBin[$i]) { return $false } } return $true } Add-Member -InputObject $Object -MemberType:ScriptMethod -Name Overlaps -Value { param ([Parameter(Mandatory = $true)][string]$CIDR = $This.CIDR) $Calc = Get-IPCalc -Cidr $CIDR $This.Compare($Calc.Subnet) -or $This.Compare($Calc.Broadcast) } Add-Member -InputObject $Object -MemberType:ScriptMethod -Name GetIParray -Value { $w = @($This.Subnet.GetAddressBytes()[0]..$This.Broadcast.GetAddressBytes()[0]) $x = @($This.Subnet.GetAddressBytes()[1]..$This.Broadcast.GetAddressBytes()[1]) $y = @($This.Subnet.GetAddressBytes()[2]..$This.Broadcast.GetAddressBytes()[2]) $z = @($This.Subnet.GetAddressBytes()[3]..$This.Broadcast.GetAddressBytes()[3]) $w.ForEach({ $wi = $_; $x.ForEach({ $xi = $_; $y.ForEach({ $yi = $_; $z.ForEach({ $zi = $_; $wi, $xi, $yi, $zi -join '.' }) }) }) }) } Add-Member -InputObject $Object -MemberType:ScriptMethod -Name isLocal -Value { param ([Parameter(Mandatory = $true)][IPAddress]$IP = $This.IPAddress) [bool](@(Get-NetIPAddress -AddressFamily IPv4 -AddressState Preferred).Where({ (Get-IPCalc -IPAddress $_.IPAddress -PrefixLength $_.PrefixLength).Compare($IP) }).Count) } Add-Member -InputObject $Object -MemberType:ScriptMethod -Name GetLocalRoute -Value { param ([Parameter(Mandatory = $true)][IPAddress]$IP = $This.IPAddress, [int]$Count = 1) @(Get-NetRoute -AddressFamily IPv4).Where({ (Get-IPCalc -CIDR $_.DestinationPrefix).Compare($IP) }) | Sort-Object -Property @{Expression = { (Get-IPCalc -CIDR $_.DestinationPrefix).PrefixLength } } -Descending | Select-Object -First $Count } Add-Member -InputObject $Object -MemberType:ScriptMethod -Force -Name ToString -Value { $This.CIDR } $PSPropertySet = New-Object -TypeName System.Management.Automation.PSPropertySet -ArgumentList @('DefaultDisplayPropertySet', $DefaultProperties) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]$PSPropertySet Add-Member -InputObject $Object -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers $Object } Function IsIpAddressInRange { <# .EXAMPLE IsIpAddressInRange '192.168.1.10' '192.168.1.0-192.168.1.100' True #> param( [string] $ipAddress, [string] $Range ) $arrRange = $Range.Split("-") [string] $fromAddress = $arrRange[0] [string] $toAddress = $arrRange[1] $ip = [system.net.ipaddress]::Parse($ipAddress).GetAddressBytes() [array]::Reverse($ip) $ip = [system.BitConverter]::ToUInt32($ip, 0) $from = [system.net.ipaddress]::Parse($fromAddress).GetAddressBytes() [array]::Reverse($from) $from = [system.BitConverter]::ToUInt32($from, 0) $to = [system.net.ipaddress]::Parse($toAddress).GetAddressBytes() [array]::Reverse($to) $to = [system.BitConverter]::ToUInt32($to, 0) $from -le $ip -and $ip -le $to } |