Powershell – Sort-Objects, list of IP Addresses

ipv4powershellwindows-server-2012

I've got a /20 network and I want to know all used IP Addresses and their attributes like the MAC, the name and the description plus all free addresses between the used ones so that I got a long list where I can see if the address is taken or not.
Luckily I got a Server2012 so that I can use the CMDLets of Microsoft.
My aproach was to generate all possible addresses.
At the end I want a list which looks like smth like this:

IP, Mac, Name, Comment
19.0.0.0, 00:00:11:11:11:01, TestUser_1, This is the 1st Testuser
. (here are some used and some free)
.
19.0.2.45 (this one is free)
.
19.0.6.3 (this one is free, too)
19.0.11.201, 11:22:33:44:55:66, TestUser_N, This is just another comment

Sampe Code:

$x=0
$y=0
$ipstring = "19.0."
for ($i=$x;$i -le 15; $i++)
{
   for ($j=$y;$j -le 255;$j++)
   {
      $gesIP = $ipstring+"$i"+"."+"$j"
   }
}

The code above creates addresses between 19.0.0.0 to 19.0.15.255

Now I need to get my used addresses:

$usedAddresses = Get-DhcpServerv4Reservation -ComputerName $env:computername -ScopeId ((Get-DhcpServerv4Scope -ComputerName $env:computername).IPAddress.IPAddressToString)

In order of looking witch addresses are free I was thinking about to compare the addresses. I wasn't quite sure if the lists of objects are sorted. So I tried to sort them using the following algorithm:

$IP_sort = $IPv4_res  | Sort-Object {"{0:d3}.{1:d3}.{2:d3}.{3:d3}" -f @([int[]]$_.IPAddress.IPAddressToString.split('.'))}

After that I saved 'em

foreach ($ine in $IP_sort)
{
write-output ("{0}  {1}  {2}  {3}" -f ($ine).IPAddress.IPAddressToString, ($ine).ClientId, ($ine).Description, ($ine).Name) | ac EnterPlaceAndTextfileHere
}

Now I got 2 sorted lists where I just need to compare each other. The first list contains all addresses, the second contains only the used addresses.

Now I need to compare those two lists. I tried to manage it like that:

if ($ges_IP -eq $IP_sort[$k].IPAddress.IPAddressToString)
{
  write-output ("{0}  {1}  {2}  {3}" -f ($IPv4_res[$k]).IPAddress.IPAddressToString, ($IPv4_res[$k]).ClientId, ($IPv4_res[$k]).Name, ($IPv4_res[$k]).Description) | ac EnterPlaceAndTextfileHere
}
else
{
   $ges_IP | ac EnterPlaceAndTextfileHere
}        

Now I got one big list which would be sorted – hopefully.
But unfortunaltey I got some errors. Some addresses does not match the other attributes and some adresses are not in the correct order. I was wondering why… Is my code wrong? Do I think too complicated or does powershell manage to place this much addresses at the wrong order sometimes and it "just happens" sometime?

Best Answer

When using Sort-Object you are sorting the IP address as it was a string.

Consider:

19.0.9.234
19.0.15.5

When the example is sorted ascending as a string, 19.0.15.5 is ordered before 19.0.9.234.

While 15 is bigger then 9, when a string is sorted only characters in the same string position are considered, I.e. 1 vs 9.

One solution would be to pad the IP octets with 0, there by make the strings the same length and lining the octets up. I.e. 015, 009.

You could do this with Sort-Object as a calculated property or before your store each of your source data sets.

I.e.

Sort-Object -Property @{ Expression = { [String]::Join('.',  $_.IPAddress.IPAddressToString.Split('.').PadLeft('0', 3)); } }

Hope that helps.