List all the members of a group error when there are no members
Language: VB Script
Reference: Hey Scripting Guy! Script Center Home > Scripts > Active Directory > Groups > List All the Members of a Group
It has a problem when there are no members of the group! If there are no members of the group, it provides an erroneous result for that group. I see two choices... 1. pull up the membership property of each member and cross verify or 2. Somehow check the member property of the group to see if it's null. I would prefer the second option if someone knows how to code it. Here's my script so far...
' *****************************
' * List All Groups in the Domain and
' * List All Members of each Group
' *
' * Output to a text file on the user's desktop in the format:
' * group name <tab> type <tab> member name <tab> type
' * Prompt for text file name.
' *****************************
Const MY_DOMAIN = "dc=contoso,dc=com"
' *****************************
' Start Main
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const myPrompt = "Enter the Output filename (i.e. Groups.txt) that will be saved on your desktop:"
'Get filename to create and set it up to receive input
If UCase( Right( WScript.FullName, 12 ) ) = "\CSCRIPT.EXE" Then
WScript.StdOut.Write myPrompt & " "
strMyFileName = WScript.StdIn.ReadLine
Else
strMyFileName = InputBox( myPrompt )
End If
if strMyFileName = "" then
wscript.quit
end if
Set WshShell = CreateObject("WScript.Shell")
Set WshSysEnv = WshShell.Environment("PROCESS")
strMyFileName = WshSysEnv("USERPROFILE") & "\Desktop\" & strMyFileName
Set WshSysEnv = nothing
Set WshShell = nothing
Set objFSO = CreateObject("Scripting.FileSystemObject")
if objFSO.FileExists(strMyFileName) then
wscript.echo "That filename already exists"
wscript.quit
end if
Set objMyOutput = objFSO.OpenTextFile(strMyFileName, ForWriting, True)
' Enumerate the groups in the domain
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = _
"SELECT ADsPath, Name FROM 'LDAP://" & MY_DOMAIN & "' WHERE objectCategory='group'"Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Set objGroup = GetObject(objRecordSet.Fields("ADsPath").Value)
strGroupName = objRecordSet.Fields("Name").Value
If objGroup.GroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
strGroupDesc = "Domain local "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
strGroupDesc = "Global "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
strGroupDesc = "Universal "
Else
strGroupDesc = "Unknown "
End If
If objGroup.GroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
strGroupDesc = strGroupDesc & "Security group"
Else
strGroupDesc = strGroupDesc & "Distribution group"
End If
' Reference List all the members of a group
For Each strMemberOf in objGroup.Member
Set objMember = GetObject("LDAP://" & strMemberOf)
strMemberName = right(objMember.Name,len(objMember.Name)-3)
' wscript.echo strGroupName & vbcrlf & strGroupDesc & vbcrlf & strMemberName & vbcrlf & objMember.Class
objMyOutput.WriteLine(strGroupName & vbtab & strGroupDesc & vbtab & strMemberName & vbtab & objMember.Class)
Next
objRecordSet.MoveNext
Loop
objMyOutput.close
Answers
I have when you powershell guys do in one line what I did in an entire script, but mine still adds the type descriptions. I found out the hard way that set object = nothing does have its uses along with some error checking! Note to self... when looping a piece of vb script and setting an object in the loop, make sure and clear objects at the end of the loop before they get reused. It made a difference. I also added error checking of Err.Number to make sure the object.parameter existed and that cleaned up the output as well. I checked it against Active Directory and it cleared up the erroneous entries. The key was checking the error against E_ADS_PROPERTY_NOT_FOUND. Here's the result...
' *****************************
' * List All Groups in the Domain and
' * List All Members of each Group
' *
' * Output to a text file on the user's desktop in the format:
' * group name <tab> type <tab> member name <tab> type
' * Prompt for text file name.
' *****************************
' Variables
Const MY_DOMAIN = "dc=contoso,dc=com"
' *****************************
' Start Main
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
Const MYPROMPT = "Enter the Output filename (i.e. Groups.txt) that will be saved on your desktop:"
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFSO = CreateObject("Scripting.FileSystemObject")' Setup the output file
If UCase( Right( WScript.FullName, 12 ) ) = "\CSCRIPT.EXE" Then
WScript.StdOut.Write MYPROMPT & " "
strMyFileName = WScript.StdIn.ReadLine
Else
strMyFileName = InputBox( MYPROMPT )
End If
if strMyFileName = "" then
wscript.quit
end if
Set WshShell = CreateObject("WScript.Shell")
Set WshSysEnv = WshShell.Environment("PROCESS")
strMyFileName = WshSysEnv("USERPROFILE") & "\Desktop\" & strMyFileName
Set WshSysEnv = nothing
Set WshShell = nothing
if objFSO.FileExists(strMyFileName) then
'objFSO.DeleteFile(strMyFileName)
wscript.echo "That filename already exists"
wscript.quit
end if' Get a recordset of groups in AD
Set objMyOutput = objFSO.OpenTextFile(strMyFileName, ForWriting, True)
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = _
"SELECT ADsPath, Name FROM 'LDAP://" & MY_DOMAIN & "' WHERE objectCategory='group'"
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst' For each Group, Get group properties
Do Until objRecordSet.EOF
Set objGroup = GetObject(objRecordSet.Fields("ADsPath").Value)
strGroupName = objRecordSet.Fields("Name").Value
If objGroup.GroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
strGroupDesc = "Domain local "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
strGroupDesc = "Global "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
strGroupDesc = "Universal "
Else
strGroupDesc = "Unknown "
End If
If objGroup.GroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
strGroupDesc = strGroupDesc & "Security group"
Else
strGroupDesc = strGroupDesc & "Distribution group"
End If' Check if there are members
err.clear
arrMemberOf = objGroup.GetEx("Member")
If Err.Number = E_ADS_PROPERTY_NOT_FOUND then
' Write a line to the outputfile with group properties and no members
objMyOutput.WriteLine(strGroupName & vbtab & strGroupDesc & vbtab & "<null>" & vbtab & "<null>")
Else
' For each group member, get member properties
For Each strMemberOf in arrMemberOf
Set objMember = GetObject("LDAP://" & strMemberOf)
strMemberName = right(objMember.Name,len(objMember.Name)-3)
' Write a line to the outputfile with group and member properties
objMyOutput.WriteLine(strGroupName & vbtab & strGroupDesc & vbtab & strMemberName & vbtab & objMember.Class)
set objMember = nothing
Next
End If
objRecordSet.MoveNext
Set objGroup = nothing
Loop
objMyOutput.close- Marked As Answer byJames Anderson Thursday, July 02, 2009 3:00 PM
All Replies
- I haven't tested your script yet but I see that you are enumerating members of the objGroup.Member object (instead of objGroup.Members). Is this a typo?
An alternative way of getting the members of all groups in your AD is to use a combination of DSQUERY and DSGET, as shown:
dsquery group | dsget group -members
This command will list all groups in your AD through DSQUEY, pipes each group to DSGET to list the members of the group. Empty groups will have, well, empty entries. =)
Regards,
Salvador Manaois III
MCITP | Enterprise & Server Administrator
MCSE MCSA MCTS(x5) CIWA C|EH
My Blog: Bytes and Badz
My Shots: View My PhotoStream I have when you powershell guys do in one line what I did in an entire script, but mine still adds the type descriptions. I found out the hard way that set object = nothing does have its uses along with some error checking! Note to self... when looping a piece of vb script and setting an object in the loop, make sure and clear objects at the end of the loop before they get reused. It made a difference. I also added error checking of Err.Number to make sure the object.parameter existed and that cleaned up the output as well. I checked it against Active Directory and it cleared up the erroneous entries. The key was checking the error against E_ADS_PROPERTY_NOT_FOUND. Here's the result...
' *****************************
' * List All Groups in the Domain and
' * List All Members of each Group
' *
' * Output to a text file on the user's desktop in the format:
' * group name <tab> type <tab> member name <tab> type
' * Prompt for text file name.
' *****************************
' Variables
Const MY_DOMAIN = "dc=contoso,dc=com"
' *****************************
' Start Main
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
Const MYPROMPT = "Enter the Output filename (i.e. Groups.txt) that will be saved on your desktop:"
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFSO = CreateObject("Scripting.FileSystemObject")' Setup the output file
If UCase( Right( WScript.FullName, 12 ) ) = "\CSCRIPT.EXE" Then
WScript.StdOut.Write MYPROMPT & " "
strMyFileName = WScript.StdIn.ReadLine
Else
strMyFileName = InputBox( MYPROMPT )
End If
if strMyFileName = "" then
wscript.quit
end if
Set WshShell = CreateObject("WScript.Shell")
Set WshSysEnv = WshShell.Environment("PROCESS")
strMyFileName = WshSysEnv("USERPROFILE") & "\Desktop\" & strMyFileName
Set WshSysEnv = nothing
Set WshShell = nothing
if objFSO.FileExists(strMyFileName) then
'objFSO.DeleteFile(strMyFileName)
wscript.echo "That filename already exists"
wscript.quit
end if' Get a recordset of groups in AD
Set objMyOutput = objFSO.OpenTextFile(strMyFileName, ForWriting, True)
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = _
"SELECT ADsPath, Name FROM 'LDAP://" & MY_DOMAIN & "' WHERE objectCategory='group'"
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst' For each Group, Get group properties
Do Until objRecordSet.EOF
Set objGroup = GetObject(objRecordSet.Fields("ADsPath").Value)
strGroupName = objRecordSet.Fields("Name").Value
If objGroup.GroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
strGroupDesc = "Domain local "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
strGroupDesc = "Global "
ElseIf objGroup.GroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
strGroupDesc = "Universal "
Else
strGroupDesc = "Unknown "
End If
If objGroup.GroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
strGroupDesc = strGroupDesc & "Security group"
Else
strGroupDesc = strGroupDesc & "Distribution group"
End If' Check if there are members
err.clear
arrMemberOf = objGroup.GetEx("Member")
If Err.Number = E_ADS_PROPERTY_NOT_FOUND then
' Write a line to the outputfile with group properties and no members
objMyOutput.WriteLine(strGroupName & vbtab & strGroupDesc & vbtab & "<null>" & vbtab & "<null>")
Else
' For each group member, get member properties
For Each strMemberOf in arrMemberOf
Set objMember = GetObject("LDAP://" & strMemberOf)
strMemberName = right(objMember.Name,len(objMember.Name)-3)
' Write a line to the outputfile with group and member properties
objMyOutput.WriteLine(strGroupName & vbtab & strGroupDesc & vbtab & strMemberName & vbtab & objMember.Class)
set objMember = nothing
Next
End If
objRecordSet.MoveNext
Set objGroup = nothing
Loop
objMyOutput.close- Marked As Answer byJames Anderson Thursday, July 02, 2009 3:00 PM
- As to your question on objGroup.Member, ldp.exe has the property listed as "member", not "members". It works with objGroup.Member (wasn't a typo). I have found ldp.exe a great tool for looking up property names and seeing what the property values are. The schema management console also does a nice job of listing properties. I recommend both to anyone writing AD scripts.

