Mapping IP Addresses to Active Directory Sites and Subnets

In Active Directory we use sites to tell a client which Domain Controllers to use from a physical location, this ensures that clients connect to the nearest DC and avoids unneeded latency and traffic.

I was working with a customer last week and when looking at Service Map for a specific DC we noticed some clients are not in the same subnet as the server. Not a best-case scenario. We were getting around 2000 different clients from at least 100s of subnets, so pin pointing where each client is coming from needed some scripting.

Using Kusto we exported the list of devices connecting to this specific DC over port 389, the result was the below CSV

We then used PowerShell to get a list of all the subnets in the domain (which is a little more than 600) and the site for each of them. I used Excel’s Autofill feature to quickly extract the site name in the below table,

Now we wanted to generate a table that shows each of the IP Addresses and which subnet / AD site it belongs too, not an easy job for VLOOKUP.

Fortunately, PowerShell support IP Address types and bitwise arithmetic operators. This makes it easy to check if an IP Address belongs to a subnet.

For example, take the IP Address 192.168.1.66 and the subnet 192.168.1.0/24 If we look at them in binary we see the following table, the bold part represents the mask bits (or subnet mask).

DecimalBinary

192.168.1.66

11000000101010000000000101000010

192.168.1.0

11000000101010000000000100000000
01000111 01100101 01100101 01101011 00100000 01000001 01101100 01100101 01110010 01110100

To check if 192.168.1.66 belongs to 192.168.1.0/24 we can check if first 24 binary numbers are the same (which they are!)

(([IPAddress]"192.168.1.66").Address -band ([IPAddress]"255.255.255.0").Address) -eq ([IPAddress]"192.168.1.0").Address

This will return $true.

Now let’s wrap it all in a loop to cover all IPs and Subnets, (See comments for hints!)

#Import sites CSV and calculate some properties

$Subnets = Import-Csv -Path C:\temp\sites.csv
$Subnets | ForEach-Object {
    $_ | Add-Member -MemberType NoteProperty -Name "SiteName" -Value (($_.site -split ",")[0] -replace "CN=", "")
    $_ | Add-Member -MemberType NoteProperty -Name "SubnetID" -Value ([IPAddress](($_.Name -split "/")[0]))
    $_ | Add-Member -MemberType NoteProperty -Name "SubnetMask" -Value ([IPAddress]"$([system.convert]::ToInt64(("1"*[int](($_.Name -split "/")[1])).PadRight(32,"0"),2))")
}


#Import Computers CSV and calculate some properties

$Computers = Import-Csv -Path "C:\temp\Computers.csv"
foreach ($Computer in $Computers) {
    $IPAddress = [IPAddress] $Computer.SourceIp
    $Computer | Add-Member -MemberType NoteProperty -Name "Sites" -Value @()
    $Computer | Add-Member -MemberType NoteProperty -Name "SitesString" -Value ""
    $Computer | Add-Member -MemberType NoteProperty -Name "Subnets" -Value @()
    $Computer | Add-Member -MemberType NoteProperty -Name "SubnetsString" -Value ""
    
    #See if the computer's IP Address belongs to any subnet(s) or site(s)
    foreach ($Subnet in $Subnets) {
        if (($IPAddress.Address -band $Subnet.SubnetMask.Address) -eq $Subnet.SubnetID.Address) {
            $Computer.Sites += $Subnet.SiteName
            $Computer.Subnets += $Subnet.Name
        }
    }
    
    #Convert the arrays to strings becuase that is easier to export to CSV
    $Computer.SitesString = $Computer.Sites -join "," 
    $Computer.SubnetsString = $Computer.Subnets -join ","
}  
$Computers | ogv

The result is a table that shows each IP and the matching sites and subnets, (Can you tell which version of PowerShell this is?)

The results showed a lot of IPs without a subnet, and many that belongs to more than one! Time to do some cleanup, but that will be our next post!

Cheers!

Authors

One thought on “Mapping IP Addresses to Active Directory Sites and Subnets