【问题标题】:Get users that are 'memberof' a group获取属于“成员”组的用户
【发布时间】:2019-06-05 18:20:46
【问题描述】:

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

这是我的代码:

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() );
}

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

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...
}

很遗憾,由于某种原因,这不起作用。

【问题讨论】:

    标签: c# .net active-directory


    【解决方案1】:

    如果可以使用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);
        }
    }
    

    我有一些 VB 代码也可以使用旧方法,但使用 AccountManagement 肯定更简单。


    这是我所指的 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
    

    及用法:

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

    【讨论】:

    • 这很好用,谢谢。但是,此方法与其他方法有什么区别。有没有办法可以指定其搜索的服务器。我想确保我显示的其他一些数据没有差异。
    • 我不是 100% 确定它在幕后做了什么,但我之前已经将它们混合在一起,没有任何问题或差异。
    • 您知道它是如何将域与适当的 LDAP 服务器相关联的吗?
    • 如果出现问题,您可以使用其他一些构造函数重载来更直接地控制它(或者甚至只传递域控制器的名称而不是域名本身)。如果你真的对它的工作原理感兴趣,那么逻辑就在System.DirectoryServices.AccountManagement.PrincipalContext.DoLSAPDirectoryInit。可以通过反编译System.DirectoryServices.AccountManagement.dll找到源码。
    • 当然。它不是很漂亮,所以希望我不会因为发布它而蒙受任何损失……给我一分钟时间来总结一下。
    【解决方案2】:
    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
        }
    }
    

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

    【讨论】:

      【解决方案3】:

      如果您检查HERE,您可以执行以下操作:

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

      【讨论】:

      • 这对我不起作用,因为我没有完整路径,我只有 CN
      【解决方案4】:

      使用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>();
                  ...
              }
      

      【讨论】:

        猜你喜欢
        • 2013-12-14
        • 2020-02-24
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 2017-06-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多