> IG wrote:
>
> >I can find several scripts to enumerate members of a specific group, but
> > nothing to parse all groups in an OU and output members of each group.
> >
> > Ideally, I would like to output group name, group description and (nested)
> > group members to a .csv file (with each group as a column).
> >
> > My first attempts used dsquery & dsget but I could only get either a list
> > of
> > groups OR a list of members. Using vbscript, I can bind to LDAP
> > successfully
> > but then it falls apart probably because I'm cutting & pasting from
> > different
> > scripts.
>
> Here is a VBScript program that uses a recursive subroutine to enumerate all
> the groups in an OU and any child OU's. For each group, another recursive
> subroutine enumerates all members. If any members are groups, the sub is
> called recursively. A dictionary object is used to prevent enumeration of
> duplicate groups (and prevent an infinite loop if any group nesting is
> circular).
> ============
> Option Explicit
>
> Dim objMemberList, strOU, objOU
>
> ' Dictionary object to track groups.
> Set objMemberList = CreateObject("Scripting.Dictionary")
> objMemberList.CompareMode = vbTextCompare
>
> ' Specify base OU.
> strOU = "ou=TestOU,dc=MyDomain,dc=com"
>
> ' Bind to base OU.
> Set objOU = GetObject("LDAP://" & strOU)
>
> ' Enumerate groups in OU.
> Call EnumOU(objOU, "")
>
> Sub EnumOU(ByVal objADContainer, ByVal strOffset)
> ' Recursive subroutine to enumerate groups in the OU
> ' and all child OU's.
>
> Dim objGroup, objChild
>
> ' Output name of OU.
> Wscript.Echo strOffset & "OU: " & objADContainer.distinguishedName
>
> ' Enumerate groups in OU.
> objADContainer.Filter = Array("group")
> For Each objGroup In objADContainer
> Call EnumGroup(objGroup, strOffset & " ")
> Next
>
> ' Enumerate child OU's.
> objADContainer.Filter = Array("organizationalUnit")
> For Each objChild In objADContainer
> Call EnumOU(objChild, strOffset & " ")
> Next
>
> End Sub
>
> Sub EnumGroup(ByVal objADGroup, ByVal strOffset)
> ' Recursive subroutine to enumerate group membership.
> ' objMemberList is a dictionary object with global scope.
> ' This subroutine outputs group members. Nested group members
> ' are included. objMemberList prevents an infinite loop if
> ' nested groups are circular.
>
> Dim objMember
>
> ' Check if group already enumerated.
> If (objMemberList.Exists(objADGroup.sAMAccountName) = True) Then
> Wscript.Echo strOffset & "Group: " & objADGroup.sAMAccountName & "
> (Duplicate)"
> Else
> ' Add this group to dictionary object.
> objMemberList.Add objADGroup.sAMAccountName, True
> Wscript.Echo strOffset & "Group: " & objADGroup.sAMAccountName
> For Each objMember In objADGroup.Members
> ' Check if member is a group.
> If (UCase(Left(objMember.objectCategory, 8)) = "CN=GROUP") Then
> Wscript.Echo strOffset & " Member: " &
> objMember.sAMAccountName & " (Group)"
> Call EnumGroup(objMember, strOffset & " ")
> Else
> Wscript.Echo strOffset & " Member: " &
> objMember.sAMAccountName
> End If
> Next
> End If
>
> End Sub
> ===========
> I don't see how a script could arrange the groups in columns, with members
> listed below. That would require amazing logic. A better idea would be to
> have one group per row, with members listed in columns. However, this would
> not accomodate nested OU's. If you skip nested OU's, and have the script
> skip any duplicate groups, maybe the script below would work. The comma
> delimited output can be redirected to a text file that can be read into a
> spreadsheet, where you might be able to switch rows and columns:
> =============
> Option Explicit
>
> Dim objMemberList, strOU, objOU
> Dim objGroup, strGroup
>
> ' Dictionary object to track groups.
> Set objMemberList = CreateObject("Scripting.Dictionary")
> objMemberList.CompareMode = vbTextCompare
>
> ' Specify base OU.
> strOU = "ou=TestOU,dc=MyDomain,dc=com"
>
> ' Bind to base OU.
> Set objOU = GetObject("LDAP://" & strOU)
>
> ' Filter on groups directly in OU.
> objOU.Filter = Array("group")
>
> ' Enumerate groups.
> For Each objGroup In objOU
> strGroup = objGroup.sAMAccountName
> Call EnumGroup(objGroup)
> Wscript.Echo strGroup
> Next
>
> Sub EnumGroup(ByVal objADGroup)
> ' Recursive subroutine to enumerate group membership.
> ' objMemberList is a dictionary object with global scope.
> ' This subroutine outputs group members. Nested group members
> ' are included. objMemberList prevents an infinite loop if
> ' nested groups are circular.
> ' Variable strGroup must have global scope.
>
> Dim objMember
>
> ' Check if group already enumerated.
> If (objMemberList.Exists(objADGroup.sAMAccountName) = False) Then
> ' Add this group to dictionary object.
> objMemberList.Add objADGroup.sAMAccountName, True
> For Each objMember In objADGroup.Members
> ' Check if member is a group.
> If (UCase(Left(objMember.objectCategory, 8)) = "CN=GROUP") Then
> Call EnumGroup(objMember)
> Else
> strGroup = strGroup & "," & objMember.sAMAccountName
> End If
> Next
> End If
>
> End Sub
> ================
> Both scripts should be run at a command prompt, with the output directed to
> a text file. Use the //nologo option to suppress logo info. Note the above
> lists all members except groups.
>
> To reverse things, so the groups are in columns, I think you would have to
> enumerate all the groups ahead of time and populate an array of arrays, then
> enumerate the arrays and output.
>
> --
> Richard Mueller
> Microsoft MVP Scripting and ADSI
> Hilltop Lab -
http://www.rlmueller.net> --
>
>
>