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!