>
> The line in the program LockedUsers.vbs that I meant to replace is further
> down, in the "For" loop that loops through the DC's. The complete code could
> look similar to below. This assumes the ou of interest is "ou=Sales":
> ==================
> Option Explicit
>
> Dim objRootDSE, strConfig, adoConnection, adoCommand, strQuery
> Dim adoRecordset, objDC
> Dim strDNSDomain, objShell, lngBiasKey, lngBias, k, arrstrDCs()
> Dim strDN, dtmDate, objDate, strUser, strNTName
> Dim objList1, objList2, objList3, j, intBadCount
> Dim strBase, strFilter, strAttributes, objWinNTUser
> Dim objTrans, strNetBIOSDomain, objDomain, arrstrNTNames()
> Dim lngHigh, lngLow
>
> ' Constants for the NameTranslate object.
> Const ADS_NAME_INITTYPE_GC = 3
> Const ADS_NAME_TYPE_NT4 = 3
> Const ADS_NAME_TYPE_1779 = 1
>
> ' Determine DNS domain name.
> Set objRootDSE = GetObject("LDAP://RootDSE")
> strDNSDomain = objRootDSE.Get("defaultNamingContext")
>
> ' Use the NameTranslate object to convert the DNS domain name
> ' to the NetBIOS domain name.
> Set objTrans = CreateObject("NameTranslate")
> objTrans.Init ADS_NAME_INITTYPE_GC, ""
> objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
> strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)
> ' Remove trailing backslash.
> strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)
>
> ' Find locked out user accounts in domain
> ' create array of sAMAccountName's
> Set objDomain = GetObject("WinNT://" & strNetBIOSDomain)
> objDomain.Filter = Array("user")
> k = 0
> For Each objWinNTUser In objDomain
> If (objWinNTUser.IsAccountLocked = True) Then
> ReDim Preserve arrstrNTNames(k)
> arrstrNTNames(k) =
objWinNTUser.name
> k = k + 1
> End If
> Next
>
> If (k = 0) Then
> Wscript.Echo "No user accounts locked out in domain"
> Wscript.Quit
> End If
>
> ' Use dictionary objects to track latest badPasswordTime,
> ' badPwdCount, and Domain Controller for each locked out user.
> Set objList1 = CreateObject("Scripting.Dictionary")
>
objList1.CompareMode = vbTextCompare
> Set objList2 = CreateObject("Scripting.Dictionary")
>
objList2.CompareMode = vbTextCompare
> Set objList3 = CreateObject("Scripting.Dictionary")
>
objList3.CompareMode = vbTextCompare
>
> ' Obtain local Time Zone bias from machine 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
>
> ' Determine configuration context.
> strConfig = objRootDSE.Get("configurationNamingContext")
>
> ' 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 = "
"
> 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
> ' DNS host names 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
>
> ' Use ADO to retrieve all user objects from each Domain Controller.
> strFilter = "(&(objectCategory=person)(objectClass=user))"
> strAttributes = "distinguishedName,sAMAccountName," _
> & "badPasswordTime,badPwdCount"
> For k = 0 To Ubound(arrstrDCs)
> strBase = ""
> 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
> strNTName = adoRecordset.Fields("sAMAccountName").Value
> ' Check each user to see if in array of locked out accounts.
> For j = 0 To UBound(arrstrNTNames)
> If (UCase(strNTName) = UCase(arrstrNTNames(j))) Then
> ' User locked out, retrieve badPasswordTime.
> strDN = adoRecordset.Fields("distinguishedName").Value
> intBadCount = adoRecordset.Fields("badPwdCount").Value
> On Error Resume Next
> Set objDate =
> adoRecordset.Fields("badPasswordTime").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 (objList1.Exists(strDN) = True) Then
> If (dtmDate > objList1.Item(strDN)) Then
> ' Later badBadPasswordTime found, save info from
> this DC.
> objList1.Item(strDN) = dtmDate
> objList2.Item(strDN) = intBadCount
> objList3.Item(strDN) = arrstrDCs(k)
> End If
> Else
> ' First time user found, save info from this DC.
> objList1.Add strDN, dtmDate
> objList2.Add strDN, intBadCount
> objList3.Add strDN, arrstrDCs(k)
> End If
> End If
> Next
> adoRecordset.MoveNext
> Loop
> adoRecordset.Close
> End If
> Next
>
> ' Output information on each locked out user.
> For Each strUser In objList1.Keys
> Wscript.Echo strUser & " ; " & objList1.Item(strUser) & " ; " _
> & objList2.Item(strUser) & " ; " & objList3.Item(strUser)
> Next
>
> ' Clean up.
> adoConnection.Close
> Set objRootDSE = Nothing
> Set adoConnection = Nothing
> Set adoCommand = Nothing
> Set adoRecordset = Nothing
> Set objTrans = Nothing
> Set objDomain = Nothing
> Set objWinNTUser = Nothing
> Set objDC = Nothing
> Set objDate = Nothing
> Set objList1 = Nothing
> Set objList2 = Nothing
> Set objList3 = Nothing
> Set objShell = Nothing
> ===============
> In the statement:
>
> strBase = ""
>
> you need to modify "ou=Sales" to match the OU you are interested in.
> Everything else should stay the same.
>
> --
> Richard Mueller
> Microsoft MVP Scripting and ADSI
> Hilltop Lab - http://www.rlmueller.net
> --
>
>
>