I needed a powershell script today with which i can check if two given IP addresses match or if a given IP address belongs to a subnet or if a smaller subnet belongs to a larger one (or vise vursa). I found a nice script written by Sava from http://www.padisetty.com/ which had part of the functionality i required so i took and modified it to suit my needs. Below you will be able to find the modified script i hope it helps somebody :). The script will return an array of two values, one to indicate true or false and the second the direction. The direction is important as you may want to compare values for a firewall and as such you want to fit one in the other in a particular direction.
Usage example:
- checkSubnet ‘10.185.255.128/26’ ‘10.165.255.166/32’
- checkSubnet ‘10.125.255.128’ ‘10.125.255.166′
- checkSubnet ‘10.140.20.0/21’ ‘10.140.20.0/27’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# Please note i took inspiration form www.padisetty.com # The function will check ip to ip, ip to subnet, subnet to ip or subnet to subnet belong to each other and return true or false and the direction of the check #//////////////////////////////////////////////////////////////////////// function checkSubnet ([string]$addr1, [string]$addr2) { # Separate the network address and lenght $network1, [int]$subnetlen1 = $addr1.Split('/') $network2, [int]$subnetlen2 = $addr2.Split('/') #Convert network address to binary [uint32] $unetwork1 = NetworkToBinary $network1 [uint32] $unetwork2 = NetworkToBinary $network2 #Check if subnet length exists and is less then 32(/32 is host, single ip so no calculation needed) if so convert to binary if($subnetlen1 -lt 32){ [uint32] $mask1 = SubToBinary $subnetlen1 } if($subnetlen2 -lt 32){ [uint32] $mask2 = SubToBinary $subnetlen2 } #Compare the results if($mask1 -and $mask2){ # If both inputs are subnets check which is smaller and check if it belongs in the larger one if($mask1 -lt $mask2){ return CheckSubnetToNetwork $unetwork1 $mask1 $unetwork2 }else{ return CheckNetworkToSubnet $unetwork2 $mask2 $unetwork1 } }ElseIf($mask1){ # If second input is address and first input is subnet check if it belongs return CheckSubnetToNetwork $unetwork1 $mask1 $unetwork2 }ElseIf($mask2){ # If first input is address and second input is subnet check if it belongs return CheckNetworkToSubnet $unetwork2 $mask2 $unetwork1 }Else{ # If both inputs are ip check if they match CheckNetworkToNetwork $unetwork1 $unetwork2 } } function CheckNetworkToSubnet ([uint32]$un2, [uint32]$ma2, [uint32]$un1) { $ReturnArray = "" | Select-Object -Property Condition,Direction if($un2 -eq ($ma2 -band $un1)){ $ReturnArray.Condition = $True $ReturnArray.Direction = "Addr1ToAddr2" return $ReturnArray }else{ $ReturnArray.Condition = $False $ReturnArray.Direction = "Addr1ToAddr2" return $ReturnArray } } function CheckSubnetToNetwork ([uint32]$un1, [uint32]$ma1, [uint32]$un2) { $ReturnArray = "" | Select-Object -Property Condition,Direction if($un1 -eq ($ma1 -band $un2)){ $ReturnArray.Condition = $True $ReturnArray.Direction = "Addr2ToAddr1" return $ReturnArray }else{ $ReturnArray.Condition = $False $ReturnArray.Direction = "Addr2ToAddr1" return $ReturnArray } } function CheckNetworkToNetwork ([uint32]$un1, [uint32]$un2) { $ReturnArray = "" | Select-Object -Property Condition,Direction if($un1 -eq $un2){ $ReturnArray.Condition = $True $ReturnArray.Direction = "Addr1ToAddr2" return $ReturnArray }else{ $ReturnArray.Condition = $False $ReturnArray.Direction = "Addr1ToAddr2" return $ReturnArray } } function SubToBinary ([int]$sub) { return ((-bnot [uint32]0) -shl (32 - $sub)) } function NetworkToBinary ($network) { $a = [uint32[]]$network.split('.') return ($a[0] -shl 24) + ($a[1] -shl 16) + ($a[2] -shl 8) + $a[3] } #//////////////////////////////////////////////////////////////////////// |
Excellent post, very forward thinking to use functions. I didn’t have to change a single bit when I plugged my script into this.
https://blogs.technet.microsoft.com/rspitz/2018/03/02/powershell-script-to-determine-if-an-ip-range-is-part-of-the-azure-datacenter-ip-range/
Thank you!
hi – Thanks very much for this function. This was perfect and fit-for-purpose where firewall rules are to be checked and validated
This is a great script, but I did notice one thing. If you enter a CIDR format that has additional data beyond the mask it doesn’t provide the correct output. For example
checkSubnet “10.0.20.32” “10.1.0.0/8” returns false although it is in the range. The unnecessary and ignored .1 in the second CIDR throws it off. I added some code to scrub the input and added it before the compare
#Fix if a valid but incorrect entry is used (example 10.1.0.0/8)
if ($unetwork1 -ne ($unetwork1 -band $mask1))
{
Write-Host “Mismatch between first argument address format and subnet mask, fixing” -ForegroundColor Red
$unetwork1 = ($unetwork1 -band $mask1)
}
if ($unetwork2 -ne ($unetwork2 -band $mask2))
{
Write-Host “Mismatch between second argument address format and subnet mask, fixing” -ForegroundColor Red
$unetwork2 = ($unetwork2 -band $mask2)
}
To fix my own fix, my code fails if you enter in a single IP or CIDR that represents a single IP, so I moved this code into the If statement above that so it only runs if the -lt 32 condition is true. That has seemed to fix it and I have ran it on hundreds of subnets
This saved me some time and effort. Thank you for sharing your excellent script.