VBScript - 检索用户的嵌套组并删除重复

时间:2014-09-30 08:35:57

标签: windows recursion vbscript active-directory nested-groups

对于我的工作,我必须在VBScript中编写一个脚本,该脚本检索用户所属的所有组的列表,包括嵌套组,并取出将在整个列表中重复的嵌套组(以及缩进嵌套组,进一步缩进嵌套组的嵌套组等。)

我找到了一个脚本,它通过gallery.technet.microsoft.com上的Monimoy Sanyal获取用户所属的整个组列表,并尝试根据我的需要调整它。这是我编辑的脚本:

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

不是像原始脚本那样显示找到的EACH组的弹出窗口,而是将整个列表存储在字符串中(GroupsList = GroupsList + ObjGroup.CN + VbCrLf表示直接组,GroupsList = GroupsList + vbTab + ObjThisIsNestedGroup.CN + VbCrLf表示递归函数中的嵌套组,)一旦脚本完成查找组,它就会将String保存在文件中。 (f.write(GroupsList)

我的问题是,尽管递归函数中有If "InStr(GroupsList, ObjThisIsNestedGroup.CN) = 0,我仍然发现自己在整个结果中都有大量的重复(我们的AD对于组来说是一种臃肿,它是一个包含许多嵌套组的巨大结构,其他嵌套组中的嵌套组等)并且检查似乎没有注意到已在GroupsList中找到ObjThisIsNestedGroup.CN。 我不知道如何正确实现缩进。

有什么想法吗?我对脚本非常陌生,所以如果答案显而易见,请原谅我。

2 个答案:

答案 0 :(得分:0)

将组添加为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)

答案 1 :(得分:0)

我找到了解决这两个问题的方法。好吧,第一个问题我不确定我是如何修复的,因为我只是在修改之后还原了代码然后它神奇地工作了。 对于增加的缩进,我声明了一个名为RecurCount的全局变量,每次调用递归过程时都会递增,并在过程后减少。然后,在程序中,我添加了一个For i = 0到RecurCount,它根据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

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