Contents for Ezine 85 - LastLogon
Property
Is your server running slowly? Check with SolarWinds ipMonitor
Get a free evaluation copy of ipMonitor
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.
If you are looking for handy network utilities, try some of the free downloads at
Tools4Ever
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. - Enumerate the lastLogon date for all objects in an OU
- Filter those users with old accounts
- Move the accounts to a holding OU
- 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.
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.
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,). PrerequisitesThis 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.
- Decide upon the OU where you want to enumerate accounts, this is vital. (I choose OU=Droitwich, note the comma.)
- Copy and paste the example script below into notepad or
use a VBScript editor.
-
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).
- Save the file with a .vbs extension, for example:
lastLogon.vbs
- Double click lastLogon.vbs and check the message box.
This example displays the lastLogon LDAP attribute for all object in a named OU.
' LastLogon.vbs ' 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 PointsNote 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 ChallengesFor 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.
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.
Their topics and material are ideal for getting you started with VBScript. The
videos are easy to follow and you can control the pace. Try their free demo material and then see if you want to buy the full package.
See more about VB Script Training CD.
|