Guy’s Scripting Ezine 85 – LastLogon Property

Contents for Ezine 85 – LastLogon Property

Ldap Query Last Logon

 ♣

This Week’s Secret

I have a dilemma.  Four readers have requested a script that will assist them to delete users.  They want to clean up Active Directory based on time since the last logon.  My problem is that I don’t like and I don’t trust the lastLogon LDAP property, which is required for such a script.  To return to my dilemma, do I ignore lastLogon, or do I help readers by creating a script?

Here is what I am going to do, set out my concerns about lastLogon, then give you a script which works OK for me.  I seek a compromise between explaining how to detect old objects with VBScript, yet warn you of the inherent pitfalls of such a script.

Guy Recommends 3 Free Active Directory ToolsDownload Solarwinds Active Directory Administration Tool

SolarWinds have produced three Active Directory add-ons.  These free utilities have been approved by Microsoft, and will help to manage your domain by:

  1. Seeking and zapping unwanted user accounts.
  2. Finding inactive computers.
  3. Bulk-importing new users.  Give this AD utility a try, it’s free!

Download your FREE Active Directory administration tools.

Scenario: You want to Identify Old User or Computer Accounts

Administrators want to delete old accounts, this is a worthy goal.  If a user never joined the organization, or a computer has been thrown out, then the corresponding account only clutters up Active Directory.

My recipe for success is to break down a complex script into manageable scriplets, get each part working and then join them all together.  Therefore, let us take a step backwards and analyse the four steps need to achieve our goal of deleting old accounts.

  1. Enumerate the lastLogon date for all objects in an OU
  2. Filter those users with old accounts
  3. Move the accounts to a holding OU
  4. Check then delete the accounts

This week’s scripts seek solely to achieve point 1. To list the lastLogon date for objects in an OU.  Next week I will tackle filtering and moving Active Directory objects such as users.

Beware lastLogon

Time to explain what Guy can possibly have against manipulating old accounts with the lastLogon LDAP property.

0) Creating any script which deletes Active Directory objects, puts me under extra pressure.  What if, despite testing,  my script goes wrong and deletes the wrong objects in your domain?

1) My research reveals that Active Directory stores the lastLogon attribute as Integer8 (8 bytes). This means lastLogon is stored as a 64-bit number, the problem is that VBScript cannot handle 64-bit numbers directly.  Fortunately, there is a work around, namely, to treat lastLogon as an object, and then assign it HighPart and LowPart values.

To digress, the ace stock picker Warren Buffett once said, ‘Never invest in a company whose workings you cannot understand’.  Guy says, ‘Never invest in an LDAP property whose workings you do not fully comprehend’.  My problem is that I have not met anyone who can explain to my satisfaction the maths and logic of HighPart and LowPart.  Yes, it worked in my example, but I did not truly understand why.

2)My best maths skill is estimating, I always know roughly how much the shopping will cost, I can guess to within one gallon how much petrol I need to fill my tank.  When it comes to estimating how many 100 nanosecond slices there are in a year, I have no idea.  Perhaps I should have mentioned earlier, lastLogon measures 100 nanosecond time slices since January 1st 1601.  I believe this time base is known as (UTC) Universal Time Co-ordination.  My point is that I cannot rely on my usual estimation skills to work out if I have made an arithmetic mistake.  (Are there 10000000 nanoseconds in a second, or is it 10000000?) 

Just in case you think I am a maths dunce, I am able to calculate, that depending when you read this, there are approx 147803 days since January 1601.  You may detect I am having a cathartic moment, so here is another of my irritations – numbers without thousand separators.  To my way of thinking, the number of days should display as 147,803 in English. (147.803 in American?)   Is my irritation with large numbers without separators an age factor, or is it an English phenomenon?  Do tell me what you think.

3) The next problem, which is going to affect some readers, is the date format.  The fact that the majority of readers have dateline offset from GMT of just a few hours, probably won’t matter.  However, a more serious worry is that the lastLogon calculation relies on the date format.  Specifically, there is more than one time format, the USA use: mm-dd-yy, whereas, the UK uses the format dd-mm-yy.  Again, my gut instinct is the format will be consistent for all domain controllers thus will not matter, but a lingering doubt remains in my mind.

4) There is one more banana skin waiting to trip you up.  LastLogon is one of the few Active Directory objects that is not replicated between domain controllers.  I’m lucky in that I only had one Domain Controller in my test domain, but this does not reflect real life.  I can foresee a potential disaster that unless you query all domain controllers, you could easily come to the wrong conclusion.  One Domain Controller could report that a given user never logged on, only to find out that they had indeed logged on elsewhere.  Meanwhile, you could have deleted the user on the basis of my lastLogon script.

In summary, if a script has one imperfection, then I can forgive it, but when I get 4 or 5 niggles, I start to worry about a scripts reliability.

Guy Recommends:  A Free Trial of the Network Performance Monitor (NPM)Review of Orion NPM v11.5 v11.5

SolarWinds’ Orion performance monitor will help you discover what’s happening on your network.  This utility will also guide you through troubleshooting; the dashboard will indicate whether the root cause is a broken link, faulty equipment or resource overload.

What I like best is the way NPM suggests solutions to network problems.  Its also has the ability to monitor the health of individual VMware virtual machines.  If you are interested in troubleshooting, and creating network maps, then I recommend that you try NPM now.

Download a free trial of Solarwinds’ Network Performance Monitor

Script to Identify Dormant User and Computer Accounts

The goal of this script is to display the time when each object last logged on.  In case you get swamped with data, I suggest you start with one, named OU.  Later you could amend the script to point to CN=Users, (not OU=Users,).

Prerequisites

This script needs an Active Directory domain, however please note that for safety, this script is designed for a domain with only one Domain Controller.  Best would be to logon as administrator at a domain controller.  My plan B would be to Remote Desktop to a domain controller.

Instructions for Creating a VBScript to display lastLogon time.

  1. Decide upon the OU where you want to enumerate accounts, this is vital.  (I choose OU=Droitwich, note the comma.)
  2. Copy and paste the example script below into notepad or use a VBScript editor.
  3. One advantage of a good script editor such as OnScript is that you can see the line numbers (See menu on the upper left for free copy).
  4. Save the file with a .vbs extension, for example: lastLogon.vbs 
  5. Double click lastLogon.vbs and check the message box.

Example – To Reset All Passwords in a Named OU

This example displays the lastLogon LDAP attribute for all object in a named OU.

‘ Example VBScript to display when an object last logged on
‘ Version 2.0 – August 2005
‘ ———————————————————‘
Option Explicit
Dim objOU, objUser, objRootDSE, objLastLogon
Dim strContainer, strDNSDomain
Dim intLastLogonTime, intGuyTime
‘ ——————————————————–‘
‘ Note: Please change OU=Droitwich, to reflect your domain
‘ ——————————————————–‘
strContainer = "OU=Droitwich, "

Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("DefaultNamingContext")

strContainer = strContainer & strDNSDomain
set objOU =GetObject("LDAP://" & strContainer )
For Each objUser In objOU
Set objLastLogon = objUser.Get("lastLogon")
intLastLogonTime = objLastLogon.HighPart * (2^32) + objLastLogon.LowPart
intLastLogonTime = intLastLogonTime / (60 * 10000000)
intLastLogonTime = intLastLogonTime / 1440

Wscript.Echo objUser.givenName & " ‘s last logon time: " _
& intLastLogonTime + #1/1/1601#
Next
WScript.Quit

‘ End of lastLogon example VBScript

Learning Points

Note 1: There are 10000000 (Ten million) 100 nanosecond slices in a second.  The 60* refers to the number of seconds in a minute.  I expect that you have worked out that 1440 refers to the number of minutes in a day.

Note 2: UTC time starts in 1601, remember the hash (#) in the formula + #1/1/1601#.  My calculations show there have been approx 147803 days since the beginning of UTC time in January 1601.

LastLogon Challenges

For a production script, you would probably need to filter either the object so that it returned Users, or Computers but not both.  Another filtering method that springs to mind is displaying only accounts that have not logged on since a specified date.

Both these challenges will be picked up in next week’s ezine, but if you wanted to experiment then feel free to amend my script, because it’s only by changing my script that you will truly understand lastLogon.

Guy Recommends: Tools4ever’s UMRAUMRA The User Management Resource Administrator

Tired of writing scripts? The User Management Resource Administrator solution by Tools4ever offers an alternative to time-consuming manual processes.

It features 100% auto provisioning, Helpdesk Delegation, Connectors to more than 130 systems/applications, Workflow Management, Self Service and many other benefits. Click on the link for more information onUMRA.

Summary of lastLogon date

Clearing up old accounts, or user objects that never have and never will logon is good housekeeping.  The best LDAP property is lastLogon, however, before you take action and delete accounts, check that the results are as expected.  Perhaps the most insidious problem is that lastLogon is not replicated amongst your domain controllers.

See More Active Directory VBScripts for Passwords

• User Spreadsheet  • Add Users to Groups  • Create Users  • Free CSV Importer

Ezine 83 Passwords  • Ezine 85 LastLogon  • Ezine 86 LastLogon   • Ezine 122 Passwords

Ezine 128 IUSR Passwords  • VBScript change password  • Tool Kit  • Ezines