LastLogon attribute search

G

Guest

I have a native windows 2003 domain. I want to query active directory for
users whose lastlogon attribute is older than 60 days, but I am not sure how
to begin. I have tried building a query from scratch, but I never see
LastLogon as a field that I can select. Any information about how to
accomlish this would be appreciated. Thanks!
 
C

Chriss3 [MVP]

Hello
You can use dsquery -computer inactive <days>

--
Regards
Christoffer Andersson
Microsoft MVP - Directory Services

No email replies please - reply in the newsgroup
 
G

Guest

Sorry, I looked it up and dsquery can be used to look for users, but I am not
sure that it is checking the lastlogon attribute. I believe it is checking
the password age which would mean that I would only be able to run it a
couple of times a year. I have a 180 days password life. That gets me started
anyway. Thanks!
 
P

Paul Bergson

In order to find out the last user logon either use the 2003 ADUC query

If you aren't on 2003 yest then try the script below, it has to poll every
dc to get the last logon on each and then from that determine the latest
logon. It creates a csv file on the local c:\users.txt

Line 101 allows you to pull dc's you don't want to include (We have virtual
dc's, etc...)
Modify line 213 to match your domain name

This is a *.vbs program. It will take about 10 minutes to run on a 1000
user object AD with 5 dc's

If you have more than 3000 user objects you will have to update line 210



'
' Author Paul Bergson
' Date Written June 24, 2003
' Description Rips out all users and their context from AD and writes
them to a ssv file (semi-colon seperated)
' Modified December 3, 2003 Fixed sAMAccountName
reference bug
' January 2, 2004 Added display name to the csv
output file
' May not be modified for commercial use
'
'

Option Explicit

Dim aryContainer(500) ' Track the name of all containers
Dim aryCN(9999,10) ' Track the name of all users
Dim aryWhen() ' When Created
Dim arySvCN() ' Original context
Dim aryHomeDirectory() ' Location of home folder
Dim aryScriptPath() ' Location of script path
Dim arydisplayName() ' Display Name
Dim cntLen, cntComma, cntRight
Dim cntX, cntY, cntZ
Dim cntL, cntM, cntO
Dim cntColumns
Dim flgLoop
Dim flgContainerFnd
Dim txtName, txtCN, txtSvName
Dim usr
Dim flag
Dim objConnection
Dim objRecordSet
Dim objCommand
Dim objUser
Dim fso
Dim ts
Dim strHomeDirectory
Dim Output

Dim fsoHTA
Dim tsHTA


Dim oRoot, sConfig, oConnection, oCommand, sQuery
Dim oResults, oDC, sDNSDomain, oShell, nBiasKey
Dim nBias, k, sDCs(), sAdsPath, oDate, nDate
Dim oComputer, nLatestDate

Const ADS_UF_PASSWD_NOTREQD = &H0020
Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Const ADS_UF_PASSWORD_EXPIRED = &H800000
Const ADS_UF_ACCOUNTDISABLE = &H0002


Sub AvailableDCs


' Obtain local Time Zone bias from machine registry.
' Watch for line wrapping.
Set oShell = CreateObject("Wscript.Shell")
nBiasKey =
oShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\Ac
tiveTimeBias")
If UCase(TypeName(nBiasKey)) = "LONG" Then
nBias = nBiasKey
ElseIf UCase(TypeName(nBiasKey)) = "VARIANT()" Then
nBias = 0
For k = 0 To UBound(nBiasKey)
nBias = nBias + (nBiasKey(k) * 256^k)
Next
End If

' Determine configuration context and
' DNS domain from RootDSE object.
Set oRoot = GetObject("LDAP://RootDSE")
sConfig = oRoot.Get("ConfigurationNamingContext")
sDNSDomain = oRoot.Get("DefaultNamingContext")

' Use ADO to search Active Directory for
' ObjectClass nTDSDSA.
' This will identify all Domain Controllers.
Set oCommand = CreateObject("ADODB.Command")
Set oConnection = CreateObject("ADODB.Connection")
oConnection.Provider = "ADsDSOObject"
oConnection.Open = "Active Directory Provider"
oCommand.ActiveConnection = oConnection

sQuery = "<LDAP://" & sConfig _
& ">;(ObjectClass=nTDSDSA);AdsPath;subtree"

oCommand.CommandText = sQuery
oCommand.Properties("Page Size") = 100
oCommand.Properties("Timeout") = 30
oCommand.Properties("Searchscope") = 2
oCommand.Properties("Cache Results") = False

Set oResults = oCommand.Execute

' Enumerate parent objects of class nTDSDSA. Save
' Domain Controller names in dynamic array sDCs.
k = 0
Do Until oResults.EOF
Set oDC = _
GetObject(GetObject(oResults.Fields("AdsPath")).Parent)

If Not UCASE(Left(oDC.DNSHostName,3)) = "VDC" and Not
UCASE(Left(oDC.DNSHostName,5)) = "DCSRE" Then ' don't include virtual
servers or SRE
ReDim Preserve sDCs(k)
sDCs(k) = oDC.DNSHostName
k = k + 1
End If
oResults.MoveNext
Loop

End Sub



Sub LastTime

' Hard code LDAP AdsPath of user.
sAdsPath = arySvCN(cntL)

' Retrieve LastLogon attribute for computer on
' each Domain Controller.
nLatestDate = #1/1/1601#
oDate = #1/1/1601#


For k = 0 To Ubound(sDCs)
On Error Resume Next
Set oComputer = GetObject("LDAP://" & sDCs(k) & "/" & sAdsPath)

' Trap error in case LastLogon is null.
Set oDate = oComputer.LastLogon
On Error Resume Next

If Err.Number <> 0 Then
Err.Clear
nDate = #1/1/1601#
Else
If (oDate.HighPart = 0) And (oDate.LowPart = 0 ) Then
nDate = #1/1/1601#
Else
nDate = #1/1/1601# + (((oDate.HighPart * (2 ^ 32)) _
+ oDate.LowPart)/600000000 - nBias)/1440
End If
End If

Err.Clear
If nDate > nLatestDate Then
nLatestDate = nDate
End If

Next

End Sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Routine to strip out all containers and place in the aryContainer '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub Stripper

Do
cntLen = Len(txtName)-3
txtName = Right(txtName,cntLen) ' Drops the Container
Type Name
cntComma = Instr(txtName,",") - 1 ' Find the end of the
name

If cntComma < 0 Then ' Last Name to process
there is no comma
cntComma = Len(txtName)
End If

txtCN = Left(txtName,cntComma) ' Pull the Name out of
the Distinguished Name

flgContainerFnd = "N"


For cntL = 0 to 500 ' Does this current
Container exist?
If aryContainer(cntL) = "" Then ' If current location is
blank then add it to the table
aryContainer(cntL) = txtCN
Exit For
End If

If aryContainer(cntL) = txtCN Then ' OU found
Exit For
End if
Next

aryCN(cntX, cntY) = cntL ' Store location of OU
cntY = cntY + 1 ' increment counter

cntComma = Instr(txtName,",") ' If equal to zero then
all done

If cntComma > 0 Then
cntRight = Len(txtName) - (cntComma) ' Get to start of next
part of name
txtName = Right(txtName, cntRight) ' Purge CN name
flgLoop = "Y"
Else
flgLoop = "N" ' Set all done flag
End If

Loop Until flgLoop = "N"

End Sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Main Code of Program '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set objConnection = CreateObject("ADODB.Connection") ' Create a Connection
object in memory
objConnection.Open "Provider=ADsDSOObject;" ' Open the Connection
object using the ADSI OLE DB provider

Set objCommand = CreateObject("ADODB.Command") 'Create an ADO Command
object in memory, and assign the Command _
objCommand.ActiveConnection = objConnection ' object's
ActiveConnection property to the Connection object

objCommand.Properties("Page Size") = 100
objCommand.Properties("Size Limit") = 3000

objCommand.CommandText = _
"<LDAP://dc=your
domain,dc=com>;(objectCategory=user);sAMAccountName,distinguishedName,name,w
henCreated,homeDirectory,scriptPath,displayName;subtree"

Set objRecordSet = objCommand.Execute ' Run the query by
calling the Execute method of the Command object

cntX = 0
cntY = 0

While Not objRecordSet.EOF
txtName = lcase(objRecordSet.Fields("distinguishedName")) '
Access each record in objRecordSet
txtSvName = txtName

ReDim Preserve arySvCN(cntX)
ReDim Preserve aryWhen(cntX) ' Save when
account created
ReDim Preserve aryHomeDirectory(cntX)
ReDim Preserve aryScriptPath(cntX)
ReDim Preserve arydisplayName(cntX)
aryWhen(cntX) = lcase(objRecordSet.Fields("whenCreated"))
aryHomeDirectory(cntX) = lcase(objRecordSet.Fields("homeDirectory"))
aryScriptPath(cntX) = lcase(objRecordSet.Fields("scriptPath"))
arydisplayName(cntX) = lcase(objRecordSet.Fields("displayName"))

cntLen = Len(txtName)
txtName = Left(txtName,(cntLen-18)) ' Provides the name w/o
dc=Your Domain,dc=com
cntLen = Len(txtName)-3
txtName = Right(txtName,cntLen) ' Drops the Container
Type Name
cntComma = Instr(txtName,",") - 1 ' Find the end of the
name
txtCN = Left(txtName,cntComma) ' Pull the Name out of
the Distinguished Name

aryCN(cntX, cntY) = lcase(objRecordSet.Fields("sAMAccountName")) '
Save Name
arySvCN(cntX) = txtSvName ' Save Distinguished
Name
cntY = cntY + 1 ' increment table
counter
cntRight = Len(txtName) - (cntComma + 1) ' Get to start of next
part of name
txtName = Right(txtName,cntRight) ' Purge CN name

Call Stripper ' Build table of the
context of the user

cntX = cntX + 1
cntY = 0

objRecordSet.MoveNext
Wend


Call AvailableDCs ' Go get the DC's in the
domain

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Create a file on the c drive '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set fso = CreateObject("Scripting.FileSystemObject")
set ts = fso.CreateTextFile("c:\users.txt", True)

For cntL = 0 to 500 ' Find out how many
columns used
If aryContainer(cntL) = "" Then
Exit For
End If
Next

cntColumns = cntL

ts.write("Logon Name; Context")
'For cntO = 1 to cntColumns - 2 ' used to add headers for
ou
' ts.write("; OU")
'Next
ts.write("; Header OU") ' Remove for multiple
OU's
ts.writeline("; Last Logon Date; Creation Date; Home Folder; Script; Display
Name; Password Not Needed; Password Does Not Expire; Expired Password;
Account Is Disabled")

For cntL = 0 to 9999 ' Cycle through all
users found
If aryCN(cntL,0) = "" Then ' Quit once end found
Exit For
End If

ts.write(aryCN(cntL,0)) & "; " ' Output users logon
name
ts.write(arySvCN(cntL)) & "; " ' Output full context of
user

ts.write(aryContainer(aryCN(cntL,1))) ' Output users Home OU


' code will enumurate all the individual columns from within the context
' For cntM = 1 to 11
' If aryCN(cntL,cntM) > "" Then
' ts.write ("; ")
' ts.write(aryContainer(aryCN(cntL,cntM))) ' Output the context of
this user
' Else
' Exit For ' No records left to
process
' End If
' Next
'
' If cntColumns > cntM Then ' Align Columns
' For cntO = 1 to cntColumns - cntM
' ts.write("; ")
' Next
' End If

Call LastTime ' Sniff Out Last Time
logged on

If nLatestDate <> "1/1/1601" Then
ts.write("; " & nLatestDate)
Else
ts.write("; ")
End If

ts.write("; ") ' Date Account Was
Created
ts.write(aryWhen(cntL))


ts.write("; ") ' Home folder location
If aryHomeDirectory(cntL) > "" Then
ts.write(aryHomeDirectory(cntL))
Else
ts.write(" ")
End If

ts.write("; ")

If aryScriptPath(cntL) > "" Then
ts.write(aryScriptPath(cntL))
Else
ts.write(" ")
End If

ts.write("; ")

If arydisplayName(cntL) > "" Then
ts.write(arydisplayName(cntL))
Else
ts.write(" ")
End If

If aryContainer(aryCN(cntL,1)) <> "ServiceAccounts" Then
on error resume next
Set usr = GetObject("WinNT://gob/" & aryCN(cntL,0))
flag = usr.Get("UserFlags")

If flag AND ADS_UF_PASSWD_NOTREQD Then
ts.write("; y")
Else
ts.write("; ")
End If

If flag AND ADS_UF_DONT_EXPIRE_PASSWD Then
ts.write("; y")
Else
ts.write("; ")
End If

If flag AND ADS_UF_PASSWORD_EXPIRED Then
ts.write("; y")
Else
ts.write("; ")
End If

If flag AND ADS_UF_ACCOUNTDISABLE Then
ts.write("; y")
Else
ts.write("; ")
End If
End If

ts.writeline() ' Start a newline

Next

objConnection.Close


--

Paul Bergson MCT, MCSE, MCSA, CNE, CNA, CCA

This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jerold Schulman

I have a native windows 2003 domain. I want to query active directory for
users whose lastlogon attribute is older than 60 days, but I am not sure how
to begin. I have tried building a query from scratch, but I never see
LastLogon as a field that I can select. Any information about how to
accomlish this would be appreciated. Thanks!


See tip 8080 in the 'Tips & Tricks' at http://www.jsiinc.com

Jerold Schulman
Windows: General MVP
JSI, Inc.
http://www.jsiinc.com
 
G

Guest

Would it be possible to email me that script (drop the VBS extension)? When
it was pasted in the post it was word wrapped and I am having alot of
problems debugging it. I am sorry to bother! Thank you for your help!

(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top