vbScript – List All Members Of Sensitive Groups: Schema, Enterprise and Domain Admins

Download Script: AD-Admin-Audit
Update 2011.06.21: I found a missing line in this script keeping it from running. I fixed that in the code below. I also added a downloadable zip file with the script to help with the formatting issues caused when copying and pasting directly from the site.

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:

  1. Enumerate all domains in the forest
  2. Loop through each domain
  3. Execute LDAP query against each domain
  4. Loop through LDAP query results
  5. 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
' UPDATED: 2011.06.21
' USAGE  : cscript /nologo AD-AdminAudit.vbs
' 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.
'==========================================================================

Option Explicit

'Define Constants
Const adUseClient = 3
Const ForWriting = 2

'Set the path and filename for the dump of sensitive users
'  Folder must exist!
Dim fileTemp : fileTemp = "C:AD Admin Audit.txt"

' Create tmp file and report file
Dim objFSO, objTempFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTempFile = objFSO.OpenTextFile(fileTemp, ForWriting, True)

' Query RootDSE and return array with all AD domains in forest
Dim adoCommand, adoConnection, objRootDSE
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.cursorLocation = adUseClient
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
Set objRootDSE = GetObject("LDAP://RootDSE")

' Build the LDAP Query
Dim strBase, strFilter, strAttrs, strScope, strQuery
strBase   =  ";"
strFilter = "(objectcategory=domainDNS);"
strAttrs  = "distinguishedName;"
strScope  = "subtree"
strQuery = strBase & strFilter & strAttrs & strScope

' Set Query parameters
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 50
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

' Execute the query
Dim adoRecordSet : Set adoRecordSet = adoCommand.Execute

' Start Loop
Do Until adoRecordSet.EOF
	' Parse ad search results to create well formed DNS domain
	Dim strDomain
	strDomain = Replace(adoRecordSet.Fields(0).Value,"DC=","")
	strDomain = Replace(strDomain,",",".")
	Call GrpAll(strDomain)
	adoRecordSet.MoveNext
Loop
adoRecordSet.Close
adoConnection.Close

Private Function GrpAll(byVal strDomain)
	' 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.
	Dim adoComm, adoConn
	Set adoComm = CreateObject("ADODB.Command")
	Set adoConn = CreateObject("ADODB.Connection")
	adoConn.Provider = "ADsDSOObject"
	adoConn.cursorLocation = adUseClient
	adoConn.Open "Active Directory Provider"
	adoComm.ActiveConnection = adoConn
	
	strBase   = ";"
	strFilter = "(&(objectCategory=group)(|((name=Enterprise Admins*)(name=Domain Admins*)(name=Schema Admins*))));"
	strAttrs  = "name,member;"
	strScope  = "subtree"
	
	strQuery = strBase & strFilter & strAttrs & strScope
	adoComm.CommandText = strQuery
	adoComm.Properties("Page Size") = 5000
	adoComm.Properties("Timeout") = 30
	adoComm.Properties("Cache Results") = False
	
	Dim adoRS : Set adoRS = adoComm.Execute
	
	objTempFile.WriteLine "Group report for domain: " & strDomain
	
	adoRS.MoveFirst
	
	Do Until adoRS.EOF
		Dim strMember
		objTempFile.WriteLine vbTab & adoRS.Fields(0).Value
		For Each strMember in adoRS.Fields(1).Value
			objTempFile.WriteLine vbTab & vbTab & strMember
		Next
		adoRS.MoveNext
	Loop
	
	adoRS.Close
	adoConn.Close
End Function

38 comments

  1. nice script, this helped with exactly what i wanted (ill just need to make it output to file) but its great, thanks

    1. 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

  2. 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…

    1. 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.

  3. Brilliant script! How, though, would you modify the strFilter line to output just Domain Admins?

  4. 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!

  5. How did you manage to get around the requirement for :
    adoRS.MoveFirst
    after executing
    Set adoRS = adoComm.Execute?

  6. 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.

  7. Aaron,

    If you paste in directly from the web page you get the URL codes as well as the text.

    i.e &amp 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.

  8. Set objRootDSE = GetObject (“LDAP://RootDSE”)

    What is this line in the program, I do not see another reference to it?

    1. 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

  9. 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.

  10. 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

  11. I tried running this script in a test environment however getting the below mentioned error.

    Script: C:Documents and SettingsAdministratorDesktopGet 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

  12. sorry. Doesn’t appear to be pasting.
    to strBase line add
    Quotes then Lessthan symbol then LDAP then : then 2 forward slashes then quotes then ampersand then x then ampersand then quotes then greaterthan sybmol then ; then quotes.
    Hope this makes sense

  13. I have the same problem as ravs. I don’t quite understand Brents reponse. Any help is appreciated.

    Thanks!

  14. When I put this script in my website I get an error on this line:

    Set objRootDSE = GetObject(“LDAP://RootDSE”)

    The error says “ActiveX component cannot create object.”

    How do I fix this?

  15. Looks fantastic…of course, I would know that for sure if it actually ran, instead of halting with the compilation error several people have pointed out. You put a heck of a lot of effort into writing this script–and it shows–could you possibly replace what is on this page with your final code that actually runs?

    Thanks!

    1. The script is updated and now works. I also put a download link since copy/paste doesn’t seem very reliable with ampersands.

  16. Hi,

    This is a nice script, also how I add the sAMAccountName to get logon name by using this script?

  17. Only below adition is enough?
    I try this but it doesn’t return user logon names:(

    strAttrs = “distinguishedName,sAMAccountName;”

  18. Hello!
    Running the script from 2003 DC and getting the error in line 101:
    For Each strMember in adoRS.Fields(1).Value

    the error:
    Object not a collection

    Please help!

  19. I run the script on Windows 2008 domains and it runs fine. When i run it on a Windows 2003 domain I get The following error:

    ADAdminAudit.vbs(101, 3) Microsoft VBScript runtime error: Object not a collection

    Any ideas?

    Dave

  20. Thank you for the script. I run the script on my win 2003 root server and getting run time error.

    Line: 100
    Char: 3
    Error: Object not a collection
    Code: 800A01c3
    Source: Microsoft VBScript runtime error

    Could you please help

  21. How difficult would it be to look up nested groups? I’ve seen people put groups inside of the domain admins (which your script at least shows the groups), but it would be icing on the cake if the script could turn around and show the members of these groups as well…

  22. Unable to read AD user data from
    domain code (DC)
    i am getting null values from adoRS.Fields(1).Value

  23. Unable to read AD user data from
    domain code (DC)
    i am getting null values from adoRS.Fields(1).Value

  24. Very nice script.. but there is an important missing point unfortunately.

    For example, if a group (MyAdmins) is member of the Domain Admins group, the script doesn’t display the members of MyAdmins and so … We dont really know who has the right.

    Otherwise nice script ! =)

  25. The script works great except I cant pull from my German domain. It uses Domänen-Admins instead of Domain Admins. I updated the group names in the script but it still does not pull the list

    Any ideas?

    Thank you,

    Richard

  26. Great Script! The only things I added are ‘Administrators’ to the filter and enumeration of the users in ‘Domain Admins’ whose Primary group is ‘Domain Admins’. I’m using this in a scheduled task to compare current list with previous list and to email if there are any changes. Thanks!

  27. Thankyou for the hours of saved time – just one question what do I need to add to get the output to contain the users “User Logon Name”?

    Cheers

  28. The scripts runs perfect, but it only list portion of domain admin users. It did not list all domain admin users. Did anynoe has same issue? Thanks.

Comments are closed.