Last time, we started looking at the Active Directory Searcher object and how to find a single user object. If you missed it, take a moment to get caught up.

If you recall, I created a simple searcher.



1 2 $searcher = New-Object system . DirectoryServices . DirectorySearcher $searcher . filter = "samaccountname=jeff"



My Active Directory (AD) domain is not especially large, so the query does not take long to run. However, you will want to fine tune your search to be as specific and limited as possible. We will look at some filtering techniques later. Right now, I want to focus on search scope by discussing how much AD you will need to search.

When you create a search object, it defaults to the domain root for the current logged on user.

The Searcher Search Root (Image Credit: Jeff Hicks)

When I invoked the FindOne() method, it searched the entire domain structure. That may be perfectly acceptable if you have no idea where the object is located. In my case, I know that all active user accounts are under the Employees organizational unit. I will need to know the distinguished name, and assuming that I do, I can reposition my search.



1 $searcher . SearchRoot = "LDAP://ou=employees,dc=globomantics,dc=local"



Now the search runs very quickly.

Searching For an Object (Image Credit: Jeff Hicks)

This search took 27ms and it took 35ms when searching the entire domain. Sure, that is hardly earth shattering but this will make a difference when searching for many objects. If you have a large domain, it will make a bigger difference.

Another tweak you can make is to modify the set of object properties that get returned. If you recall from last time, the user account result came back with 75 properties. What if I know I only need a small subset? I can configure the searcher to only retrieve those properties.

This takes a little juggling to get the property names loaded.



1 2 3 4 $props = "distinguishedname" , "name" , "samaccountname" , "title" , "department" , "directreports" foreach ( $item in $props ) { $searcher . PropertiesToLoad . Add ( $item ) | out-null }



Search Properties to Load (Image Credit: Jeff Hicks)

The result is now limited to these properties and ran a little quicker at 22ms.

Limited Property Results (Image Credit: Jeff Hicks)

You can use the techniques from the previous article to clean this up.

You can also get the complete object with the GetDirectoryEntry() method. If you recall, the FindOne() and FindAll() methods write a result object to the pipeline, not the actual object.

Getting the Full Directory Entry (Image Credit: Jeff Hicks)

Here is another way to display properties cleanly:



1 2 3 4 5 6 $entry | Select @ { Name = "DN" ; Expression = { $_ . DistinguishedName . value } } , @ { Name = "SAM" ; Expression = { $_ . samAccountname . value } } , @ { Name = "Name" ; Expression = { $_ . name . value } } , @ { Name = "Title" ; Expression = { $_ . title . value } } , @ { Name = "Dept" ; Expression = { $_ . department . value } } , @ { Name = "DirectReports" ; Expression = { $_ . directreports . value } }



Selected Properties (Image Credit: Jeff Hicks)

I could have easily retrieved these properties alone in the searcher without having to get the full object. If you want to do a full directory entry, you do not have to resort to 100 Select-Object expressions.



1 2 3 4 5 6 7 8 $entry . Properties . GetEnumerator ( ) | Foreach -begin { $h = @ { } } -process { $h . add ( $_ . PropertyName , $_ . value ) } -end { new-object psobject -Property $h }



A Better Property Display (Image Credit: Jeff Hicks)

Subscribe to Petri Newsletters Office 365 Insider Our Petri Office 365 Insider is dedicated to sharing detailed knowledge from top Office 365 experts. Delivered once a month to your inbox. All Newsletters Petri.com may use your contact information to provide updates, offers and resources that may be of interest to you. You can unsubscribe at any time. To learn more about how we manage your data, you can read our Privacy Policy and Terms of Service. !Already a Petri.com member? Login here for 1-click registration.

Let’s put everything we have looked at into a function that will get the full user object from AD with nothing but the SamAccountname.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 Function Get-MyADUserObject { [ cmdletbinding ( ) ] Param ( [ Parameter ( Position = 0 , Mandatory ) ] [ string ] $SamAccountname , [ ValidatePattern ( "^LDAP://" ) ] [ string ] $SearchRoot ) $searcher = New-Object system . DirectoryServices . DirectorySearcher $searcher . filter = "samaccountname=$SamAccountName" #limit search properties since we're going to get the complete user object $searcher . PropertiesToLoad . Add ( "distinguishedname" ) | out-null if ( $SearchRoot ) { $searcher . SearchRoot = $SearchRoot } $user = $searcher . FindOne ( ) if ( $user . Path ) { $entry = $user . GetDirectoryEntry ( ) $entry . Properties . GetEnumerator ( ) | Foreach -begin { $h = @ { } } -process { $h . add ( $_ . propertyName , $_ . value ) } -end { new-object psobject -Property $h } } else { Write-Warning "Could not find user $samaccountname under $($searcher.SearchRoot.Path)" } } #end function



Feel free to expand upon this. Now, I have a tool to get a user from AD that writes an object to the pipeline. I can work with this.

Testing the Function (Image Credit: Jeff Hicks)

Everything we have been doing for a single object, we can also do for many. We will start down that path next time.