Searching the Active Directory using PowerShell


In my last blog, I provided a sample PowerShell script that shows how to use the System.DirectoryServices namespace from .NET Framework to bulk create users. Now I will show you can you can use the same namespace to search the Active Directory.

We have a lot of customers wanting to get the last time a user has logged on the system. Since there is no way to create an LDAP query to give you the last time a user has logged on, I figured that it is best to get all the users into memory and then filter them using PowerShell’s handy cmdlets to do the work.

First, I have to create the function that enumerates all the users. I did this by using the System.DirectoryServices.DirectoryEntry class and System.DirectoryServices.DirectorySearcher class. The section of code below shows how to do this:

 1: #'===================================================================
 2: #' This function will get all the users in an OU &; its sub OUs
 3: #'===================================================================
 4: function FindAllUsers()
 5: {
 6:     $searchFilter = "(&(objectCategory=user)(objectClass=user))" 
 7:     $deBaseDN = new-object System.DirectoryServices.DirectoryEntry $BaseDN, $domAdmin, $domPass
 8:     $deBaseDN.RefreshCache()
 9:     
 10:     #start-sleep 10
 11:     $deSearcher = new-object System.DirectoryServices.DirectorySearcher 
 12:     $deSearcher.SearchRoot = $deBaseDN
 13:     $deSearcher.SearchScope = "subtree"
 14:     $deSearcher.Filter = $searchFilter
 15:     $deSearcher.PageSize = 1000
 16:     $hr  = $deSearcher.PropertiesToLoad.Add("distinguishedname")
 17:     $hr  = $deSearcher.PropertiesToLoad.Add("lastlogontimestamp")
 18:     $src = $deSearcher.FindAll()
 19:     
 20:     return $src
 21: }

You will need to set some of the variables ahead of time that I normally put at the beginning of the script:

 1: #'===================================================================
 2: #' Specify the your environment specific settings
 3: #'===================================================================
 4: $domain   = "YOURDOMAIN"
 5: $searchDN = "DC=yourdomain,DC=com"
 6: $BaseDN   = "LDAP://" + $domain + "/" + $searchDN
 7: $domAdmin = "YOURDOMAIN\Administrator"
 8: $domPass  = "!Password!"

I then save all the users found and store it in a variable called $allusers, which is the unfiltered list of users.

 1: $allusers = FindAllUsers

I need to filter down the list and only include users that do have logged into the system. If a user has not logged into the system, the lastLogonTimestamp does not exist, so I filtered it using the command below and stored it in a variable called $withlastlogons:

 1: $withlastlogons = $allusers | where-object {$_.Properties["lastlogontimestamp"] -ne $null }

I then created a new variable called $filterusers where it is a modified version of $withlastlogons. I did this because the lastLogonTimestamp property value needed to be converted so I can compare it with date values that are native to PowerShell.

 1: $filterusers = $withlastlogons | select-object @{Name="LastLogonTimeStamp"; Expression = {[datetime]::fromfiletime($_.Properties["lastlogontimestamp"][0])}}, @{Name="DN"; Expression = {$_.Properties["distinguishedname"][0]}}

The last thing I had to do is to filter it relative to the current date. If I want to pull all the users that has logged and it has been over 10 days since they last logged on, I would use the filter:

 1: $filterusers | where-object {$_.lastlogontimestamp -lt (get-Date).AddDays(-10)}

Below is the final code along with some other samples on how to pull the data:

 1: #'===================================================================
 2: #' Specify the your environment specific settings
 3: #'===================================================================
 4: $domain   = "YOURDOMAIN"
 5: $searchDN = "DC=yourdomain,DC=com"
 6: $BaseDN   = "LDAP://" + $domain + "/" + $searchDN
 7: $domAdmin = "YOURDOMAIN\Administrator"
 8: $domPass  = "!Password!"
 9:   
 10:  
 11: #'===================================================================
 12: #' This function will get all the users in an OU &; its sub OUs
 13: #'===================================================================
 14: function FindAllUsers()
 15: {
 16:     $searchFilter = "(&(objectCategory=user)(objectClass=user))" 
 17:     $deBaseDN = new-object System.DirectoryServices.DirectoryEntry $BaseDN, $domAdmin, $domPass
 18:     $deBaseDN.RefreshCache()
 19:     
 20:     #start-sleep 10
 21:     $deSearcher = new-object System.DirectoryServices.DirectorySearcher 
 22:     $deSearcher.SearchRoot = $deBaseDN
 23:     $deSearcher.SearchScope = "subtree"
 24:     $deSearcher.Filter = $searchFilter
 25:     $deSearcher.PageSize = 1000
 26:     $hr  = $deSearcher.PropertiesToLoad.Add("distinguishedname")
 27:     $hr  = $deSearcher.PropertiesToLoad.Add("lastlogontimestamp")
 28:     $src = $deSearcher.FindAll()
 29:     
 30:     return $src
 31: }
 32:  
 33: #'===================================================================
 34: # This illustrates how to call the function "FindAllUsers" and then
 35: # processes ALL users &; only add to the collection if the
 36: # lastlogontimestamp exist. The collection is named $withlastlogons 
 37: #'===================================================================
 38: $allusers = FindAllUsers
 39: $withlastlogons = $allusers | where-object {$_.Properties["lastlogontimestamp"] -ne $null }
 40:  
 41: #'===================================================================
 42: # This outputs the lastlogontimestamp in raw format
 43: #'===================================================================
 44: $withlastlogons | % { $_.Properties["lastlogontimestamp"][0] }
 45:  
 46: #'===================================================================
 47: # This outputs the lastlogontimestamp in date format
 48: #'===================================================================
 49: $withlastlogons | % { [datetime]::fromfiletime($_.Properties["lastlogontimestamp"][0]) }
 50:  
 51: #'===================================================================
 52: # This illustrates how to get the lastLogonTimeStamp in date format &;
 53: # stuff it in a variable name $dates
 54: #'===================================================================
 55: $dates = $withlastlogons | % { [datetime]::fromfiletime($_.Properties["lastlogontimestamp"][0]) }
 56:  
 57: #'===================================================================
 58: # This creates a collection of users w/ the LastLogonTimeStamp &; DN
 59: # and retrieve the users that have not logged in for over 10 days
 60: #'===================================================================
 61: $filterusers = $withlastlogons | select-object @{Name="LastLogonTimeStamp"; Expression = {[datetime]::fromfiletime($_.Properties["lastlogontimestamp"][0])}}, @{Name="DN"; Expression = {$_.Properties["distinguishedname"][0]}}
 62: $filterusers | where-object {$_.lastlogontimestamp -lt (get-Date).AddDays(-10)}

Have fun!

Skip to main content