Programming With Groups

A common task for directory services developers is searching for groups and group memberships. Generally, there are four types of tasks that involve groups:

  1. Find a specific group in a domain, or find all the groups of a certain kind in a domain.
  2. Find all the members of a group.
  3. Find all the groups that a principal (a user, computer, or group) is in.
  4. Determine whether a principal is a member of a given group.

The System.DirectoryServices.AccountManagement API provides several ways to handle each of these tasks.

How to find a group

To find a group using its name, id, or other characteristics, the simplest method is to use the Query by Example practice. For instance, to find the group whose display name is "Administrators", one would create an example group principal object, set its display name attribute to "Administrators", and perform the search:

// Create the principal context for the group object.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// Create the GroupPrincipal object and set the diplay name property. 
GroupPrincipal g = new GroupPrincipal(ctx);
g.DisplayName = "Administrators";
  
// Create a PrincipalSearcher object.     
PrincipalSearcher ps = new PrincipalSearcher(g);

// Searches for all groups named "Administrators".
PrincipalSearchResult<Principal> results = ps.FindAll();

Similarly, to find all security groups, one would filter on the IsSecurityGroup property of the example group principal object:

// Create the GroupPrincipal object and set the IsSecurityGroup
// property. 
GroupPrincipal g = new GroupPrincipal(ctx);
g.IsSecurityGroup = true;
  
// Create a PrincipalSearcher object.     
PrincipalSearcher ps = new PrincipalSearcher(g);

// Searches for all security groups
PrincipalSearchResult<Principal> results = ps.FindAll();

How to find all the members of a group

There are three ways to find all the members of a given group. All three methods return foreign members, but only one method expands all groups recursively to return the members of all sub-groups. The first method is to enumerate on the Members property. This property enumerates all direct members of the group, and includes subgroups, but does not expand them. Alternatively, you can call the GetMembers method, which returns a collection of the principal objects that are contained in the group. This is the same data set as enumerated by the Members property earlier, and therefore it includes subgroups, but does not expand them.

Finally, the most comprehensive method is to call an overload of the System.DirectoryServices.AccountManagement.GroupPrincipal.GetMembers(System.Boolean) method which accepts a Boolean. If you call this method with a true value, it will return a list of all members. This includes all the members of all sub-groups. This method returns only leaf nodes; that is, it will return all the members of all sub-groups, but not the sub-groups themselves.

How to find all the groups that a principal is in

To find all the groups that a principal is a member of, you can use three available functions. The GetGroups() method of Principal objects has two overloads. If GetGroups is called by using no argument, it returns all the groups of which the principal is directly a member. If called by using a principal context object, it returns all the groups that a principal is a member of in that context. Neither method is recursive; both return only the groups of which the principal is directly a member. The following code sample illustrates the use of both GetGroups overloads.

Note: See the Knowledge Base article here for important information regarding the functionality of GetGroups.

[C#]

// Create the context for the principal object. 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, 
                                            "fabrikam",
                                            "DC=fabrikam,DC=com");

// Find the principal object for which you wish to enumerate group
// membership.
UserPrincipal userPrincipal = 
                  UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "JSmith");

// Enumerates all distribution groups that JSmith is a
// member of.  This will include groups in other domains, not
// just fabrikam.
PrincipalSearchResult groups = userPrincipal.GetGroups();

foreach (GroupPrincipal g in groups)
        {
            Console.WriteLine(g.DisplayName);
        }

// Enumerates all distribution groups in the fabrikam domain
// that Jsmith is a member of. 
PrincipalSearchResult groups = userPrincipal.GetGroups(ctx);

foreach (GroupPrincipal g in groups)
        {
            Console.WriteLine(g.DisplayName);
        }

It is possible for a principal to be a member of a group that is itself a member of a larger group. For example, a user could be a member of the "Domain Admins" group, which is itself a member of the "Administrators" group. Calling GetGroups for such a user will only return the "Domain Admins" group. However, the user's security token contains a complete list of groups. The GetAuthorizationGroups method will return group objects representing all the groups in the users token that are being used for access checks. The groups returned may also include local computer groups; this depends on where this method call is executed. The following example illustrates the use of GetAuthorizationGroups:

// Create the context for the principal object. 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, 
                                            "fabrikam",
                                            "DC=fabrikam,DC=com");

// Find the principal object for which you wish to enumerate group
// membership.
UserPrincipal userPrincipal = 
                  UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "Jsmith");

// Enumerates all security groups that are in Jsmith's security
// token, which will include nested groups.
// Includes other domains, not just fabrikam.
PrincipalSearchResult groups = userPrincipal.GetAuthorizationGroups();

foreach (GroupPrincipal g in groups)
        {
            Console.WriteLine(g.DisplayName);
        }

How to determine whether a principal is a member of a given group

You can determine whether a principal is a member of a given group by calling the IsMemberOf method, which has two overloads. The first overload takes a group principal object as an argument and returns true if the principal object is a member of that group, and false otherwise. This is illustrated by the following code sample:

// Create the context for the principal object. 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, 
                                            "fabrikam",
                                            "DC=fabrikam,DC=com");

// Retrieve the group principal object for the group you need.
GroupPrincipal groupPrincipal =   
                GroupPrincipal.FindByIdentity(principalContext, "Administrators");

// Find the principal object for which you wish to check membership.
UserPrincipal userPrincipal = 
                  UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "Jsmith");

// Check to see if this user is a member of the "Administrators" group.
bool isMember = user.IsMemberOf(groupPrincipal)

Given a principle context object, an identity type and an identity value, an overload of the IsMemberOf method also returns true or false, as shown here:

// Create the context for the principal object. 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, 
                                            "fabrikam",
                                            "DC=fabrikam,DC=com");

// Find the principal object for which you wish to check membership.
UserPrincipal userPrincipal = 
                  UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "Jsmith");

// Check to see if this user is a member of the "Administrators" group.
bool isMember = user.IsMemberOf(principalContext, IdentityType.Name, "Administrators");

See Also

Reference

GroupPrincipal
Principal

Send comments about this topic to Microsoft.

Copyright © 2008 by Microsoft Corporation. All rights reserved.