There seems to be a large argument between some of systems administrators we have worked with about the best way to determine exactly how an Active Directory account is stale or not.

First, let's talk about the TWO main attributes on the account:

- LastLogon:
                  When a user logs on, this attribute is updated on the Domain Controller that provided the authentication ONLY.  Because it is only updated on one DC, that means this attribute is not replicated.  While that might seem inconvenient at first, this is actually a pretty useful function.  In those cases when you may want to figure out what sites a user has logged on (or not logged on), you would use this attribute.
                  To accomplish that, you can write a quick query:

$(foreach ($DC in ((get-addomaincontroller -filter * | sort name).name) ){ $user = get-aduser chris -properties lastlogon -server     $dc | select name,lastlogon ; echo "$DC - $(w32tm /ntte $user.lastlogon)" }  )

                   When you run this command, every DC in the domain will be queried for a user account’s attribute for lastlogon.  In this example, we’re looking for ‘’.  If you see the results come back with no value for lastlogon=, that means that user has never logged on using that particular Domain Controller. 

                  If you look at the results, the most recent logon timestamp will show the domain controller the user has last authenticated to.

- LastLogonTimeStamp

                  To summarize this attribute, this is the replicated version of the LastLogon attribute.  Although, because it just can’t be that easy, there are a few things to understand before we start to use this attribute.                 

1: LastLogonTimeStamp only updates when the mood is right.

                  There is an attribute called the “ms-DS-Logon-Time-Sync-Interval”.  You can find this attribute on the domain default naming context.  By default, the value for this setting is 'NOT SET', but that actually translates to 14 days.

                  To prevent an insane amount of replication every time a user logs on, Active Directory will actually perform a calculation to determine if it should update this attribute.  By preventing the change of this attribute, it won’t need to replicate as often.

                  How does AD know when to update this attribute?

  • When the user logs on, the DC will pull the current value for lastlogontimestamp.
  • A value is generated for comparison. (14 minus a random percentage of 5 = valueforcomparison) (This generates a threshold of less than 14 days for updating)
  • The previous timestamp is subtracted from the current time.
  • If the time difference between the last timestamp is greater than the comparisonvalue, the attribute is updated ( = It has been too long, it updates, the attribute replicates)
  • If the time difference is still less than the comparison value, then it hasn’t been long enough and the attribute won’t be updated yet.

2: What is this attribute really used for?

                  As far as we can tell, this is primarily used to identify stale accounts on the domain.  If you wanted to find a list of all the users and decide who hasn’t utilized their accounts within a certain defined amount of time, you could perform an LDAP query and filter based upon this value.  That sounds pretty useful, right?  Not so much.  As pretty much any VBScript writer will tell you, it’s a little annoying to take this value and convert it from NT time to something readable.  It’s a bit of a hassle, but it works.

                  Even though the value for this attribute is displayed in NT Time, we can easily view a user’s timestamp value in ‘human friendly mode’ in Active Directory Users and Computers.  To view this value:

-        Open ADUC.msc

-        Go to the View Menu and select Advanced Features

-        Navigate to the user you wish to view (Do not use the Find feature)

-        Open the objects properties

-        Choose the Attribute Editor tab

-        Scroll down to the LastLogonTimeStamp attribute

  • You’ll notice that in the view, it displays as a normal date and time.
  • If you click the EDIT button, you’ll get a popup showing the NT Time value.

 So if Microsoft has a process that already converts and displays something easier on the eyes, why isn’t that a replicated value?  Well, that brings me to my main point of this article.

- LastLogonDate

                  One day, we were helping a colleague identify a list of active users and computers.  While putting the second set of eyes on his Powershell script, we noticed that he was utilizing the LastLogonTimeStamp value.  The problem was that this was supposed to be a dynamic script that could be ran at anytime and give an accurate output that would always find accounts active within the last 90 days.

                  Although his process worked, he had to do a lot of extra work to get it there.  Things like 1) Get today’s date, 2) Figure out what 90 days ago was, 3) Convert that date to a usable format and then have each object do a comparison to see which side of the fence it fell on.

                  When we asked him about why he wasn’t using the LastLogonDate attribute provided by PowerShell, he told me that value wasn’t replicated. 

So what is the LastLogonDate attribute?

                  PowerShell was nice enough to give us a third option to query by.  LastLogonDate is a converted version of LastLogontimestamp.  He was technically right.  It’s not a replicated attribute.  Instead, it’s a locally calculated value of the replicated value.  Most importantly, it gives us the ability to query using human friendly date formats!!

Instead of converting values back in forth, we can dynamically generate a list of active accounts:

                  Using a static date:

get-aduser -filter * -properties * | Where-Object {$_.lastlogondate -ge "1/7/2014"}

                   Using a dynamic calculated date (Within 90 days shown):

get-aduser -filter * -properties * | Where-Object {$_.lastlogondate -ge (get-date).adddays(-90)}

 That is a whole lot simpler than some of the VB Scripts we’ve seen!

To verify that the LastLogonDate value is in fact an accurate representation of the replicated value:

                  Convert the value using the W32TM commands:

w32tm /ntte 130336170486218095

150852 01:10:48.6218095 - 1/7/2014 8:10:48 PM

                   Using the command we used earlier for LastLogon, but for LastLogonDate instead:

$(foreach ($DC in ((get-addomaincontroller -filter * | sort name).name) ){ $user = get-aduser chris -properties lastlogondate –server $dc | select name,lastlogondate ; echo "$DC - $($user.lastlogondate)" }  )



                  Now that we know more about the lastlogontimestamp and lastlogondate, we can rapidly provide a more accurate list of who is stale.  And because we know that those attributes do not always update, we should probably refrain from filtering any timeline shorter than 14 days, unless you have manually set the time interval to a shorter time.

 Other Alternatives:

                  The great thing about PowerShell is that there is an ever growing list of cmdlets that simplify the major tasks that most administrators run.  If you are not adding any complex filters or if you just prefer a different way of accomplishing this task, consider the following cmdlet: Search-ADAccount

 You can quickly find a list of user accounts that not logged in within 90 days by using the following command:

Search-ADAccount -AccountInactive -DateTime ((get-date).adddays(-90)) -UsersOnly


Hope that you have found this article to be useful and somewhat educational.  We appreciate everyone’s feedback.

We would like thank Warren Williams for his blog.  It was extremely helpful in helping me understand how the timestamps work.
Check it out: