Let's say we wanted to query Active Directory and print out a report of all of our users, and their last logon time. That seems like a pretty normal task for a Powershell script. It'd probably be short and easy to read, at least if it were written by a normal person.
Alice sends us one that wasn't. She's already done us a favor, as she writes: "Code cleaned up and indented for the whitespace-missing-impaired."
#####################################
# lists accounts and selected attributes alphabetically
#####################################
foreach( $letter in "a", "b", "c"......"z")
{
$strfilter = $letter + "*"
$objdomain = New-object System.DirectoryServices.DirectoryEntry
$objSearcher = New-object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objdomain
$objSearcher.Filter = $strFilter
$objSearcher.PropertiesToLoad.Add("name");
$colResults = $objSearcher.FindAll()
foreach($result in $colResults)
{
$name = $result.Properties.Name
$searcher = New-Object DirectoryServices.DirectorySearcher([adsi]"")
$searcher.filter "(&(objectCategory=User)(sAMAccountName=$name))"
$users = searcher.FindAll()
foreach($user in $users)
{
Write-Output $user.properties.item("name") + "," + $user.properties.item("lastLogon")
}
}
}
This accomplishes sorting alphabetically by iterating across the alphabet. Which, I suspect, isn't going to actually get them in alphabetical order; it makes sure that albert and alice appear before bob, but doesn't enforce that albert must come before alice.
In any case, we iterate across the alphabet, and then create a searcher that finds a*, then b*, etc. We explicitly tell the searcher that the only property we care about is the name field, so that we don't load unnecessary fields, like the ones we want to report on.
We then iterate across the list of names, construct a new searcher, and search for the account with the username we fetched. That lets us get all of the fields we need, including the ones we aren't going to use.
Now, we search for a username, so we expect there to only be one result, but since searcher.FindAll() returns an array, we "need" to write a loop to iterate across the array of one, which is clearly a better choice than using the FindOne function.
As it usually goes with these sorts of things, one of the managers absolutely adores the fact that they have an easy way to generate a CSV file that they can manipulate in Excel, so this terrible script is "mission critical".