Using AD to determine whether or not people are still working for the company and are allowed to logon to the systems is not the ideal, and account management should happen based on knowing what accounts should and should not be use, and not by figuring out which haven’t been used.  Realistically, if a fired employee is still logging on to the system we are not going to pick up the account that is stale and disable/delete it like actually needs to be done.
That said, in the real world things aren't always quite that easy.  As such, regardless of whether the account is a user account or computer account we have several attributes that are stored with the account that help us determine if it is used recently.  Unfortunately they all are potentially inaccurate in one fashion or another.  These attributes are pwdLastSet, lastLogon, and lastLogonTimeStamp (as of Windows 2003 DFL).
Essentially you can determine if the account is stale by ensuring all of the attributes are over a designated threshold.  A starting threshold for users is 3 times the maximum user password age and for computers is also 3 times the maximum computer password age.  In short, if both pwdLastSet and lastLogonTimeStamp are greater than the threshold, it is pretty safe to delete the account, unless you are in academia and the faculty member may be on sabbatical.
If you don’t have both of those, it gets a little more questionable as to whether or not the account is still in use, as each attribute can incorrectly report how recently the account was used in the following fashions:
  • This is systemically is inaccurate if either the domain has no password policy specifying an age limit or the account has the userAccountControl attribute PASSWD_CANT_CHANGE bit set.  Note, computer accounts can be configured to not change their password, but I have not observed many environments which change this setting.
  • This can be also misrepresent the recentness of account usage if, for example, the user or computer has not authenticated to the network in the intervening time between when the password needed to be changed and any threshold you may specify.  Think user is on vacation or sabbatical (common in academic environments).
  • This is also inaccurate if a user has a laptop and travels for extended periods.  Since the system is not on the network to communicate with the Domain Controller at boot, it can not reset the account.  This can be addressed by several methods, restarting the netlogon service after VPN has been established or using nltest or netdom to reset the password in a VPN startup script.
  • The data in this attribute is not replicated, thus this is only accurate on the DC the user last logged into.  Unless all DCs for the domain are queried, the data may be inaccurate.
  • Since AD clients are site aware, this also means that if there was only one DC in a remote location (or as happens sometimes, only one DC listed in WINS or DNS if they aren’t configured properly) and that system is decommissioned or lost due to some sort of outage it is entirely possible any indication the account ever logged in no longer exists.
  • This only tracks interactive logons.  This essentially means that a user has to press Ctrl+Alt+Del in order for this to register.
    Terminal services logons are a different type of logon in the SECURITY_LOGON_TYPE enumeration, of type RemoteInteractive and may not update lastLogon.  At some point I will test this and update the blog (possibly, “best laid plans of mice and men” and all that).
  • This is updated only when a client logs on.  If a user does not log off their machine for 90 days and the machine does not reboot, this will report the user has last logged on 90 days ago, which is exactly the truth.  It does not update in order to report that the user has been accessing the system and the network for the last 90 days.
  • Updating only when logon occurs also affects computers if they are not rebooted.  If the computers have remained up and running, the lastLogon is when they booted up.  This is highly unlikely to impact client systems, but may impact servers if they are up for greater than a specified threshold.
    Extremely long uptimes are much less likely if security updates are being deployed regularly.
  • (Updated 11/20/2014) – this does not track users who logon via cached credentials while the computer is off line and then connect.  An example is VPN scenario.
  • This requires Windows 2003 domain functional level (DFL).
  • Prior to Windows 2003 SP1 this did not track all network logons.
  • This can be up to 14 days off, though by adjusting your threshold but this shouldn’t be a problem if the number is sufficiently high.
  • As with pwdLastSet, this is also inaccurate if a user has a laptop and travels for extended periods.  The concerns and methods to address this are the same methods as pwdLastSet.
Also, when pulling this data you could also run into null values and these cause the following concerns:
  • pwdLastSet – the password gets set, updating this attribute, if you use any of the native Microsoft tools to create the account or when the computer is first joined to the domain.  If this is "0" (zero), some 3rd party code probably created the account and the computer never joined.  Except for a minor inconvenience to whomever pre-created the account, this account can be safely deleted unless one of the other timestamps is not null
  • lastLogon – this could be null for any number of reasons.  The user never logged on interactively (think user who only uses web based e-mail), the user never logged on to the DC(s) queried, or the user last logged on to a DC that no longer exists.
    If this is null on all DCs and lastLogonTimeStamp is not available, do not assume the account is stale unless no decommissions of DCs have occurred within the threshold.
  • lastLogonTimeStamp – if this is null the account has never logged on since the domain was brought to DFL 2003.  This is only a concern if the DFL was raised within the threshold designated for the account to be stale.
Be careful with place holder computer accounts for non-Windows OSs prior to as they may behave differently.  If you look at the operatingSystem attribute on the computer object you can determine if it needs more attention.  Examples:
  • Microsoft Cluster Server Virtual Server computer accounts.
  • OS X
  • Unix Interop
  • NetAPP

Update 11/20/2014:

There are several scenarios where there are non-logon processes that update lastLogonTimeStamp when a user has not logged on.  Anything that consumes Service-for-User (S4U) (this behavior was introduced in Windows 2003 SP1).  This includes the following known scenarios:
Another scenario that causes lastLogonTimeStamp to update is pre-populating passwords on RODCs.  Specifically know to happen via repadmin /rodcpwrepl.
LastInteractiveLogonTimeStamp – this has all the limitations of “LastLogon” except that it is replicated

Cases have been found where users known to have left the company were still showing as active and logging in.  However, further investigation showed infrastructure consuming S4U to audit permissions were increasing lastLogonTimeStamp.  This returns us to the recommendation at the start of this article that HR data needs to be authoritative.  These could have just as easily been the users continuing to logon and gain access to corporate resources they no longer should have.