Update 2009.04.16: At the request of a commenter, I added a couple lines to the script that will dump the output to a text file in the root of the C: drive. I also corrected a couple errors in the script.
I was tasked to get a dump of all the users in our Schema Admins, Enterprise Admins and Domain Admins for our Forest. I started thinking about it and realized a couple things. Two of the three groups reside at the forest root while the Domain Admins group exists for every domain in the forest. This meant I would need to enumerate every domain and depending on the domain, enumerate either all three groups or just one.
My thinking was overly complex and I realized this halfway through writing a new script. Using the power of LDAP, I can use a logical “or” (|) statement. When run against a domain, it would always return “Domain Admins” since it will always exist in an AD domain. When it is run against the forest root domain, it would also return the “Enterprise Admins” group and “Schema Admins” group. Here is the LDAP query:
(&(objectCategory=group)(|((name=Enterprise Admins*)(name=Domain Admins*)(name=Schema Admins*))))
At this point, all I need to do is this:
- Enumerate all domains in the forest
- Loop through each domain
- Execute LDAP query against each domain
- Loop through LDAP query results
- Dump membership of each group
The script below does just that. I hope some find it useful. There is no configuration necessary. You should be able to just run it from your environment as no domain references (or really anything) is hard coded. The only thing you may want to add to or remove from is the LDAP filter. Cheers!
'========================================================================== ' VBScript Source File ' NAME: Active Directory Admin Audit ' AUTHOR: Andrew J Healey ' DATE : 2009.04.16 ' COMMENT: This script will check all the domains within a forest ' and report all the members of the following groups: Schema ' Admins, Enterprise Admins and Domain Admins. See notes to ' expand on the groups. '========================================================================== 'Define Constants Const adUseClient = 3 Const ForWriting = 2 'Set the path and filename for the dump of sensitive users ' Folder must exist! fileTemp = "C:\AD Admin Audit.txt" 'Create tmp file and report file Set objFSO = CreateObject("Scripting.FileSystemObject") Set objTempFile = objFSO.OpenTextFile(fileTemp, ForWriting, True) 'Query RootDSE and return array with all AD domains in forest Set adoComm = CreateObject("ADODB.Command") Set adoConn = CreateObject("ADODB.Connection") adoConn.Provider = "ADsDSOObject" adoConn.cursorLocation = adUseClient adoConn.Open "Active Directory Provider" adoComm.ActiveConnection = adoConn Set objRootDSE = GetObject("LDAP://RootDSE") strBase = "<GC://" & objRootDSE.Get("rootDomainNamingContext") & ">;" strFilter = "(objectcategory=domainDNS);" strAttrs = "distinguishedName;" strScope = "subtree" strQuery = strBase & strFilter & strAttrs & strScope adoComm.CommandText = strQuery adoComm.Properties("Page Size") = 50 adoComm.Properties("Timeout") = 30 adoComm.Properties("Cache Results") = False Set adoRS = adoComm.Execute 'Start Loop Do Until adoRS.EOF 'Parse ad search results to create well formed DNS domain strDomain = Replace(adoRS.Fields(0).Value,"DC=","") strDomain = Replace(strDomain,",",".") Call GrpAll(strDomain) adoRS.MoveNext Loop adoRS.Close adoConn.Close wscript.quit Function GrpAll(x) 'To search for more groups, edit the "strFilter" line. It uses a simple ' LDAP or (|) so multiple groups can be added. It uses ADO record sets ' to loop so it doesn't have to find all of them, just one. Every domain ' will contain at least the Domain Admins group. Set adoCommand = CreateObject("ADODB.Command") Set adoConnection = CreateObject("ADODB.Connection") adoConnection.Provider = "ADsDSOObject" adoConnection.cursorLocation = adUseClient adoConnection.Open "Active Directory Provider" adoCommand.ActiveConnection = adoConnection strBase = ";" strFilter = "(&(objectCategory=group)(|((name=Enterprise Admins*)" & _ "(name=Domain Admins*)(name=Schema Admins*))));" strAttrs = "name,member;" strScope = "subtree" strQuery = strBase & strFilter & strAttrs & strScope adoCommand.CommandText = strQuery adoCommand.Properties("Page Size") = 5000 adoCommand.Properties("Timeout") = 30 adoCommand.Properties("Cache Results") = False Set adoRecordset = adoCommand.Execute objTempFile.WriteLine "Group report for domain: " & x adoRecordset.MoveFirst Do Until adoRecordset.EOF objTempFile.WriteLine vbTab & adoRecordset.Fields(0).Value For Each strMember in adoRecordset.Fields(1).Value objTempFile.WriteLine vbTab & vbTab & strMember Next adoRecordset.MoveNext Loop adoRecordset.Close adoConnection.Close End Function
nice script, this helped with exactly what i wanted (ill just need to make it output to file) but its great, thanks
John,
I am glad it was helpful. All you need to do is run the script from the command line and pipe the output to a text file: cscript.exe “List All Members.vbs” > list.txt
Can you please help me. How do i make the output file in the script body – i cannot type “List All Members.vbs” > list.txt” – I just can run the script…
Check out the script. I updated it so it will dump the information to a text file. I also fixed some things. Let me know if you have problems running the script. This should allow you to double click the script and capture the output in a text file.
Brilliant script! How, though, would you modify the strFilter line to output just Domain Admins?
Great script but I’m not sure why the disabled members of the Enterprise and Schema Admins groups are listed, but not the disabled members of Domain Admins. For consistency, it would be
better if the disabled members would be listed in all three groups.
Keep up the great work!
Sweet, really nice piece of work. Thank you.
How did you manage to get around the requirement for :
adoRS.MoveFirst
after executing
Set adoRS = adoComm.Execute?
I am unable to run this script. I get the error:
Line: 38
Char: 24
Error: Expected end of statement
Code: 800A0401
Source: Microsoft VBScript compilation error
This was on two different Windows Server 2003 DCs. I copied the script whole from your post and put it in a VBS file. Please assist. Thank you.
Aaron,
If you paste in directly from the web page you get the URL codes as well as the text.
i.e & instead of just the & char
so a string concatination would look like :
string1 amp&; string2
instead of string1 & string2
So, relace all the amp&; with the character & and you will be good to go.
Set objRootDSE = GetObject (“LDAP://RootDSE”)
What is this line in the program, I do not see another reference to it?
Williams,
Thanks for catching that. It is fixed in the post now. The line with “strBase” should have been:
strBase = "<GC://" & objRootDSE.Get("rootDomainNamingContext") & ">;"Andrew
The Script is not running. I am trying to run the Script on one of of our Domain Controller Server / Member Server but getting error. “One or more errors occured during processing of command”. Getting error in this line:
Set adoRecordset = adoCommand.Execute
Our DC is Windows 2003 SP2.Please help.
Hi Andrew,
Even i am facing the same error;
“One or more errors occured during processing of command”. Getting error in this line:
Set adoRecordset = adoCommand.Execute
Our DC is Windows 2003 SP2.Please help.
Regards,
Gururaj
I tried running this script in a test environment however getting the below mentioned error.
Script: C:\Documents and Settings\Administrator\Desktop\Get Admins List.vbs
Line: 82
Char: 2
Error: One or more errors occurred during processing of command.
Code: 80040E14
Source: Provider
Any help will be greatly appreciated.
Thanks,
Ravs