Как отобразить группы безопасности и пользователей в этой группе безопасности с помощью представления списка? - PullRequest
1 голос
/ 11 июня 2019

Мне нужно показать все мои группы безопасности и пользователей, которые являются членами групп безопасности в listView.
В настоящий момент я могу отобразить все группы безопасности, но не знаю, как отобразить пользователей в группе безопасности.

Вот мой код, который я сейчас использую:

private void Security_group_btn_Click(object sender, EventArgs e)
    {
        DirectorySearcher searcher = new DirectorySearcher(DomainName);
        PrincipalContext ctx = new PrincipalContext(ContextType.Domain, DomainName);
        UserPrincipal userPrin = new UserPrincipal(ctx);
        userPrin.Name = "*";
        var search = new System.DirectoryServices.AccountManagement.PrincipalSearcher();
        search.QueryFilter = userPrin;
        var results = searcher.FindAll();
        ListView lvwListView = this.security_listView;
        lvwListView.Clear();
        lvwListView.Columns.Add("Security Group", 175, HorizontalAlignment.Left);
        lvwListView.Columns.Add("Users", 175, HorizontalAlignment.Left);
        searcher.Filter = "(&(objectClass=group))";
        searcher.SearchScope = SearchScope.Subtree;
        searcher.PropertiesToLoad.Add("sAMAccountName");

        SearchResultCollection result = searcher.FindAll();
        foreach (SearchResult entry in result)
        {
            lvwListView.Items.Add(entry.GetDirectoryEntry().Properties["sAMAccountName"].Value.ToString());
        }
            result.Dispose();
            searcher.Dispose();
        }

    }
}

В общем, я хотел бы отобразить что-то подобное в моем ListView:

Security Group          Name

Users                   User1
                        User2
                        User3
Administrators          User1
                        User2
                        User3
                        User4

Спасибо

1 Ответ

1 голос
/ 11 июня 2019

Во-первых, будьте осторожны с этим:

lvwListView.Items.Add(entry.GetDirectoryEntry().Properties["sAMAccountName"].Value.ToString());

В частности, используйте GetDirectoryEntry() только для получения значения.Когда вы получаете значение, используя DirectoryEntry.Properties, оно проверяет, есть ли уже значение, которое вы запрашиваете в кеше.Если нет, он запрашивает у AD каждый атрибут со значением , что обычно будет намного больше данных, чем вам нужно на самом деле.Поскольку вы перебираете несколько учетных записей, это может значительно замедлить работу.

Вы уже запрашиваете sAMAccountName в результатах поиска, так как вы использовали searcher.PropertiesToLoad.Add("sAMAccountName"), так что вы можете вытянутьзначение непосредственно из объекта SearchResult:

lvwListView.Items.Add((string) entry.Properties["sAMAccountName"][0]);

Я подробнее говорю об этом в статье, которую я написал о лучшей производительности при программировании с Active Directory .

Теперь, чтобы действительно ответить на ваш вопрос:

Получение членов - это отдельная история.Вы можете запросить атрибут member в поиске, но у вас возникают проблемы, когда в группе более 1500 участников.Вы должны попросить членов на страницах.Но также вы должны решить, как вы будете обрабатывать вложенные группы: когда группа является членом группы.Вы хотите просто перечислить это имя группы?Или вы хотите заглянуть в эту группу и получить этих членов?

Я тоже написал об этом целую статью: Найти всех членов группы

Ноболее чем вероятно, что вы можете просто использовать один из примеров методов, которые я покажу в этой статье.Это возьмет DirectoryEntry объект группы и выдаст вам список строк, содержащих DOMAIN\username каждого объекта внутри группы (вы можете изменить его, если хотите).Вы можете использовать параметр recursive, чтобы решить, что вы хотите делать с вложенными группами.

public static IEnumerable<string> GetGroupMemberList(DirectoryEntry group, bool recursive = false) {
    var members = new List<string>();

    group.RefreshCache(new[] { "member" });

    while (true) {
        var memberDns = group.Properties["member"];
        foreach (string member in memberDns) {
            using (var memberDe = new DirectoryEntry($"LDAP://{member.Replace("/", "\\/")}")) {
                memberDe.RefreshCache(new[] { "objectClass", "msDS-PrincipalName", "cn" });

                if (recursive && memberDe.Properties["objectClass"].Contains("group")) {
                    members.AddRange(GetGroupMemberList(memberDe, true));
                } else {
                    var username = memberDe.Properties["msDS-PrincipalName"].Value.ToString();
                    if (!string.IsNullOrEmpty(username)) {
                        members.Add(username);
                    }
                }
            }
        }

        if (memberDns.Count == 0) break;

        try {
            group.RefreshCache(new[] {$"member;range={members.Count}-*"});
        } catch (COMException e) {
            if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
                break;
            }
            throw;
        }
    }
    return members;
}

Вы бы назвали его из своего кода следующим образом:

var members = GetGroupMemberList(entry.GetDirectoryEntry());

Тогда вы можетеотображайте их по своему усмотрению.

Это будет хорошо работать, если вы работаете только в одном лесу AD.Но если ваш домен доверяет другим доменам за пределами вашего леса, и вы можете ожидать, что пользователи из этих доменов будут видеть группы, которые вы просматриваете, то вам необходимо учитывать это.Но я расскажу об этом в этой статье.Я также расскажу об основных группах, о которых вам редко нужно заботиться, но вы можете.

Обновление: Чтобы добавить два столбца в ListViewItem, необходимо создатьэто отдельно.Вы можете использовать конструктор , который принимает строковый массив «подэлементов», как они его называют.

Вы можете поместить что-то подобное в ваш цикл, где вы просматриваете элементы, гдеgroupName - это имя группы, а member - это имя члена группы.

lvwListView.Items.Add(new ListViewItem(new [] {
                          groupName,
                          member
                      });

Если вы хотите, чтобы groupName было только первым, тогда вы можете просто вставить пустую строку ("") вместо groupName для остальных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...