CertCities.com -- The Ultimate Site for Certified IT Professionals
Register today for a Free Sponsored Tech Library Webcast and you could WIN! Share share | bookmark | e-mail
  Microsoft®
  Cisco®
  Security
  Oracle®
  A+/Network+"
  Linux/Unix
  More Certs
  Newsletters
  Salary Surveys
  Forums
  News
  Exam Reviews
  Tips
  Columns
  Features
  PopQuiz
  RSS Feeds
  Press Releases
  Contributors
  About Us
  Search
 

Advanced Search
  Free Newsletter
  Sign-up for the #1 Weekly IT
Certification News
and Advice.
Subscribe to CertCities.com Free Weekly E-mail Newsletter
CertCities.com

See What's New on
Redmondmag.com!

Cover Story: IE8: Behind the 8 Ball

Tech-Ed: Let's (Third) Party!

A Secure Leap into the Cloud

Windows Mobile's New Moves

SQL Speed Secrets


CertCities.com
Let us know what you
think! E-mail us at:



 
 
...Home ... Editorial ... Columns ..Column Story Saturday: April 5, 2014


 Microsoft: Under the Hood  
Don Jones
Don Jones


 Finding Idle Users
A domain security script for pre-Windows Server 2003 domains.
by Don Jones  
5/26/2004 -- My business partner, Derek Melber, was recently asked by one of our consulting clients to create a script that would aid them in auditing their domain security. He wanted to create a report that would display users' account status, including lockout, disabled, last time their password was changed, and so forth. He also wanted to display users' last logon date.

All that information is in the domain, but the last logon date in particular can be difficult to figure out in pre-Win2003 domains. That's because, prior to Win2003, the "lastLogon" attribute isn't replicated, meaning only the last DC that a user authenticated to will have an accurate value. So to display an accurate value, you'd have to query every domain controller in the domain—perfect gruntwork for a script, but not the easiest thing to code. I had some free time this past Saturday, though (I have no life), and decided to take a whack at it, using Derek's original script as a starting point.

One thing I wanted to do was be able to check every user in the domain, which is a less-than-straightforward task in AD, where users can be buried under a tree of organizational units (OUs). Fortunately, AD is backward-compatible with Windows NT domains, meaning AD can present its user list as a flat list, ignoring OU membership. Windows NT also provides an easier-to-use LastLogin property for users; AD's native lastLogon property (note the subtle name difference) is a complex integer value that includes both a time and date, and it's a pain to fuss with in VBScript.

On the other hand, NT doesn't make it very easy to enumerate a list of all DCs in the domain. AD doesn't exactly make it easier, but it does have a helpful Domain Controllers OU, which, nine times out of ten, contains every DC in the domain. In fact, pretty much nobody recommends ever moving DCs out of the Domain Controllers OU, so it's a safe bet that all the DCs' computer accounts can be found there.

Given the relative strengths and weaknesses of NT and AD, then, I resolved to use both. The result is the following script, which uses Active Directory Services Interface (ADSI) and VBScript to query an AD domain both from an NT standpoint (using the WinNT: moniker) and from a native AD standpoint (using the LDAP: moniker). Check it out:

'get domain and container
Dim sTarget, sOU
sTarget = InputBox("Target what domain?", "Domain?", _
   "techmentorevent")

sLDAP = InputBox("LDAP version of domain name?", "LDAP Domain?", _
  "dc=techmentorevents,dc=pri")

'iterate through all DCs?
Dim bCheckAll
bCheckAll = MsgBox("Check all DCs for last logon date?", _
  4, "Check all DCs?")
If bCheckAll = 6 Then
  bCheckAll = True
Else
  bCheckAll = False
End If

'objects for output file
Dim sOutput, oFSO, oTS
sOutput = InputBox("Output path and filename?", "Filename?", _
  "c:\domainreport.csv")
Set oFSO = CreateObject("Scripting.FileSystemObject")

'see if file exists
If oFSO.FileExists(sOutput) Then
  MsgBox("File exists. Please select another.")
  WScript.Quit
End If

'create output file
Set oTS = oFSO.CreateTextFile(sOutput)
Const cComma = ","

'output header
oTS.WriteLine "User" & _
  cComma & "Disabled" & cComma & "Locked" & _
  cComma & "IdleDays"

'get destination container
On Error Resume Next
Set oOU = GetObject("WinNT://" & sTarget)
If Err <> 0 Then
  MsgBox "Error: " & vbCrLf & Err.Description
  WScript.Quit
End If
On Error Goto 0

'filter for user objects
oOU.Filter = Array("User")

'get the Default Domain Controllers container
Dim oDCs, oDC
Set oDCs = GetObject("LDAP://ou=Domain Controllers," & _
  sLDAP)

'go through container objects
Dim oObject
For Each oObject In oOU

      'get attributes
      Dim bDisabled, bLocked, iIdleDays
      Dim dLastLogin, dLocalLastLogin

      'reset last login date
      dLastLogin = CDate("1/1/1900")

      'is user disabled?
      If oObject.accountdisabled Then
        bDisabled = True
      Else
        bDisabled = False
      End If

      'is user locked out?
        If oObject.isaccountlocked Then
        bLocked = True
       Else
        bLocked = False
       End If

      'output basic info
      oTS.Write oObject.name & cComma & _
        bDisabled & cComma & _
        bLocked & cComma

      'check for last login?
      If bCheckAll Then

        'checking last login on all DCs
        For Each oDC In oDCs

          'get last login from this DC
          Dim oLocalUser
          Set oLocalUser = GetObject("WinNT://" & _
               Replace(oDC.sAMAccountName,"$","") & "/" & _
               oObject.name & ",user")

            On Error Resume Next
            dLocalLastLogin = oLocalUser.LastLogin
            If Err <> 0 Then
               dLocalLastLogin = CDate("1/1/1900")
            End If
            On Error Goto 0

            'is that more recent?
            If dLocalLastLogin > dLastLogin Then
               dLastLogin = dLocalLastLogin
            End If

          Next

          'output last login
          oTS.Write DateDiff("d",dLastLogin,Date) & vbcrlf

      Else
         'not checking last login
         oTS.Write "n/a" & vbcrlf
      End If

Next

'close text file and notify
oTS.Close
MsgBox "Finished. Output is at " & sOutput


When you run this script, you'll have to enter the domain name twice. First, enter a normal NT domain name (the default is TECHMENTOREVENT). Next, enter the LDAP-style domain name. The default is "dc=techmentorevents,dc=pri" for my example domain, techmentorevents.pri. If your domain was braincore.net, you'd enter "dc=braincore,dc=net" for the domain name. You can decide whether or not to check the LastLogin property, because doing so will cause the script to run for a lot longer since it has to query a bunch of computers. The script will, by the way, bomb out if any of your DCs are unreachable. I left it that way on purpose, but you can have it ignore missing DCs by using the following code:

      'get last login from this DC
      Dim oLocalUser
      On Error Resume Next
      Set oLocalUser = GetObject("WinNT://" & _
         Replace(oDC.sAMAccountName,"$","") & "/" & _
         oObject.name & ",user")

The boldfaced line of code tells VBScript to ignore any errors and keep right on processing.

I hope this will be a useful script for you. Those of you lucky enough to work in a native Windows Server 2003 domain don't need this trickery, because Win2003 repliates the lastLogin property to all DCs; just use the Saved Queries feature in 2003's AD Users and Computers console to query for user accounts that haven't logged in during a specified number of days. Note that it's impossible for me to test this script in the myriad environments out there; it's possible your environment may contain something that causes the script to bomb unexpectedly. If it does, please feel free to send me a short e-mail describing the problem and I'll do my best to help you figure it out. This script outputs a file that can easily be imported into Excel so that you can sort by column or do whatever other fancy stuff you like.


Don Jones is the owner and operator of ScriptingAnswers.com, a speaker at national technical IT conferences, and the author of nearly twenty books on information technology. His latest book is "Managing Windows with VBScript and WMI" (Addison-Welsey) and he's completing "Windows Administrator's Automation Toolkit" (Microsoft Press). You can reach Don at his Web site or at .

 


More articles by Don Jones:

-- advertisement --


There are 20 CertCities.com user Comments for “Finding Idle Users”
Page 1 of 2
7/13/04: JohnRolstead from St. Louis, MO says: This code works ok if you are in a small environment, with only a few domain controllers. I support a Windows 2000 shop with 30 domain controllers in all parts of the world. Another alternative to Last Logon is Password Last Set. Our password policy is set to max 90 days, so if a password is not changing in 120 days or so, the user is probably no longer needed. pwdLastSet is replicated to all DCs, making query time about 1 minute. Here is the coder who wrote the perl script to query this value. It can work for users and computers by the way. NT changes password every 7 days, W2K and above every 30 days. # This Perl code finds the user accounts whose password is about to expire # --------------------------------------------------------------- # From the book "Active Directory Cookbook" by Robbie Allen # Publisher: O'Reilly and Associates # ISBN: 0-596-00466-4 # Book web site: http://rallenhome.com/books/adcookbook/code.html #
12/9/04: Nate79 from Colorado says: Thanks for taking the time to post this script Don. It helped out with some stuff we had to do for Sarbanes-Oxley.
2/15/05: Dipesh Malk from Delhi says: Every time i will try to execute this script. i will get an error message that: ERROR : PERMISSION DENIED 'GETOBJECT' CODE : 800A0046
3/15/05: Joshua from Little Rock, Arkansas, USA says: I'm receiving the same error that Dipesh gets. What gives?
9/13/06: Jones Fan says: Thanks Don! Works perfectly, as your scripts always do. Dipesh and Josh: Are you running with enterprise admin rights? Also, check to make sure this key is present in the registry: HKLM\SOFTWARE\Microsoft\Ole\EnableDCOM:R eg_SZ:Y Could also check this: Open Control Panel Open Administrative Tools Open the Component Services applet Select Component Services and open the Computers Folder Right Click My Computer and select Properties Select the Default Properties tab and Ensure Enable Distribted COM on this Computer is Checked. Apply, close all windows and reboot the PC
1/26/07: Anonymous says: I am just wondering, is it possible to modify this scripts to find only the “OU USERS” (I mean with specified OU’s) with “last logon” ? Can you also please publish the new scripts in your website and send one email along the modified scripts? Thanks, SuvajitBasu
7/21/10: Anonymous says: Thanks for the code, unfortunately I can't get it to run. Forgive me, I'm a n00b in Active Directory. I'm not sure what the LDAP prompt is referring to, and this is probably why I'm getting the 'a referral was returned from the server' error after running the script. A little help?
6/30/13: michael kors outlet coupons from [email protected] says: ths michael kors outlet coupons http://www.michaelkorsioutlet.org/
7/1/13: louis vuitton outlet store from [email protected] says: nice articles louis vuitton outlet store http://www.louisvuittonttoutlet.com
7/5/13: guccioutletstore-online.com from [email protected] says: good share. guccioutletstore-online.com http://www.guccioutletstore-online.com
First Page   Next Page   Last Page
Your comment about: “Finding Idle Users”
Name: (optional)
Location: (optional)
E-mail Address: (optional)
Comment:
   

-- advertisement (story continued below) --

top