Reputation: 1904
I have been developing VM provision script. My question is : I have here-string like below. now , I want to add route
based on ip address range. I am using CSV file with BACKUPIP
column.
if an BACKUPIP is in range 10.10.104.1
to 10.10.107.254
it will work route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
if an BACKUPIP is in range 10.10.180.1
to 10.10.185.254
it will work route add yy.yy.yy.yy mask 255.255.255.0 yy.yy.yy.yy -p
Here is my script:
Import-Csv -Path .\vm.csv -UseCulture -PipelineVariable row |
ForEach-Object -Process {
# Create the VM, store result in $vm
if($($row.IP) -eq '???'){
route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
}
else{
route add yy.yy.yy.yy mask 255.255.255.0 yy.yy.yy.yy -p
}
}
LAST UPDATE :
$rangeFrom104 = '10.10.104.1'
$rangeTo107 = '10.10.107.254'
$rangeFrom180 = '10.10.180.1'
$rangeTo185 = '10.10.185.254'
if (([version]$rangeFrom104) -lt ([version]$($row.IP)) -and ([version]$($row.IP)) -lt ([version]$rangeTo107) )
{
route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
}
elseif (([version]$rangeFrom180) -lt ([version]$($row.IP)) -and ([version]$($row.IP)) -lt ([version]$rangeTo185) )
{
route add yy.yy.yy.yy mask 255.255.255.0 yy.yy.yy.yy -p
}
Upvotes: 0
Views: 987
Reputation: 23623
There exists a IPAddress
class in .Net:
$MyIPAddress = [System.Net.IPAddress]'10.10.105.7'
$rangeFrom104 = [System.Net.IPAddress]'10.10.104.1'
$rangeTo107 = [System.Net.IPAddress]'10.10.107.254'
If ($rangeFrom104.Address -lt $MyIPAddress.Address -and $MyIPAddress.Address -lt $rangeTo107.Address) {
# route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
}
As @Theo commented, the Address
property is obsolete:
This property has been deprecated. It is address family dependent.
Please use IPAddress.Equals method to perform comparisons.
I guess this is due to compliance with IPv6 (but I presume that the property won't easily cease to exist as that would probably break some legacy programs). Anyways, that doesn't mean that the whole [System.Net.IPAddress]
class is deprecated. Meaning that you might also use the GetAddressBytes
method which I think better than a custom function or relying on a (smart! [version]
) type but also are both limited to IPv4 (~4 bytes).
With using the GetAddressBytes
method, you might simple convert the bytes to a hexadecimal string, which format is comparable (e.g. '10' -gt '0A'
) as long as the byte arrays are of the same size (e.g. both IPv4):
function Convert-IPAddressToHexadecimal ([Net.IPAddress]$IPAddress, [Switch]$IPv6) {
If ($IPv6) {$IPAddress = $IPAddress.MapToIPv6()}
[BitConverter]::ToString($IPAddress.GetAddressBytes())
}; Set-Alias IP2Hex Convert-IPAddressToHexadecimal
$MyIPAddress = IP2Hex '10.10.105.7' # 0A-0A-69-07
$rangeFrom104 = IP2Hex '10.10.104.1' # 0A-0A-68-01
$rangeTo107 = IP2Hex '10.10.107.254' # 0A-0A-6B-FE
If ($rangeFrom104 -lt $MyIPAddress -and $MyIPAddress -lt $rangeTo107) {
# route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
}
If you do need to make your script IPv6 compliant and comparing IP addresses to both IPv4 ranges and IPv6 ranges, you might consider to map all IP addresses to an IPv6 address: using: $MyIPAddress.MapToIPv6().GetAddressBytes()
(the -IPv6
switch):
IP2Hex -IPv6 '10.10.105.7' # 00-00-00-00-00-00-00-00-00-00-FF-FF-0A-0A-69-07
Update 2020-09-06:
It is unclear whether the Address
property is really obsolete. See: Avoid byte[] allocations once IPAddress.Address is back #18966.
Anyhow, there is a pitfall in using the Address
property for comparison as it appears that the address is stored as Big-Endian read from memory as Little-Endian format, see: System.Net.IPAddress returning weird addresses, causing the last byte in 10.10.104.1
(1
) to become most significant.
This means that comparing the Address
property might give an incorrect result if there are differences between multiple bytes in the concerned IP Addressed:
([IPAddress]'0.0.0.1').Address -lt ([IPAddress]'0.0.1.0').Address
False
Upvotes: 0
Reputation: 61028
Really like the [Version]
approach Lee_Dailey suggested.
Here's another approach that converts the IP addresses to their numeric values:
function Convert-IPv4ToDecimal ([string]$IpAddress){
# helper function to return the numeric value (uint32) of a dotted IP
# address string used for testing if an IP address is in range.
$n = [uint32[]]$IpAddress.Split('.')
# or use: $n = [uint32[]]([IpAddress]$IpAddress).GetAddressBytes()
# to get the obsolete property ([IpAddress]$IpAddress).Address
# you need to do the math in reversed order.
# return [uint32] ($n[3] -shl 24) + ($n[2] -shl 16) + ($n[1] -shl 8) + $n[0]
# for comparing different ranges as in this question, do not reverse the byte order
return [uint32] ($n[0] -shl 24) + ($n[1] -shl 16) + ($n[2] -shl 8) + $n[3]
}
$startRange1 = Convert-IPv4ToDecimal '172.25.104.1'
$endRange1 = Convert-IPv4ToDecimal '172.25.107.254'
$startRange2 = Convert-IPv4ToDecimal '172.25.112.1'
$endRange2 = Convert-IPv4ToDecimal '172.25.115.254'
Import-Csv -Path .\vm.csv -UseCulture | ForEach-Object {
# Create the VM, store result in $vm
# convert the .BACKUPIP to numeric value
$backupIp = Convert-IPv4ToDecimal $_.BACKUPIP
# test the IP range
if ($backupIp -ge $startRange1 -and $backupIp -le $endRange1) {
Write-Host "BACKUPIP '$($_.BACKUPIP)' is in Range 1"
route add xx.xx.xx.xx mask 255.255.255.0 xx.xx.xx.xx -p
}
elseif ($backupIp -ge $startRange2 -and $backupIp -le $endRange2) {
Write-Host "BACKUPIP '$($_.BACKUPIP)' is in Range 2"
route add yy.yy.yy.yy mask 255.255.255.0 yy.yy.yy.yy -p
}
else {
Write-Warning "No range defined for IP address '$($_.BACKUPIP)'"
}
}
Upvotes: 2