Useful script for finding when a specified user last logged on to the domain.
I saw a similar script some time ago (it was for all domain users though), but I cannot remember where, so I wrote this one myself!
Any advice on making it better would be greatly appreciated!
' LastLogonSpecific.vbs
' Script to check when a specific user last logged on to the domain.
' As the LastLogon attribute does not replicate, each domain controller is
' queried to find the latest LastLogon information for the specified user.
' We could use the LastLogonTimeStamp attribute, which is replicated, but this
' is inefficient as it only updates when the user logs on if the old value is
' older than 14 days.
'---------------------------------------------------------------------------'
' As the lastLogon attribute does not get replicated, each DC in the domain
' is queried to find the latest lastLogon for the specified user.
' The latest date found is kept in a dictionary object. The script uses ADO
' to search the domain for all DCs, and the AdsPath of each is saved into an
' array. Then, for each DC, ADO is used to search AD on that DC for the user
' object and return the lastLogon attribute.
' The lastLogon attribute is a 64-bit number representing the number of 100
' nanosecond intervals since 01/01/1991. This value is converted to a date.
' The last logon date is in UTC, which must be adjusted by the Time Zone
' bias, stored in the machine registry, to convert to local time. Option Explicit
Dim adoCommand, adoConnection, adoRecordset, arrstrDCs(), dtmdate
Dim k, lngBias, lngBiasKey, lngHigh, lngLow
Dim objDate, objDC, objList, objRootDSE, objShell
Dim strAttributes, strBase, strConfig, strDNSDomain
Dim strFilter, strName, strNTName, strQuery strName = InputBox("Enter username","UserName","") ' Retrieve local Time Zone bias from registry
Set objShell = CreateObject("Wscript.Shell")
lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\" _
& "TimeZoneInformation\ActiveTimeBias")
If (UCase(TypeName(lngBiasKey)) = "LONG") Then
lngBias = lngBiasKey
ElseIf (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then
lngBias = 0
For k = 0 To UBound(lngBiasKey)
lngBias = lngBias + (lngBiasKey(k) * 256^k)
Next
End If ' Use a dictionary object to track latest lastLogon for each user.
Set objList = CreateObject("Scripting.Dictionary")
objList.CompareMode = vbTextCompare ' Setup ADO objects and
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection ' Identify domain controllers
Set objRootDSE = GetObject("LDAP://RootDSE")
strConfig = objRootDSE.Get("configurationNamingContext")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
strBase = "<LDAP://" & strConfig & ">"
strFilter = "(objectClass=nTDSDSA)"
strAttributes = "AdsPath"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree" ' Run the query.
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 60
adoCommand.Properties("Cache Results") = False Set adoRecordset = adoCommand.Execute ' Enumerate parent objects of class nTDSDSA, save DC AdsPaths in arrstrDCs
k = 0
Do Until adoRecordset.EOF
Set objDC = _
GetObject(GetObject(adoRecordset.Fields("AdsPath").Value).Parent)
ReDim Preserve arrstrDCs(k)
arrstrDCs(k) = objDC.DNSHostName
k = k + 1
adoRecordset.MoveNext
Loop
adoRecordset.Close strAttributes = "sAMAccountName,lastLogon" ' Retrieve lastLogon attribute for each user on each Domain Controller.
For k = 0 To Ubound(arrstrDCs)
' Search the entire domain in the copy of AD on this DC
strBase = "<LDAP://" & arrstrDCs(k) & "/" & strDNSDomain & ">"
strFilter = "(|(sAMAccountName=" & strName & "))" ' Create LDAP syntax query and execute
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
Set adoRecordset = adoCommand.Execute ' Enumerate the resulting recordset
Do Until adoRecordset.EOF
strNTName = adoRecordset.Fields("sAMAccountName").Value
On Error Resume Next
Set objDate = adoRecordset.Fields("lastLogon").Value
If (Err.Number <> 0) Then
On Error GoTo 0
dtmDate = #1/1/1991#
Else
On Error GoTo 0
lngHigh = objDate.HighPart
lngLow = objDate.LowPart
If (lngLow < 0) Then
lngHigh = lngHigh + 1
End If
If (lngHigh = 0) And (lngLow = 0) Then
dtmDate = #1/1/1991#
Else
dtmDate = #1/1/1991# + (((lngHigh * (2 ^ 32)) _
+ lngLow)/600000000 - lngBias)/1440
End If
End If ' Retain newest value for user
If (objList.Exists(strNTName) = True) Then
If (dtmDate > objList(strNTName)) Then
objList.Item(strNTName) = dtmDate
End If
Else
objList.Add strNTName, dtmDate
End If adoRecordset.MoveNext
Loop
adoRecordset.Close
Next ' Output latest lastLogon date for specified user
For Each strNTName In objList.Keys
Wscript.Echo strNTName & " last logged on at " & objList.Item(strNTName)
Next adoConnection.Close I don't understand why the line breaks don't work properly, so if you want a copy of the code (with the correct line breaks!) just PM me
~harry
<message edited by harry on Thursday, September 15, 2011 6:03 PM>