How to get the groups of a user in Active Directory? (c#, asp.net) How to get the groups of a user in Active Directory? (c#, asp.net) asp.net asp.net

How to get the groups of a user in Active Directory? (c#, asp.net)


If you're on .NET 3.5 or up, you can use the new System.DirectoryServices.AccountManagement (S.DS.AM) namespace which makes this a lot easier than it used to be.

Read all about it here: Managing Directory Security Principals in the .NET Framework 3.5

Update: older MSDN magazine articles aren't online anymore, unfortunately - you'll need to download the CHM for the January 2008 MSDN magazine from Microsoft and read the article in there.

Basically, you need to have a "principal context" (typically your domain), a user principal, and then you get its groups very easily:

public List<GroupPrincipal> GetGroups(string userName){   List<GroupPrincipal> result = new List<GroupPrincipal>();   // establish domain context   PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);   // find your user   UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);   // if found - grab its groups   if(user != null)   {      PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();      // iterate over all groups      foreach(Principal p in groups)      {         // make sure to add only group principals         if(p is GroupPrincipal)         {             result.Add((GroupPrincipal)p);         }      }   }   return result;}

and that's all there is! You now have a result (a list) of authorization groups that user belongs to - iterate over them, print out their names or whatever you need to do.

Update: In order to access certain properties, which are not surfaced on the UserPrincipal object, you need to dig into the underlying DirectoryEntry:

public string GetDepartment(Principal principal){    string result = string.Empty;    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry);    if (de != null)    {       if (de.Properties.Contains("department"))       {          result = de.Properties["department"][0].ToString();       }    }    return result;}

Update #2: seems shouldn't be too hard to put these two snippets of code together.... but ok - here it goes:

public string GetDepartment(string username){    string result = string.Empty;    // if you do repeated domain access, you might want to do this *once* outside this method,     // and pass it in as a second parameter!    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);    // find the user    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);    // if user is found    if(user != null)    {       // get DirectoryEntry underlying it       DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);       if (de != null)       {          if (de.Properties.Contains("department"))          {             result = de.Properties["department"][0].ToString();          }       }    }    return result;}


GetAuthorizationGroups() does not find nested groups. To really get all groups a given user is a member of (including nested groups), try this:

using System.Security.Principalprivate List<string> GetGroups(string userName){    List<string> result = new List<string>();    WindowsIdentity wi = new WindowsIdentity(userName);    foreach (IdentityReference group in wi.Groups)    {        try        {            result.Add(group.Translate(typeof(NTAccount)).ToString());        }        catch (Exception ex) { }    }    result.Sort();    return result;}

I use try/catch because I had some exceptions with 2 out of 200 groups in a very large AD because some SIDs were no longer available. (The Translate() call does a SID -> Name conversion.)


First of all, GetAuthorizationGroups() is a great function but unfortunately has 2 disadvantages:

  1. Performance is poor, especially in big company's with many users and groups. It fetches a lot more data then you actually need and does a server call for each loop iteration in the result
  2. It contains bugs which can cause your application to stop working 'some day' when groups and users are evolving. Microsoft recognized the issue and is related with some SID's. The error you'll get is "An error occurred while enumerating the groups"

Therefore, I've wrote a small function to replace GetAuthorizationGroups() with better performance and error-safe. It does only 1 LDAP call with a query using indexed fields. It can be easily extended if you need more properties than only the group names ("cn" property).

// Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain")public static List<string> GetAdGroupsForUser2(string userName, string domainName = null){    var result = new List<string>();    if (userName.Contains('\\') || userName.Contains('/'))    {        domainName = userName.Split(new char[] { '\\', '/' })[0];        userName = userName.Split(new char[] { '\\', '/' })[1];    }    using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName))        using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName))            using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name)))            {                searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName);                searcher.SearchScope = SearchScope.Subtree;                searcher.PropertiesToLoad.Add("cn");                foreach (SearchResult entry in searcher.FindAll())                    if (entry.Properties.Contains("cn"))                        result.Add(entry.Properties["cn"][0].ToString());            }    return result;}