Searching Active Directory with PowerShell

Microsoft uses thousands of employees from various vendor companies. The other day I wanted to get a list of the names and e-mail addresses of some of these vendor employees. I decided that I didn’t want to work with COM/ADSI and that C# was slight overkill for such a relatively simple (or so I thought at first) task. I discovered that virtually all of the examples I found on the Web of how to search AD using PowerShell had significant errors. So I put together my own short PowerShell script. The script begins:
$target = "(&(objectCategory=User)(company=*Acme*))"
$root = new-object directoryServices.directoryEntry
$seeker = new-object directoryServices.directorySearcher
$seeker.searchRoot = $root
$seeker.SearchScope = "Subtree"
I set up a search filter for all AD users who have a Company attribute that contains ‘Acme’ (the * characters are wildcards). Then I instantiate a DirectoryEntry object from the System.DirectoryServices namespace, and a DirectorySearcher object to actually perform the search. I specify to begin searching at the root of the Active Directory hierarchy, and to search the entire tree. My script continues:
$seeker.serverTimeLimit = -1
$seeker.clientTimeout = -1
$seeker.filter = $target
$seeker.pageSize = 10
The -1 arguments mean "do not ever timeout". The PageSize argument is important. Because the Microsoft AD is so huge, a PageSize value tells the DirectorySearcher object to buffer 10 results at a time until finished. Now I can execute the search:
$colProplist = "name", "mail"
foreach ($i in $colPropList){
  $seeker.PropertiesToLoad.Add($i) | out-null
$$resultsCollection = $seeker.findAll()
Here I say to fetch just user’s name and mail properties, and then I search using the FindAll() method. Now I can display results. This is the point where all the existing examples I found glossed over what is happening. Consider my code:
$resultsCollection = $seeker.findAll()
foreach ($result in $resultsCollection) {   
  $propertiesCollection = $result.Properties
  $mailValues = $propertiesCollection.mail  
  $mailString = $mailValues.Item(0)         
  $mailString += ";"
  write-output $mailString # use write-output so can redirect to file
This part is actually quite tricky. The FindAll() method returns a SearchResultCollection collection type. And then in my foreach loop, each $result is a complex SearchResult type. The ‘Properties’ property returns a ResultPropertyCollection collection type. Then I grab just the ‘mail’ property but in fact this property is also a collection of type ResultPropertyValueCollection! Finally the Item(0) property is the actual String type value of the user’s e-mail address. I could use a similar pattern to get the users names:
$nameValues = $  
$nameString = $nameValues.Item(0)
Anyway, working with AD is somewhat more tricky than I expected.
This entry was posted in Software Test Automation. Bookmark the permalink.