4

I'm trying to export members of specific AD groups. I have a working solution to get ALL and filter, but that seems excessive if the group I want has 5 out of 1000 possible users..

I'm working in this direction:

  public void PrintMembers(string groupname, string domain)
        {
            GroupPrincipal group = GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain, domain), groupname);
            foreach (Principal princ in group.Members)
            {
                if (princ.StructuralObjectClass == "user")
                {
                    Response.Write(UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain, domain), princ.Name));
                }

            }

        }

This sort of works, but fails to give members that have inherited the membership through an underlying group.

So: "Specific group 1" = I get all 5 members alright

"Specific group 2" = I get all 7 members alright

"Mother group", that holds the two groups above = I get no members...

I could iterate that groups subgroups, but feel there must be another way....

Any suggestions?

recursion.ninja
  • 5,377
  • 7
  • 46
  • 78
Steen
  • 2,749
  • 2
  • 20
  • 36
  • Have the same problem in a PERL app... – recursion.ninja Jun 12 '14 at 16:39
  • http://stackoverflow.com/questions/6714506/active-directory-nested-groups – Bruce Dunwiddie Jun 15 '14 at 06:28
  • @awashburn LDAP_MATCHING_RULE_IN_CHAIN should work in PERL too. – JPBlanc Jun 16 '14 at 15:35
  • Thanks all for responding. It has been more than half a year, and the solution I found at the time was to simply get all individual memberships and iterate for the interesting ones. Works in my case with not too much data and low usage. I SHOULD consider your suggestions, but I cannot justify spending time on a solved matter. I choose @Ashigore as solution, as it LOOKS like it works, and looks neat. And I don't want to leave my questions open :-) – Steen Jun 24 '14 at 14:01
  • awashburn added the ldap tag - guess thats why the question surfaced again.. – Steen Jun 24 '14 at 14:04

2 Answers2

2

First of all : @shriop point the exact answer to your question.

As far as the bounty is concerned that is to say : "A solution which uses the LDAP protocol to enumerate the users in a group and it's subgroups without recursion". Here is something working withe Active-Directory begining Windows Server 2003 SP2 and called LDAP_MATCHING_RULE_IN_CHAIN. It Search recursively (but in one query) all the users from a group (be careful it return users from security and distribution groups). Here is the ADSI usage in C# :

static void Main(string[] args)
{
  /* Connection to Active Directory
   */
  string sFromWhere = "LDAP://SRVENTR2:389/dc=societe,dc=fr";
  DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "societe\\administrateur", "test.2011");

  /* To find all the users member of groups "Grp1"  :
   * Set the base to the groups container DN; for example root DN (dc=societe,dc=fr) 
   * Set the scope to subtree
   * Use the following filter :
   * (member:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=X)
   */
  DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
  dsLookFor.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=societe,DC=fr)(objectCategory=user))";
  dsLookFor.SearchScope = SearchScope.Subtree;
  dsLookFor.PropertiesToLoad.Add("cn");
  dsLookFor.PropertiesToLoad.Add("samAccountName");  

  SearchResultCollection srcUsers = dsLookFor.FindAll();

  /* Just show each user
   */
  foreach (SearchResult srcUser in srcUsers)
  {
    Console.WriteLine("{0}", srcUser.Path);
    Console.WriteLine("{0}", srcUser.Properties["samAccountName"][0]);
  }

  Console.ReadLine();
}
Community
  • 1
  • 1
JPBlanc
  • 70,406
  • 17
  • 130
  • 175
  • This is a good answer, if you do not mind not being able to use the `System.DirectoryServices.AccountManagement` namespace. – Ashigore Jun 18 '14 at 14:00
2

Anything wrong with GetMembers(true)?

static void Main(string[] args)
{
    foreach (string user in GetMemberNames("My Group", "domain.local"))
    {
        Console.WriteLine(user);
    }
    Console.ReadKey();
}

public static string[] GetMemberNames(string groupname, string domain)
{
    using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
    using (GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupname))
    using (PrincipalSearchResult<Principal> results = group.GetMembers(true))
    {
        return results.OfType<UserPrincipal>().Select(u => u.SamAccountName).ToArray();
    }
}
Ashigore
  • 4,618
  • 1
  • 19
  • 39
  • The bounty is about LDAP. – JPBlanc Jun 18 '14 at 13:58
  • @JPBlanc The bounty might specify LDAP but the question and the example code make no such distinction. Take my answer as a solution to the original problem if you want. – Ashigore Jun 18 '14 at 13:59
  • Ashigore for me the original question was a duplicate of [Active Directory nested groups](http://stackoverflow.com/a/6715951/608772). – JPBlanc Jun 18 '14 at 14:16
  • `GetMembers(true)` has a limitation, e.g. `Domain Users` are not returned at all. In order to get them you have to call `GetMembers(false)` recursively. – Wernfried Domscheit Dec 11 '15 at 10:27
  • @WernfriedDomscheit `Domain Users` is a group, not a user. – Ashigore Dec 11 '15 at 12:29
  • Yes, but suppose `GetMembers(true)` shall return **all** users of GroupPrincipal and "Domain Users" is a member of this GroupPrincipal I would expect output of all domain users. – Wernfried Domscheit Dec 11 '15 at 13:17