littlelegs
MIS
I found a lovely piece of code that will recursively get the group membership from the DN of a initial group. I 'thought' I would be able to stick some of the code into a loop so that I could open a txt file of group DN's and have the program fetch all members for all the groups.... I just can't figure out why it isn't doing it properly.
When I execute a cmd: cscript enumgroup.vbs "cn=xxx,dc=aaa,dc=com" it works wonderfully. As soon as I put this into a loop it claims it can't find the group but it does outputs the group name to the output and it has a valid name.
Please have mercy on my butchering of the script as I don't claim to be proficient but kinda know where I want to get to but not exactly how to get there.
My thanks to the author for the script.
' EnumGroup.vbs
' VBScript program to document members of a group.
' Reveals nested group and primary group membership.
'
' ----------------------------------------------------------------------
' Copyright (c) 2002 Richard L. Mueller
' Hilltop Lab web site - ' Version 1.0 - December 10, 2002
' Version 1.1 - January 24, 2003 - Include users whose Primary Group is
' any nested group.
' Version 1.2 - February 19, 2003 - Standardize Hungarian notation.
' Version 1.3 - March 11, 2003 - Remove SearchScope property.
' Version 1.4 - April 30, 2003 - Use GetInfoEx to retrieve group
' primaryGroupToken.
' Version 1.5 - January 25, 2004 - Modify error trapping.
'
' 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
Const ForReading = 1
Dim objGroup, strDN, objMemberList, objFSO, objTextFile
Dim adoConnection, adoCommand, objRootDSE, strDNSDomain
' Dictionary object to track group membership.
Set objMemberList = CreateObject("Scripting.Dictionary")
objMemberList.CompareMode = vbTextCompare
' Check for required argument.
If (Wscript.Arguments.Count < 1) Then
Wscript.Echo "Required argument <Distinguished Name> " _
& "of group missing."
Wscript.Echo "For example:" & vbCrLf _
& "cscript //nologo EnumGroup.vbs " _
& """cn=Test Group,ou=Sales,dc=MyDomain,dc=com"""
Wscript.Quit(0)
End If
' Retrieve DNS domain name from RootDSE.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
' Setup ADO.
Set adoConnection = CreateObject("ADODB.Connection")
Set adoCommand = CreateObject("ADODB.Command")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
(WScript.Arguments.Item(0), ForReading)
'******Start with Group Names
Do Until objTextFile.AtEndOfStream
strDN = objTextFile.Readline
' Bind to the group object with the LDAP provider.
' strDN = Wscript.Arguments(0)
On Error Resume Next
Set objGroup = GetObject("LDAP://" & strDN)
If (Err.Number <> 0) Then
On Error GoTo 0
Wscript.Echo "Group not found" & vbCrLf & strDN
Wscript.Quit(1)
End If
On Error GoTo 0
' Enumerate group membership.
Wscript.Echo "Members of group " & objGroup.sAMAccountName
Call EnumGroup(objGroup, " ")
'*****End of Groups
Loop
' Clean Up.
adoConnection.Close
Set objGroup = Nothing
Set objRootDSE = Nothing
Set adoCommand = Nothing
Set adoConnection = Nothing
Sub EnumGroup(ByVal objADGroup, ByVal strOffset)
' Recursive subroutine to enumerate group membership.
' objMemberList is a dictionary object with global scope.
' objADGroup is a group object bound with the LDAP provider.
' This subroutine outputs a list of group members, one member
' per line. Nested group members are included. Users are also
' included if their primary group is objADGroup. objMemberList
' prevents an infinite loop if nested groups are circular.
Dim strFilter, strAttributes, adoRecordset, intGroupToken
Dim objMember, strQuery, strNTName
' Retrieve "primaryGroupToken" of group.
objADGroup.GetInfoEx Array("primaryGroupToken"), 0
intGroupToken = objADGroup.Get("primaryGroupToken")
' Use ADO to search for users whose "primaryGroupID" matches the
' group "primaryGroupToken".
strFilter = "(primaryGroupID=" & intGroupToken & ")"
strAttributes = "sAMAccountName"
strQuery = "<LDAP://" & strDNSDomain & ">;" & strFilter & ";" _
& strAttributes & ";subtree"
adoCommand.CommandText = strQuery
Set adoRecordset = adoCommand.Execute
Do Until adoRecordset.EOF
strNTName = adoRecordset.Fields("sAMAccountName").Value
If (objMemberList.Exists(strNTName) = False) Then
objMemberList.Add strNTName, True
Wscript.Echo strOffset & strNTName & " (Primary)"
Else
Wscript.Echo strOffset & strNTName & " (Primary, Duplicate)"
End If
adoRecordset.MoveNext
Loop
adoRecordset.Close
For Each objMember In objADGroup.Members
If (objMemberList.Exists(objMember.sAMAccountName) = False) Then
objMemberList.Add objMember.sAMAccountName, True
If (UCase(Left(objMember.objectCategory, 8)) = "CN=GROUP") Then
Wscript.Echo strOffset & objMember.sAMAccountName & " (Group)"
Call EnumGroup(objMember, strOffset & " ")
Else
Wscript.Echo strOffset & objMember.sAMAccountName
End If
Else
Wscript.Echo strOffset & objMember.sAMAccountName & " (Duplicate)"
End If
Next
Set objMember = Nothing
Set adoRecordset = Nothing
End Sub
When I execute a cmd: cscript enumgroup.vbs "cn=xxx,dc=aaa,dc=com" it works wonderfully. As soon as I put this into a loop it claims it can't find the group but it does outputs the group name to the output and it has a valid name.
Please have mercy on my butchering of the script as I don't claim to be proficient but kinda know where I want to get to but not exactly how to get there.
My thanks to the author for the script.
' EnumGroup.vbs
' VBScript program to document members of a group.
' Reveals nested group and primary group membership.
'
' ----------------------------------------------------------------------
' Copyright (c) 2002 Richard L. Mueller
' Hilltop Lab web site - ' Version 1.0 - December 10, 2002
' Version 1.1 - January 24, 2003 - Include users whose Primary Group is
' any nested group.
' Version 1.2 - February 19, 2003 - Standardize Hungarian notation.
' Version 1.3 - March 11, 2003 - Remove SearchScope property.
' Version 1.4 - April 30, 2003 - Use GetInfoEx to retrieve group
' primaryGroupToken.
' Version 1.5 - January 25, 2004 - Modify error trapping.
'
' 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
Const ForReading = 1
Dim objGroup, strDN, objMemberList, objFSO, objTextFile
Dim adoConnection, adoCommand, objRootDSE, strDNSDomain
' Dictionary object to track group membership.
Set objMemberList = CreateObject("Scripting.Dictionary")
objMemberList.CompareMode = vbTextCompare
' Check for required argument.
If (Wscript.Arguments.Count < 1) Then
Wscript.Echo "Required argument <Distinguished Name> " _
& "of group missing."
Wscript.Echo "For example:" & vbCrLf _
& "cscript //nologo EnumGroup.vbs " _
& """cn=Test Group,ou=Sales,dc=MyDomain,dc=com"""
Wscript.Quit(0)
End If
' Retrieve DNS domain name from RootDSE.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
' Setup ADO.
Set adoConnection = CreateObject("ADODB.Connection")
Set adoCommand = CreateObject("ADODB.Command")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
(WScript.Arguments.Item(0), ForReading)
'******Start with Group Names
Do Until objTextFile.AtEndOfStream
strDN = objTextFile.Readline
' Bind to the group object with the LDAP provider.
' strDN = Wscript.Arguments(0)
On Error Resume Next
Set objGroup = GetObject("LDAP://" & strDN)
If (Err.Number <> 0) Then
On Error GoTo 0
Wscript.Echo "Group not found" & vbCrLf & strDN
Wscript.Quit(1)
End If
On Error GoTo 0
' Enumerate group membership.
Wscript.Echo "Members of group " & objGroup.sAMAccountName
Call EnumGroup(objGroup, " ")
'*****End of Groups
Loop
' Clean Up.
adoConnection.Close
Set objGroup = Nothing
Set objRootDSE = Nothing
Set adoCommand = Nothing
Set adoConnection = Nothing
Sub EnumGroup(ByVal objADGroup, ByVal strOffset)
' Recursive subroutine to enumerate group membership.
' objMemberList is a dictionary object with global scope.
' objADGroup is a group object bound with the LDAP provider.
' This subroutine outputs a list of group members, one member
' per line. Nested group members are included. Users are also
' included if their primary group is objADGroup. objMemberList
' prevents an infinite loop if nested groups are circular.
Dim strFilter, strAttributes, adoRecordset, intGroupToken
Dim objMember, strQuery, strNTName
' Retrieve "primaryGroupToken" of group.
objADGroup.GetInfoEx Array("primaryGroupToken"), 0
intGroupToken = objADGroup.Get("primaryGroupToken")
' Use ADO to search for users whose "primaryGroupID" matches the
' group "primaryGroupToken".
strFilter = "(primaryGroupID=" & intGroupToken & ")"
strAttributes = "sAMAccountName"
strQuery = "<LDAP://" & strDNSDomain & ">;" & strFilter & ";" _
& strAttributes & ";subtree"
adoCommand.CommandText = strQuery
Set adoRecordset = adoCommand.Execute
Do Until adoRecordset.EOF
strNTName = adoRecordset.Fields("sAMAccountName").Value
If (objMemberList.Exists(strNTName) = False) Then
objMemberList.Add strNTName, True
Wscript.Echo strOffset & strNTName & " (Primary)"
Else
Wscript.Echo strOffset & strNTName & " (Primary, Duplicate)"
End If
adoRecordset.MoveNext
Loop
adoRecordset.Close
For Each objMember In objADGroup.Members
If (objMemberList.Exists(objMember.sAMAccountName) = False) Then
objMemberList.Add objMember.sAMAccountName, True
If (UCase(Left(objMember.objectCategory, 8)) = "CN=GROUP") Then
Wscript.Echo strOffset & objMember.sAMAccountName & " (Group)"
Call EnumGroup(objMember, strOffset & " ")
Else
Wscript.Echo strOffset & objMember.sAMAccountName
End If
Else
Wscript.Echo strOffset & objMember.sAMAccountName & " (Duplicate)"
End If
Next
Set objMember = Nothing
Set adoRecordset = Nothing
End Sub