Display All Locked Accounts in an OU

S

script-newb

Hey All,

I have this script below I used from its source
http://www.rlmueller.net

I am having a very hard time to alter this to make it search a
particular OU and its sub-ou's for locked out accounts. I cannot
search the entire domain like this script is doing due to logistics.
FWIW:
I know that when a user gets locked out in my domain it simultaneously
gets locked on a local DC and on our Root DC then takes 10-15 minutes
to show locked on all other DC's (10 total). I see this script is
getting all attributes from all DC's but I only would need it to look
at the 2 out of my 10 DC's since I know they would be the two most
accurate.
**I only mentions the above^^^, due to not wanting to take too much
bandwidth searching all DC's, if it is minuscule then disregard and
let me know.

I an somewhat of a newb at adsi-vbscript-wsh scripting to sorry for the
long windedness of this thread.

Any and all help would be appreciated.
Anybody have an easier method? (must use vbscript)

Clay

-------------- Script -------------------
' LockedUsers.vbs
' VBScript program to find user accounts in Active Directory that are
' locked out, then determine when they were locked out and on which
' Domain Controller.
'
' ------------------------------------------------------------
' Copyright (c) 2003 Richard L. Mueller
' Hilltop Lab web site - http://www.rlmueller.net
' Version 1.0 - March 17, 2003
' Version 1.1 - May 9, 2003 - Account for error in IADsLargeInteger
' property methods HighPart and Lowpart.
' Version 1.2 - January 25, 2004 - Modify error trapping.
' Version 1.3 - March 18, 2004 - Modify NameTranslate constants.
'
' 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, objConnection, objCommand, strQuery
Dim objRecordSet, objDC
Dim strDNSDomain, objShell, lngBiasKey, lngBias, k, arrstrDCs()
Dim strDN, dtmDate, objDate, lngDate, 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 objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open = "Active Directory Provider"
objCommand.ActiveConnection = objConnection

strBase = "<LDAP://" & strConfig & ">"
strFilter = "(objectClass=nTDSDSA)"
strAttributes = "AdsPath"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 60
objCommand.Properties("Cache Results") = False

Set objRecordSet = objCommand.Execute

' Enumerate parent objects of class nTDSDSA. Save Domain Controller
' DNS host names in dynamic array arrstrDCs.
k = 0
Do Until objRecordSet.EOF
Set objDC = _
GetObject(GetObject(objRecordSet.Fields("AdsPath")).Parent)
ReDim Preserve arrstrDCs(k)
arrstrDCs(k) = objDC.DNSHostName
k = k + 1
objRecordSet.MoveNext
Loop

' 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 = "<LDAP://" & arrstrDCs(k) & "/" & strDNSDomain & ">"
strQuery = strBase & ";" & strFilter & ";" & strAttributes _
& ";subtree"
objCommand.CommandText = strQuery
On Error Resume Next
Set objRecordSet = objCommand.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 objRecordSet.EOF
strNTName = objRecordSet.Fields("sAMAccountName")
' 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 = objRecordSet.Fields("distinguishedName")
lngDate = objRecordSet.Fields("badPasswordTime")
intBadCount = objRecordSet.Fields("badPwdCount")
On Error Resume Next
Set objDate = lngDate
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) Then
If dtmDate > objList1(strDN) Then
' Later badBadPasswordTime found, save info from this DC.
objList1(strDN) = dtmDate
objList2(strDN) = intBadCount
objList3(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
objRecordSet.MoveNext
Loop
End If
Next

' Output information on each locked out user.
For Each strUser In objList1
Wscript.Echo strUser & " ; " & objList1(strUser) & " ; " _
& objList2(strUser) & " ; " & objList3(strUser)
Next

' Clean up.
objConnection.Close
Set objRootDSE = Nothing
Set objConnection = Nothing
Set objCommand = Nothing
Set objRecordSet = 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

--------------End Script----------------

Thanks again
 
J

Joe Richards [MVP]

If you don't actually need a full script, you might look at unlock.exe which
blows the socks off the method used here. In fact, you could probably search
every DC's entire domain context in the time it takes the below to run on one or
two DCs for a single OU. It will definitely generate a lot less network traffic.

Check out unlock at http://www.joeware.net/win/free/tools/unlock.htm
 
S

script-newb

Thanks for the reply Joe,

With Unlock.exe , when ran what kind of DC search order does it follow.
( ie. Root first or the one I authenticated to first)

Also, I want to outpulse the found information to a text file or
inside and HTA does the executable support >output.txt or similar
functions?

Thanks,
Clay
 
J

Joe Richards [MVP]

It looks at whatever DC you point it at in the first parameter. If you put in a
.. it uses the default DC.

Yes you can pipe the output to another file with something like

unlock . * -view >somefile.txt

If you just want a specific OU, add the -b option. Type unlock for usage.

joe
 
S

script-newb

Thanks for the insight.

Unlock.exe works fine if I only used it here locally but I need
something I can spread around in our company to use. It has to be a in
a vbscript or HTA form. I know I can call the exe from either one of
those but I need it all inclusive. Can't have exe's floating around
unless the code has been sent through the change control board
 

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

Top