Hi all. I've been looking into a task I have to carry out on a large AD network whereby they want to do things to users who haven't been seen on the network for X time (eg 6 months). Initially they want to mark the account desc with a prefixed [D] and disable the account - also stuff like hiding the mailbox from the exchange mail list. A week later they want to move the account to a disabled OU and do other stuff like remove them from groups etc.
I've found a tool called oldcmp which I think was just for computers. I also found a script for ADLastSeenUsers which I modified to be users or computers and to sort alphabetically in a text file - see below. I haven't found much else to be helpful.
My main problem is I'm not sure I can trust all the users marked as NEVER last seen, or the last seen dates. I'm also unsure how to do what needs doing rather than just writing the name/lastseentime to a textfile which is what I do currently.
Mainly I'm thinking people must have to do stuff like this all the time so there should be a tool out there for it or good tutorials to follow for DIYing the scripts etc.
Does anyone have any ideas? TIA
_________________________________
Leozack
I've found a tool called oldcmp which I think was just for computers. I also found a script for ADLastSeenUsers which I modified to be users or computers and to sort alphabetically in a text file - see below. I haven't found much else to be helpful.
My main problem is I'm not sure I can trust all the users marked as NEVER last seen, or the last seen dates. I'm also unsure how to do what needs doing rather than just writing the name/lastseentime to a textfile which is what I do currently.
Mainly I'm thinking people must have to do stuff like this all the time so there should be a tool out there for it or good tutorials to follow for DIYing the scripts etc.
Does anyone have any ideas? TIA
Code:
' LastLogon.vbs
' VBScript program to determine when each user in the domain last logged
' on.
'
' Edited to sort alphabetically and output text file by GM@Mouchel June 11
'
' ----------------------------------------------------------------------
' Copyright (c) 2002-2010 Richard L. Mueller
' Hilltop Lab web site - [URL unfurl="true"]http://www.rlmueller.net[/URL]
' Version 1.0 - December 7, 2002
' Version 1.1 - January 17, 2003 - Account for null value for lastLogon.
' Version 1.2 - January 23, 2003 - Account for DC not available.
' Version 1.3 - February 3, 2003 - Retrieve users but not contacts.
' Version 1.4 - February 19, 2003 - Standardize Hungarian notation.
' Version 1.5 - March 11, 2003 - Remove SearchScope property.
' Version 1.6 - May 9, 2003 - Account for error in IADsLargeInteger
' property methods HighPart and LowPart.
' Version 1.7 - January 25, 2004 - Modify error trapping.
' Version 1.8 - July 6, 2007 - Modify how IADsLargeInteger interface
' is invoked.
' Version 1.9 - December 29, 2009 - Output "Never" if no date.
' Version 1.10 - November 6, 2010 - No need to set objects to Nothing.
'
' Because the lastLogon attribute is not replicated, every Domain
' Controller in the domain must be queried to find the latest lastLogon
' date for each user. The lastest date found is kept in a dictionary
' object. The program first uses ADO to search the domain for all Domain
' Controllers. The AdsPath of each Domain Controller is saved in an
' array. Then, for each Domain Controller, ADO is used to search the
' copy of Active Directory on that Domain Controller for all user
' objects and return the lastLogon attribute. The lastLogon attribute is
' a 64-bit number representing the number of 100 nanosecond intervals
' since 12:00 am January 1, 1601. This value is converted to a date. The
' last logon date is in UTC (Coordinated Univeral Time). It must be
' adjusted by the Time Zone bias in the machine registry to convert to
' local time.
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.
Option Explicit
Dim objRootDSE, strConfig, adoConnection, adoCommand, strQuery
Dim adoRecordset, objDC
Dim strDNSDomain, objShell, lngBiasKey, lngBias, k, arrstrDCs()
Dim strDN, dtmDate, objDate, objList, strUser
Dim strBase, strFilter, strAttributes, lngHigh, lngLow
'-----------------------------------------v
'Open up the path to save the information into a text file
Dim myFSO, WriteStuff
'-----------------------------------------^
' Use a dictionary object to track latest lastLogon for each user.
Set objList = CreateObject("Scripting.Dictionary")
objList.CompareMode = vbTextCompare
' Obtain local Time Zone bias from machine registry.
' This bias changes with Daylight Savings Time.
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
' Determine configuration context and DNS domain from RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE")
strConfig = objRootDSE.Get("configurationNamingContext")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
' Use ADO to search Active Directory for ObjectClass nTDSDSA.
' This will identify all Domain Controllers.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
strBase = "<LDAP://" & strConfig & ">"
strFilter = "(objectClass=nTDSDSA)"
strAttributes = "AdsPath"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
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 Domain Controller
' AdsPaths in dynamic array 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
' Retrieve lastLogon attribute for each user on each Domain Controller.
For k = 0 To Ubound(arrstrDCs)
strBase = "<LDAP://" & arrstrDCs(k) & "/" & strDNSDomain & ">"
'-----------------------------------------------------v
strFilter = "(&(objectCategory=person)(objectClass=user))"
' Above line checks users - below line checks pcs
'strFilter = "(objectCategory=computer)"
'-----------------------------------------------------^
strAttributes = "distinguishedName,lastLogon"
strQuery = strBase & ";" & strFilter & ";" & strAttributes _
& ";subtree"
adoCommand.CommandText = strQuery
On Error Resume Next
Set adoRecordset = adoCommand.Execute
If (Err.Number <> 0) Then
On Error GoTo 0
Wscript.Echo "Domain Controller not available: " & arrstrDCs(k)
Else
On Error GoTo 0
Do Until adoRecordset.EOF
strDN = adoRecordset.Fields("distinguishedName").Value
On Error Resume Next
Set objDate = adoRecordset.Fields("lastLogon").Value
If (Err.Number <> 0) Then
On Error GoTo 0
dtmDate = #1/1/1601#
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/1601#
Else
dtmDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _
+ lngLow)/600000000 - lngBias)/1440
End If
End If
If (objList.Exists(strDN) = True) Then
If (dtmDate > objList(strDN)) Then
objList.Item(strDN) = dtmDate
End If
Else
objList.Add strDN, dtmDate
End If
adoRecordset.MoveNext
Loop
adoRecordset.Close
End If
Next
'----------------------------------------------------------v
Set myFSO = CreateObject("Scripting.FileSystemObject")
Set WriteStuff = myFSO.OpenTextFile("ADLastSawUsers.txt", 8, True)
dim objListSorted
Set objListSorted = objList
'SortDictionary objListSorted,dictKey
' Above line sorts by dates (badly, sorts as a string not a date)
' Below line sorts by name
SortDictionary objListSorted,dictKey
dim theName
'----------------------------------------------------------^
' Output latest lastLogon date for each user.
For Each strUser In objListSorted.Keys
If (objListSorted.Item(strUser) = CStr(#1/1/1601#)) Then
'----------------------------------------------------------v
'Wscript.Echo strUser & ";Never"
'WriteStuff.WriteLine(strUser & ";Never")
theName = Left(Mid(strUser,4),InStr(Mid(strUser,4),",")-1)
If (Len(theName) < 7) Then
theName = theName & "," & vbtab & vbtab & vbtab
ElseIf (Len(theName) < 15) Then
theName = theName & "," & vbtab & vbtab
Else
theName = theName & "," & vbtab
End If
WriteStuff.WriteLine(theName & "Never")
Else
'Wscript.Echo strUser & ";" & objList.Item(strUser)
'WriteStuff.WriteLine(strUser & ";" & objListSorted.Item(strUser))
theName = Left(Mid(strUser,4),InStr(Mid(strUser,4),",")-1)
If (Len(theName) < 7) Then
theName = theName & "," & vbtab & vbtab & vbtab
ElseIf (Len(theName) < 15) Then
theName = theName & "," & vbtab & vbtab
Else
theName = theName & "," & vbtab
End If
WriteStuff.WriteLine(theName & objListSorted.Item(strUser))
'----------------------------------------------------------^
End If
Next
'----------------------------------------------------------v
WriteStuff.Close
SET WriteStuff = NOTHING
SET myFSO = NOTHING
'----------------------------------------------------------^
' Clean up.
adoConnection.Close
'----------------------------------------------------------v
Const dictKey = 1
Const dictItem = 2
Function SortDictionary(objDict,intSort)
' declare our variables
Dim strDict()
Dim objKey
Dim strKey,strItem
Dim X,Y,Z
' get the dictionary count
Z = objDict.Count
' we need more than one item to warrant sorting
If Z > 1 Then
' create an array to store dictionary information
ReDim strDict(Z,2)
X = 0
' populate the string array
For Each objKey In objDict
strDict(X,dictKey) = CStr(objKey)
strDict(X,dictItem) = CStr(objDict(objKey))
X = X + 1
Next
' perform a shell sort of the string array
For X = 0 to (Z - 2)
For Y = X to (Z - 1)
If StrComp(strDict(X,intSort),strDict(Y,intSort),vbTextCompare) > 0 Then
strKey = strDict(X,dictKey)
strItem = strDict(X,dictItem)
strDict(X,dictKey) = strDict(Y,dictKey)
strDict(X,dictItem) = strDict(Y,dictItem)
strDict(Y,dictKey) = strKey
strDict(Y,dictItem) = strItem
End If
Next
Next
' erase the contents of the dictionary object
objDict.RemoveAll
' repopulate the dictionary with the sorted information
For X = 0 to (Z - 1)
objDict.Add strDict(X,dictKey), strDict(X,dictItem)
Next
End If
End Function
'----------------------------------------------------------^
_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);