1

For my work, I have to write a script in VBScript that retrieves a list of ALL groups a user belongs to, including nested groups, and take out nested groups that would be repeated throughout the list (as well as indent nested groups, further indent nested groups of nested groups, etc.)

I found a script that fetches the entire list of groups a user belongs to by Monimoy Sanyal on gallery.technet.microsoft.com, and tried to adapt it to my needs. Here is the script as edited by me:

Option Explicit

Const ForReading = 1, ForWriting = 2, ForAppend = 8

Dim ObjUser, ObjRootDSE, ObjConn, ObjRS
Dim GroupCollection, ObjGroup
Dim StrUserName, StrDomName, StrSQL
Dim GroupsList
Dim WriteFile

GroupsList = ""

Set ObjRootDSE = GetObject("LDAP://RootDSE")
StrDomName = Trim(ObjRootDSE.Get("DefaultNamingContext"))
Set ObjRootDSE = Nothing

StrUserName = InputBox("Enter user login", "Info needed", "")
StrSQL = "Select ADsPath From 'LDAP://" & StrDomName & "' Where ObjectCategory = 'User' AND SAMAccountName = '" & StrUserName & "'"

Set ObjConn = CreateObject("ADODB.Connection")
ObjConn.Provider = "ADsDSOObject":  ObjConn.Open "Active Directory Provider"
Set ObjRS = CreateObject("ADODB.Recordset")
ObjRS.Open StrSQL, ObjConn
If Not ObjRS.EOF Then
    ObjRS.MoveLast: ObjRS.MoveFirst
    Set ObjUser = GetObject (Trim(ObjRS.Fields("ADsPath").Value))
    Set GroupCollection = ObjUser.Groups
    WScript.Echo "Looking for groups " & StrUserName & " is member of. This may take some time..."
    'Groups with direct membership, and calling recursive function for nested groups
    For Each ObjGroup In GroupCollection
        GroupsList = GroupsList + ObjGroup.CN + VbCrLf
        CheckForNestedGroup ObjGroup
    Next
    Set ObjGroup = Nothing: Set GroupCollection = Nothing:  Set ObjUser = Nothing
    'Writing list in a file named Groups <username>.txt
    Set WriteFile = WScript.CreateObject("WScript.Shell")
        Dim fso, f
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set f = fso.OpenTextFile("Groups " & StrUserName & ".txt", ForWriting,true)
        f.write(GroupsList)
        f.Close
        WScript.Echo "You can find the list in the Groups " &StrUserName & ".txt file that has just been created."
Else
    WScript.Echo "Couldn't find user " & StrUserName & " in AD."
End If
ObjRS.Close:    Set ObjRS = Nothing
ObjConn.Close:  Set ObjConn = Nothing

'Recursive fucntion
Private Sub CheckForNestedGroup(ObjThisGroupNestingCheck)
    On Error Resume Next
    Dim AllMembersCollection, StrMember, StrADsPath, ObjThisIsNestedGroup
    AllMembersCollection = ObjThisGroupNestingCheck.GetEx("MemberOf")
    For Each StrMember in AllMembersCollection
        StrADsPath = "LDAP://" & StrMember
        Set ObjThisIsNestedGroup = GetObject(StrADsPath)
        'Not include a group in the list if it is already in the list (does not work for some reason?)
        If InStr(GroupsList, ObjThisIsNestedGroup.CN) = 0 Then
            GroupsList = GroupsList + vbTab + ObjThisIsNestedGroup.CN + VbCrLf
        End If
        'Recursion to look for nested groups and nested groups of nested groups and nested groups of nested groups of nested groups and...
        CheckForNestedGroup ObjThisIsNestedGroup
    Next
    Set ObjThisIsNestedGroup = Nothing: Set StrMember = Nothing:    Set AllMembersCollection = Nothing
End Sub

Rather than display a popup for EACH group found like the original script did, I store the entire list in a String (GroupsList = GroupsList + ObjGroup.CN + VbCrLf for direct groups, GroupsList = GroupsList + vbTab + ObjThisIsNestedGroup.CN + VbCrLf for nested groups in the recursive function,) and once the script is done looking for groups, it saves the String in a file. (f.write(GroupsList))

My problem is, despite the If "InStr(GroupsList, ObjThisIsNestedGroup.CN) = 0 in the recursive function, I still find myself with tons of repetitions throughout the results (our AD is kind of bloated with groups, it is a huge structure with many nested groups and nested groups in other nested groups, etc.) and the check doesn't seem to notice that ObjThisIsNestedGroup.CN is already found in GroupsList. And I have no idea how to implement the indentation properly.

Any ideas? I'm rather new at scripting, so forgive me if the answer is obvious.

4

2 回答 2

0

将组作为键添加到 a Dictionary,因此列表仅包含唯一名称和用于输出Join()Keys数组:

Set GroupsList = CreateObject("Scripting.Dictionary")
GroupsList.CompareMode = vbTextCompare  'make keys case-insensitive
...
GroupsList(ObjGroup.CN) = True
...
f.Write Join(GroupsList.Keys, vbNewLine)
于 2014-09-30T08:55:28.697 回答
0

我找到了解决这两个问题的方法。嗯,第一个问题我不确定我是如何解决的,因为我只是在进行修改后恢复了代码,然后它神奇地工作了。对于增加的缩进,我声明了一个名为 RecurCount 的全局变量,每次调用递归过程时我都会递增,并在过程之后递减。然后,在该过程中,我向 RecurCount 添加了 For i = 0,它根据 RecurCount 添加了不同数量的 vbTab。

这是工作程序:

Private Sub CheckForNestedGroup(ObjThisGroupNestingCheck)
    On Error Resume Next
    Dim AllMembersCollection, StrMember, StrADsPath, ObjThisIsNestedGroup, TabAdd, i 
    AllMembersCollection = ObjThisGroupNestingCheck.GetEx("MemberOf")
    For Each StrMember in AllMembersCollection
        If StrMember <> "" Then
            StrADsPath = "LDAP://" & StrMember
            Set ObjThisIsNestedGroup = GetObject(StrADsPath)
            'If InStr(GroupsList, ObjThisIsNestedGroup.CN) = 0 Then (Uncomment this If and indent lines below to remove groups already in the list)
            TabAdd = ""
            For i = 0 to Recurcount
                TabAdd = TabAdd & vbTab
            Next
            GroupsList = GroupsList & TabAdd & " " & ObjThisIsNestedGroup.CN & VbCrLf
            'End If
            'Recursion to include nested groups of nested groups
            Recurcount = Recurcount + 1
            CheckForNestedGroup ObjThisIsNestedGroup
            Recurcount = Recurcount - 1
        End If
    Next
    Set ObjThisIsNestedGroup = Nothing: Set StrMember = Nothing:    Set AllMembersCollection = Nothing
End Sub

不要忘记在主脚本中将 Recurcount 调暗,并在第一次调用 CheckForNestedGroup 之前将其设为 0。

于 2014-10-02T10:43:06.673 回答