Sort a list of computers by domain first and then name, using PowerShell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

If you have a list of computers from different domains, you might want to sort them by domain first and then the computer name. Here is how.

The method I use, is simply stripping off the host name - which I define as anything before the first dot (plus the first dot, but that doesn't really matter) - sorting by what's left, which is the domain, then sorting secondarily on just the host name, which I conveniently get by using the System.String class' Split() method on a period to extract what's before the first period in the string. It works. Actually, just using "Expression = { $_ }" will work too for the secondary sort criteria. That's essentially what I do in the example with a property.

This will work with PowerShell version 2 and up.




Sorting computer names when you have strings

I put a bunch of fake hosts and domains in an array, and then demonstrate how to sort it by domain first and then by host name / computer name (anything real under these domains is unknown to me!).

Sort-computers-by-domain-and-name-example1.png

The same example as text for pasty delightfulness:

PS C:\> $Servers = @('host05.aaa.com', 'hostX.zzz.com', 'host10.bbb.com', 'host08.bbb.com',
    'host06.ccc.com', 'host99.aaa.com', 'host00.ccc.com', 'host01.aaa.com')
$Servers | Sort @{ Expression = { $_ -replace '^[^.]+\.' } }, @{ Expression = { $_.Split('.')[0] } }

host01.aaa.com
host05.aaa.com
host99.aaa.com
host08.bbb.com
host10.bbb.com
host00.ccc.com
host06.ccc.com
hostX.zzz.com

Sorting computer names when you have an object with a string property

When you use Get-ADComputer, you get a DNSHostName property back. Here I use the same list of servers as in the example above, create custom PS objects (in a v2-compatible way) that have a DNSHostName as a string property, and then sort by domain and name. The sorting is actually easier, or at least less typing, this way.

Sort-computers-by-domain-and-name-example2.png

And again as text, for pasting, and for the visually impaired:

PS C:\> $ServerObj = $Servers | foreach {
    New-Object PSObject -Property @{
        DNSHostName = $_
        #ComputerName = $_.Split('.')[0]
    }
}

$ServerObj | Sort @{ Expression = { $_.DNSHostName -replace '^[^.]+\.' } }, DNSHostName |
    Format-Table -AutoSize

DNSHostName   
-----------   
host01.aaa.com
host05.aaa.com
host99.aaa.com
host08.bbb.com
host10.bbb.com
host00.ccc.com
host06.ccc.com
hostX.zzz.com 

Sorting computer names with numbers zero-padded

What if some despicable non-programmer decided to use the nomenclature "server1", "server2", "server3", etc. without padding with zeroes? Now your sorting is all whacked with 1, 10, 11, 12 ... 19, 2, 20, 21, 22 ... and so on.

Me to the rescue! I even handle multiple levels of nesting in non-zero-padded numbers. By the way, that will also work for IPv4 addresses, if you modify it slightly (run against entire string by removing the ".Split()"), as an added bonus.

PS C:\> $Servers = @('host5.aaa.com', 'host00.zzz.com', 'host11a2.aaa.com', 'host11a11.aaa.com',
    'host11a3.aaa.com', 'host11a10.aaa.com', 
    'host11.aaa.com', 'host1.aaa.com', 'host10.aaa.com', 'host2.aaa.com')

$Servers | Sort @{ Expression = { $_ -replace '^[^.]+\.' } },
    @{ Expression = { [regex]::Replace($_.Split('.')[0], '(\d+)', { '{0:D16}' -f [int] $args[0].Value }) } },
    @{ Expression = { $_ } }

host1.aaa.com
host2.aaa.com
host5.aaa.com
host10.aaa.com
host11.aaa.com
host11a2.aaa.com
host11a3.aaa.com
host11a10.aaa.com
host11a11.aaa.com
host00.zzz.com