C# 获取属于“成员”组的用户

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9603777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:05:49  来源:igfitidea点击:

Get users that are 'memberof' a group

c#.netactive-directory

提问by Pierluc SS

I got a working solution, however I'm pretty sure there is a less resource-intensive method because the current solution involves doing a query to get the groups member and then a query to get each users information.

我得到了一个可行的解决方案,但是我很确定有一种资源密集型的方法,因为当前的解决方案涉及执行查询以获取组成员,然后执行查询以获取每个用户的信息。

Here is the code I have :

这是我的代码:

DirectoryEntry root = new DirectoryEntry( "LDAP://server:port" );
DirectorySearcher searcher = new DirectorySearcher( root );
searcher.Filter = "(&(ObjectClass=Group)(CN=foo-group))";

var members = (IEnumerable)searcher.FindOne()
              .GetDirectoryEntry()
              .Invoke( "members" );

Dictionary<string , string> results = new Dictionary<string , string>();

foreach( object member in members ) {
   DirectoryEntry de = new DirectoryEntry( member );
   results.Add( de.Properties[ "SAMAccountname" ][ 0 ].ToString(), de.Properties[ "cn" ][ 0 ].ToString() );
}

Ideally I'd like to be able to do a single query to get every user that are member of a group, filters the properties to load and then display them. So something like this

理想情况下,我希望能够执行单个查询来获取属于组成员的每个用户,过滤要加载的属性,然后显示它们。所以像这样

DirectoryEntry root = new DirectoryEntry( "LDAP://server:port" );
DirectorySearcher searcher = new DirectorySearcher( root );
searcher.PropertiesToLoad.Add( "cn" );
searcher.PropertiesToLoad.Add( "SAMAccountname" );
searcher.Filter = "(&(ObjectClass=user)(memberof=foo-group))";

foreach( var user in searcher.FindAll() ) {
    //do whatever...
}

Unfortunately, that doesn't work for some reason.

不幸的是,由于某种原因,这不起作用。

采纳答案by M.Babcock

If you can use System.DirectoryServices.AccountManagement:

如果您可以使用System.DirectoryServices.AccountManagement

var context = new PrincipalContext(ContextType.Domain, "YOUR_DOMAIN_NAME");
using (var searcher = new PrincipalSearcher())
{
    var groupName = "YourGroup";
    var sp = new GroupPrincipal(context, groupName);
    searcher.QueryFilter = sp;
    var group = searcher.FindOne() as GroupPrincipal;

    if (group == null)
        Console.WriteLine("Invalid Group Name: {0}", groupName);

    foreach (var f in group.GetMembers())
    {
        var principal = f as UserPrincipal;

        if (principal == null || string.IsNullOrEmpty(principal.Name))
            continue;

        Console.WriteLine("{0}", principal.Name);
    }
}

I have some VB code that'll do it the old way also, but this is definitely simpler with AccountManagement.

我有一些 VB 代码也可以用旧的方式来做,但这绝对是 AccountManagement 更简单。



Here's the VB code I was referring to (again it isn't pretty but it's functional):

这是我所指的 VB 代码(同样它并不漂亮,但它很实用):

Public Function GetUsersByGroup(de As DirectoryEntry, groupName As String) As IEnumerable(Of DirectoryEntry)
    Dim userList As New List(Of DirectoryEntry)
    Dim group As DirectoryEntry = GetGroup(de, groupName)

    If group Is Nothing Then Return Nothing

    For Each user In GetUsers(de)
        If IsUserInGroup(user, group) Then
            userList.Add(user)
        End If
    Next

    Return userList
End Function

Public Function GetGroup(de As DirectoryEntry, groupName As String) As DirectoryEntry
    Dim deSearch As New DirectorySearcher(de)

    deSearch.Filter = "(&(objectClass=group)(SAMAccountName=" & groupName & "))"

    Dim result As SearchResult = deSearch.FindOne()

    If result Is Nothing Then
        Return Nothing
    End If

    Return result.GetDirectoryEntry()
End Function

Public Function GetUsers(de As DirectoryEntry) As IEnumerable(Of DirectoryEntry)
    Dim deSearch As New DirectorySearcher(de)
    Dim userList As New List(Of DirectoryEntry)

    deSearch.Filter = "(&(objectClass=person))"

    For Each user In deSearch.FindAll()
        userList.Add(user.GetDirectoryEntry())
    Next

    Return userList
End Function

Public Function IsUserInGroup(user As DirectoryEntry, group As DirectoryEntry) As Boolean
    Dim memberValues = user.Properties("memberOf")

    If memberValues Is Nothing OrElse memberValues.Count = 0 Then Return False

    For Each g In memberValues.Value
        If g = group.Properties("distinguishedName").Value.ToString() Then
            Return True
        End If
    Next

    Return False
End Function

And usage:

和用法:

Dim entries = New DirectoryEntry("LDAP://...")
Dim userList As IEnumerable(Of DirectoryEntry) = GetUsersByGroup(entries, "GroupName")

回答by Christoph Fink

If you check HEREyou can do the following:

如果您在此处查看,您可以执行以下操作:

DirectoryEntry group = new DirectoryEntry("LDAP://CN=foo-group,DC=Cmp,DC=COM");
foreach(object dn in group.Properties["member"] )
    //do whatever

回答by Jetti

using System.DirectoryServices;

DirectoryEntry objEntry = DirectoryEntry(Ldapserver, userid, password);
DirectorySearcher personSearcher = new DirectorySearcher(objEntry);
personSearcher.Filter = string.Format("(SAMAccountName={0}", username);
SearchResult result = personSearcher.FindOne();

if(result != null)
{
    DirectoryEntry personEntry = result.GetDirectoryEntry();
    PropertyValueCollection groups = personEntry.Properties["memberOf"];
    foreach(string g in groups)
    {
        Console.WriteLine(g); // will write group name
    }
}

I originally used a method similar to what you have posted and it took about 12 minutes to run through my entire company's AD and get the results. After switching to this method, it takes about 2 minutes. You will need to use the ldapserver address where I wrote ldapserver and the userid and password as well and username is the SAMAccountName for the person you're looking up.

我最初使用的方法类似于您发布的方法,大约需要12分钟才能遍历我整个公司的AD并获得结果。切换到此方法后,大约需要2分钟。您将需要使用我在其中写入 ldapserver 的 ldapserver 地址以及用户 ID 和密码,而 username 是您要查找的人的 SAMAccountName。

回答by McX

It's shorter using GroupPrincipalmethod FindByIdentitywhich gives also multiple ways to identify the group with IdentityType:

使用GroupPrincipal方法更短FindByIdentity,它也提供了多种方法来识别组IdentityType

        using (var context = new PrincipalContext(ContextType.Domain, "YOUR_DOMAIN_NAME")
        {
            var userPrincipals = GroupPrincipal
                .FindByIdentity(context, IdentityType.SamAccountName, "GROUP_ACCOUNT")
                .GetMembers(true) // recursive
                .OfType<UserPrincipal>();
            ...
        }