Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Display All Locked Accounts in an OU

Status
Not open for further replies.

drweb

IS-IT--Management
Apr 17, 2002
26
US
Hey All,

I have thi script below I used from its source

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 seach the entire domian like this script is doing due to logistics.

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

' 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 - ' 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
 
You can simply do it like this. (This is all brain code with the reference of physically looking at rm's page as posted, but not necessarily following him.)
[tt]
dim sou, sdnsname, snbdomain, sbase, sfilter, sattr, sscope, ssamaccountname
dim orootdse, otrans, conn, ocommand, rs, ouser

[blue]'you input here to complete the base path, it can be deeper in the hierarchy
'sou is the rdn chain until you reach the domain
sou="ou=rnd"
[/blue]
set orootdse=getobject("LDAP://RootDSE")
sdnsname=orootdse.get("defaultNamingContext")
set orootdse=nothing

set otrans=createobject("NameTranslate")
otrans.init 3,""
otrans.set 1,sdnsname
snbdomain=otrans.get(3) 'with trailing slash
set otrans=nothing

sbase="<LDAP://" & sou & "," & sdnsname & ">"
sfilter="(objectCategory=person)(objClass=user)"
sattr="adspath,distinguishedname,samaccountname"
sscope="subtree"

set conn=createobject("adodb.connection")
conn.provider="ADsDSOObject"
conn.open="Active Directory Provider"

set ocommand=createobject("adodb.command")
ocommand.activeconnection=connection
ocommand.commandtext=sbase & ";" & sfilter & ";" & sattr & ";" & sscope
ocommand.properties("page size")=1000
ocommand.properties("timeout")=60
ocommand.properties("cache results")=false

set rs=ocommand.execute

do until rs.eof
ssamaccount=rs.field("samaccountname")
set ouser=getobject("WinNT://" & snbdomain & ssamaccountname,"user")
if ouser.isaccountlocked then
'elaborate to persist the data if you need to
wscript.echo "You have found a locked-out user." & vbcrlf "User name : " & ouser.name & _
"Distinguished name : " & rs.field("distinguishedname") & _
"sAMAccountName : " & rs.field("samaccountname")
end if
rs.movenext
loop

rs.close
set rs=nothing
set ocommand=nothing
conn.close
set conn=nothing
[/tt]
 
Thanks you for your reply Tsuji,

I will try this first thind Monday,
Also I read somewhere when using the adodb.command it is only read-only access but using the WinNT provider later in your version I can unlock the users it finds locked. Am I thinking this out correctly?
 
Upon re-reading, I found a hasty mistake. The trailing is of course $ for m/c account. So I should revise two lines.
[tt]
snbdomain=otrans.get(3) 'with trailing[red] $ m/c account
snbdomain=left(snbdomain,len(snbdomain)-1)[/red]
[/tt]
and consequently this too.
[tt]
set ouser=getobject("WinNT://" & snbdomain & [red]"/" &[/red] ssamaccountname,"user")
[/tt]
and a typos
[tt]
ocommand.activeconnection=[red]conn[/red]
[/tt]
I would relist the whole thing with some cosmetic touch as well.
Code:
dim sdnsname,snbdomain,sbase,sfilter,sattr,sscope
dim sou,ssamacount
dim orootdse,otrans,conn,ocommand,rs,ouser

[blue]'you input here to complete the base path, it can be deeper in the hierarchy
'sou is the rdn chain until you reach the domain
sou="ou=rnd"[/blue]

set orootdse=getobject("LDAP://RootDSE")
sdnsname=orootdse.get("defaultNamingContext")
set orootdse=nothing

set otrans=createobject("NameTranslate")
with otrans
    .init 3,""
    .set 1,sdnsname
    snbdomain=.get(3)    'with trailing $ m/c account
    snbdomain=left(snbdomain,len(snbdomain)-1)
end with
set otrans=nothing

sbase="<LDAP://" & sou & "," & sdnsname & ">"
sfilter="(objectCategory=person)(objClass=user)"
sattr="adspath,distinguishedname,samaccountname"
sscope="subtree"

set conn=createobject("adodb.connection")
with conn
    .provider="ADsDSOObject"
    .open="Active Directory Provider"
end with

set ocommand=createobject("adodb.command")
with ocommand
    .activeconnection=conn
    .commandtext=sbase & ";" & sfilter & ";" & sattr & ";" & sscope
    .properties("page size")=1000
    .properties("timeout")=60
    .properties("cache results")=false
end with

set rs=ocommand.execute

do until rs.eof
    ssamaccount=rs.field("samaccountname")
    set ouser=getobject("WinNT://" & snbdomain & "/" &  ssamaccountname,"user")
    if ouser.isaccountlocked then
        'elaborate to persist the data if you need to
        wscript.echo "You have found a locked-out user." & vbcrlf "User name : " & ouser.name & _
            "Distinguished name : " & rs.field("distinguishedname") & _
            "sAMAccountName : " & rs.field("samaccountname")
    end if
    rs.movenext
loop

rs.close
set rs=nothing
set ocommand=nothing
conn.close
set conn=nothing
(Try and see what still left to change.)
 
Amendment:
Still this left to change to the corresponding line!
[tt]set ouser=getobject("WinNT://" & snbdomain & "/" & ssamaccountname [red]& ",[/red]user")[/tt]
 
Thanks for all the help.

I am getting this error that I cannot get past
on this line:
set rs=ocommand.execute

Error: One or more errors occured during the procesing of comand
Code: 80080E14
Source : Provider

I assume it points to the ldap connection but when I echo sBase is is pointing to the exact OU i want to start in.

Any ideas?


Clay
 
Sorry, I type this shorthanded and thinking of something else. Obviously, it is this.
>[tt]sfilter="(objectCategory=person)(objClass=user)"[/tt]
[tt]sfilter="[red](&[/red](objectCategory=person)(obj[red]ect[/red]Class=user)[red])[/red]"[/tt]
 
Great, I know I would not have caught that.

>ssamaccount=rs.field("samaccountname")
I changed it to ssamaccount=rs.fields("samaccountname") after getting unsupported object

but then get Null error on next line
Set ouser = GetObject("WinNT://" & snbdomain & "/" & ssamaccountname & ",user")
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top