PS Script: Match First 3 octets of IP address with IPArray

Requirement: I would like to copy large files to multiple VM using FTP. I have FTP with multiple IP Ranges with Class C Subnet. Ex.“10.10.10.10”,"10.11.10.10"“10.10.12.10”,“10.10.10.13” (All are Class C with subnet 255.255.255.

The script will be executed locally on each VM. so I want the script to match first 3 octets of assigned IP(few VM have multiple IP’s with different ranges too) and then pick the FTP IP from the list of IP address and set that as variable.

As per my knowledge, I created the IP array which contains all the FTP IP Address. Then I use Win32_NetworkAdapterConfiguration to get the list of IP address, Subnet, and Gateway. I put the Win32_NetworkAdapterConfiguration to the hash table so that I can use that for comparison.

Need help to compare hash table data and fetch the matched IP address from IP array and set that FTP IP as Variable.

Ex. If VM A have IP 10.10.12.25 then it should use 10.10.12.10 FTP IP.

I need to use Win32_NetworkAdapterConfiguration to make the script compatible with old operating systems running PS v2

$FTPIPs = @("10.10.10.10","10.11.10.10""10.10.12.10","10.10.10.13")
$AllIPs = @()
foreach ($adapter in (Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $env:COMPUTERNAME ))
        {
         $Prop = @{
                'IPAddress' = $adapter.IpAddress
                'SubnetMask' = $adapter.IPSubnet
                'DefaultGateway' = $adapter.DefaultIPGateway
         }      
$obj = New-Object -TypeName PSobject -Property $Prop
$AllIPs += $obj
        }

I did not get what you try to do and I do not see where you compare IP adresses in your code snippet but if you need to partially compare IP addresses you could simply split the IP addresses to their octets you could use the [IPADDRESS] type … something like this:

[IPADDRESS]$IP = ‘192.168.178.1’

$IP.GetAddressBytes()[0]
$IP.GetAddressBytes()[1]
$IP.GetAddressBytes()[2]
$IP.GetAddressBytes()[3]

Result:
192
168
178
1

But why match just the first 3 octets if you already know the FTP addresses?

$FTPIPs = @("10.10.10.10","10.11.10.10""10.10.12.10","10.10.10.13")
$AllIPs = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $env:COMPUTERNAME |
ForEach-Object {
    $Prop = @{
        'IPAddress' = $_.IpAddress | Where-Object {$_ -in $FTPIPs}
        'SubnetMask' = $_.IPSubnet
        'DefaultGateway' = $_.DefaultIPGateway
    }      
    New-Object -TypeName PSobject -Property $Prop
}

For that matter, since you know the IP addresses, I’m sure you also know the systems those IPs are on and you just need to use the right IP for the system that’s running the script based on how I read your original question.

Why not just use a hash table?

$FTPIPs = @{}
$FTPIPs['computer1']="10.10.10.10"
$FTPIPs['computer2']="10.11.10.10"
$FTPIPs['computer3']="10.10.12.10"
$FTPIPs['computer4']="10.10.10.13"

$FTPIP = $FTPIPs[$env:COMPUTERNAME]
$FTPIP

Hello Curtis,

Thanks for reply.

I know the FTP IP’s because it’s on single VM. I have 3rd party agent installed on all VM which will help me to deploy and execute the script on all VM. Something like 1000+ multiple domain join plus workgroup VM. I want entire traffic to be lan so same subnet needs to be used. Hence I want to discover and match the ip of VM from where the script will be executed with list of FTP IP’s because I will be adding all ip range addresses on FTP Server to make sure all traffic is lan.

Got ya,
How about just checking if the IPs are in the same network based on the mask?

Something like this:

$FTPIPs = @("10.10.10.10","10.11.10.10","10.10.12.10","10.10.10.13")
$Prop = @{
    'IPAddress' = '10.11.10.54'
    'SubnetMask' = '255.255.255.128'
    'DefaultGateway' = '10.11.10.1'
}
$LocalIP = New-Object -TypeName PSobject -Property $Prop

$FTPIPs |
ForEach-Object {
    If ((([IPAddress]$LocalIP.IPAddress).Address -band ([IPAddress]$LocalIP.SubnetMask).Address) -eq (([IPAddress]$_).Address -band ([IPAddress]$LocalIP.SubnetMask).Address)) {
        "$_ is in the same subnet as $($LocalIP.IPAddress)"
    }
}

Hello Curtis,

I thought same but the problem is all 20 IP range that I have belongs Class C hence Subnet will be same for all VM i.e. 255.255.255.0

The only factor we can find between FTP IP’s and VM IP is first 3 octets will be same and last octet will be unique. Hence I will have build condition to match first 3 octets of FTP IP’s with VM IP.

Hey Amol,
That is fine that they all have the same Subnet Mast, but they would still belong to different subnets.

The thing is based on your example "$FTPIPs = @(“10.10.10.10”,“10.11.10.10"“10.10.12.10”,“10.10.10.13”)”. If you have a subnet mast of 255.255.255.0 then you have 2 FTP servers in 1 subnet, and 2 other FTP servers in their own subnets.

10.10.10.10 and 10.10.10.13 are in the same subnet
10.11.10.10 is in it’s own
10.10.12.10 is in it’s own

IE.

"10.10.10.54", "10.11.10.251", "10.10.12.68", "10.13.10.68" |
ForEach-Object {
    [pscustomobject]@{
        'IP' = $_
        'SameSubNetAs10.10.10.10' = (([IPAddress]$_).Address -band ([IPAddress]'255.255.255.0').Address) -eq (([IPAddress]'10.10.10.10').Address -band ([IPAddress]'255.255.255.0').Address)
        'SameSubNetAs10.11.10.10' = (([IPAddress]$_).Address -band ([IPAddress]'255.255.255.0').Address) -eq (([IPAddress]'10.11.10.10').Address -band ([IPAddress]'255.255.255.0').Address)
        'SameSubNetAs10.10.12.10' = (([IPAddress]$_).Address -band ([IPAddress]'255.255.255.0').Address) -eq (([IPAddress]'10.10.12.10').Address -band ([IPAddress]'255.255.255.0').Address)
        'SameSubNetAs10.10.10.13' = (([IPAddress]$_).Address -band ([IPAddress]'255.255.255.0').Address) -eq (([IPAddress]'10.10.10.13').Address -band ([IPAddress]'255.255.255.0').Address)
    }
}

Results

IP           SameSubNetAs10.10.10.10 SameSubNetAs10.11.10.10 SameSubNetAs10.10.12.10 SameSubNetAs10.10.10.13
--           ----------------------- ----------------------- ----------------------- -----------------------
10.10.10.54                     True                   False                   False                    True
10.11.10.251                   False                    True                   False                   False
10.10.12.68                    False                   False                    True                   False
10.13.10.68                    False                   False                   False                   False

If you are intent on matching the first there octets, then you can use Olaf’s suggestion, but this is less flexible as you will only be able to use this method if your Subnet Mask is always and forever “255.255.255.0” It will not work for other masks such as “255.255.128.0” or “255.255.255.128” wheres as the method of using the subnet to compare them would account for these variances.

Example using Olaf’s suggestion:

$FTPIPs = @("10.10.10.10","10.11.10.10","10.10.12.10","10.10.10.13")
[IPADDRESS]$IP = '10.10.10.53'

$FTPIPs |
ForEach-Object {
    $FTPServerOctets = ([IPADDRESS]$_).GetAddressBytes()
    $IPOctets = $ip.GetAddressBytes()
    
    "Octet 1: $($FTPServerOctets[0]) : $($IPOctets[0])"
    "Octet 2: $($FTPServerOctets[1]) : $($IPOctets[1])"
    "Octet 3: $($FTPServerOctets[2]) : $($IPOctets[2])"
    "Octet 4: $($FTPServerOctets[3]) : $($IPOctets[3])"

    If ("$($FTPServerOctets[0]):$($FTPServerOctets[1]):$($FTPServerOctets[2])" -eq "$($IPOctets[0]):$($IPOctets[1]):$($IPOctets[2])") {
        "First three octets match: $($ip.IPAddressToString) : $_"
    } Else {
        "No match: $($ip.IPAddressToString) : $_"
    }
}

Results:

Octet 1: 10 : 10
Octet 2: 10 : 10
Octet 3: 10 : 10
Octet 4: 10 : 53
First three octets match: 10.10.10.53 : 10.10.10.10
Octet 1: 10 : 10
Octet 2: 11 : 10
Octet 3: 10 : 10
Octet 4: 10 : 53
No match: 10.10.10.53 : 10.11.10.10
Octet 1: 10 : 10
Octet 2: 10 : 10
Octet 3: 12 : 10
Octet 4: 10 : 53
No match: 10.10.10.53 : 10.10.12.10
Octet 1: 10 : 10
Octet 2: 10 : 10
Octet 3: 10 : 10
Octet 4: 13 : 53
First three octets match: 10.10.10.53 : 10.10.10.13

Thanks, Curtis & Olaf.

Based on the examples of Subnet provided by Curtis I thinks I should go with below option as its clean approach but as mentioned My subnet will always remain 255.255.255.0 so I will also see if I need to use Olaf option too.

$FTPIPs = @("10.10.10.10","10.11.10.10","10.10.12.10","10.10.10.13")
$Prop = @{
    'IPAddress' = '10.11.10.54'
    'SubnetMask' = '255.255.255.128'
    'DefaultGateway' = '10.11.10.1'
}
$LocalIP = New-Object -TypeName PSobject -Property $Prop

$FTPIPs |
ForEach-Object {
    If ((([IPAddress]$LocalIP.IPAddress).Address -band ([IPAddress]$LocalIP.SubnetMask).Address) -eq (([IPAddress]$_).Address -band ([IPAddress]$LocalIP.SubnetMask).Address)) {
        "$_ is in the same subnet as $($LocalIP.IPAddress)"
    }
}