VBScript - получение вложенных групп пользователя и избавление от повторений

Для моей работы мне нужно написать скрипт на VBScript, который извлекает список ВСЕХ групп, к которым принадлежит пользователь, включая вложенные группы, и удаляет вложенные группы, которые будут повторяться по всему списку (а также отступ для вложенных групп, дальнейший отступ вложенные группы вложенных групп и т. д.)

Я нашел скрипт, который выбирает весь список групп, к которым принадлежит пользователь, от Monimoy Sanyal на gallery.technet.microsoft.com, и попытался адаптировать его к моим потребностям. Вот скрипт, отредактированный мной:

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

Вместо того, чтобы отображать всплывающее окно для КАЖДОЙ группы, найденной как оригинальный скрипт, я сохраняю весь список в строке (GroupsList = GroupsList + ObjGroup.CN + VbCrLf для прямых групп, GroupsList = GroupsList + vbTab + ObjThisIsNestedGroup.CN + VbCrLf для вложенных групп в рекурсивной функции,) и когда скрипт завершает поиск групп, он сохраняет строку в файле. (f.write(GroupsList))

Моя проблема, несмотря на If "InStr(GroupsList, ObjThisIsNestedGroup.CN) = 0 в рекурсивной функции я все еще нахожусь с тоннами повторений в результатах (наша AD вроде как раздута с группами, это огромная структура со многими вложенными группами и вложенными группами в других вложенных группах и т. д.), и проверка не Кажется, не замечают, что ObjThisIsNestedGroup.CN уже найден в GroupsList. И я понятия не имею, как правильно реализовать отступ.

Есть идеи? Я довольно новичок в написании сценариев, так что прости меня, если ответ очевиден.

2 ответа

Решение

Я нашел решение для обеих проблем. Ну, первая проблема, я не уверен, как я ее исправил, так как я изменил код только после внесения изменений, и тогда он работал волшебным образом. Для увеличения отступа я объявил глобальную переменную с именем RecurCount, которую я увеличиваю каждый раз, когда вызываю рекурсивную процедуру, и уменьшаю ее после процедуры. Затем в рамках процедуры я добавил For i = 0 в RecurCount, который добавляет различное количество vbTabs в зависимости от RecurCount.

Вот рабочая процедура:

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 в основном скрипте и установить его в 0 прямо перед вызовом CheckForNestedGroup в первый раз.

Добавьте группы в качестве ключей к 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)
Другие вопросы по тегам