title: Active Directory: Get all group members
body: <p>Question: How do I retrieve all group members in a consistent manner?</p>
  
  <p>Context: I am retrieving all objects that are either person, group, contact, or computer:</p>
  
  <pre><code>Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))"
  </code></pre>
  
  <p>I now need to retrieve all members of groups. I have developed three methods to do this; however, they are returning different results for the same group and I am not sure why. I suspect that it may be caused by nested groups (i.e., groups within groups). Debugging it is a challenge because some groups contain so many members that the debugger times out and shows no results.</p>
  
  <p>Method 1 and 2 is slow. Method 3 is fast. So, I prefer to use method 3.</p>
  
  <pre><code>Group Name      Retrieval Method    Recursive Search    Count Members   Comment
  Group1          AccountManagement   TRUE                505 
  Group1          AccountManagement   FALSE               505 
  Group1          DirectoryServices   N/A                 101 
  Group2          AccountManagement   TRUE                440             Contains group name 'Group3'
  Group2          AccountManagement   FALSE               440             Contains group name 'Group3'
  Group2          DirectoryServices   N/A                 100             Contains group name 'Group3'
  Group3          AccountManagement   TRUE                101             All Group3
  Group3          AccountManagement   FALSE               2               All Group3
  Group3          DirectoryServices   N/A                 2               1 user 1 group (Group2)
  </code></pre>
  
  <p><strong>Method 1 and 2</strong>: Get group members using the <code>S.DS.AM</code>, where the GetMembers() is set to either true or false, respectively: <a href="https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement(v=vs.110).aspx" rel="nofollow noreferrer">https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement(v=vs.110).aspx</a></p>
  
  <pre><code>private static List&lt;Guid&gt; GetGroupMemberList(string strPropertyValue, string strDomainController, bool bolRecursive)
          {
              List&lt;Guid&gt; listGroupMemberGuid = null;
              GroupPrincipal groupPrincipal = null;
              PrincipalSearchResult&lt;Principal&gt; listPrincipalSearchResult = null;
              List&lt;Principal&gt; listPrincipalNoNull = null;
              PrincipalContext principalContext = null;
              ContextType contextType;
              IdentityType identityType;
  
              try
              {
                  listGroupMemberGuid = new List&lt;Guid&gt;();
                  contextType = ContextType.Domain;
                  principalContext = new PrincipalContext(contextType, strDomainController);
                  identityType = IdentityType.Guid;
  
                  groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
  
                  if (groupPrincipal != null)
                  {
                      listPrincipalSearchResult = groupPrincipal.GetMembers(bolRecursive);
                      listPrincipalNoNull = listPrincipalSearchResult.Where(item =&gt; item.Name != null).ToList();
                      foreach (Principal principal in listPrincipalNoNull)
                      {
                          listGroupMemberGuid.Add((Guid)principal.Guid);
                      }
                  }
                  return listGroupMemberGuid;
              }
              catch (MultipleMatchesException)
              {
                  throw new MultipleMatchesException(strPropertyValue);
              }
              catch (Exception ex)
              {
                  throw ex;
              }
              finally
              {
                  listGroupMemberGuid = null;
                  listPrincipalSearchResult.Dispose();
                  principalContext.Dispose();
                  groupPrincipal.Dispose();
              }
          }
  </code></pre>
  
  <p><strong>Method 3</strong>: Get group members using the <code>S.DS.AD</code>: <a href="https://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectory(v=vs.110).aspx" rel="nofollow noreferrer">https://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectory(v=vs.110).aspx</a></p>
  
  <pre><code>private static List&lt;string&gt; GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
          {
              List&lt;string&gt; listGroupMemberDn = new List&lt;string&gt;();
              string strPath = strActiveDirectoryHost + "/&lt;GUID=" + strPropertyValue + "&gt;";
              DirectoryEntry directoryEntryGroup;
              DirectoryEntry directoryEntryGroupMembers;
              DirectorySearcher directorySearcher;
              SearchResultCollection searchResultCollection;
              DataTypeConverter objConverter = null;
  
              objConverter = new DataTypeConverter();
  
              try
              {
                  directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
                  directoryEntryGroup.RefreshCache();
              }
              catch (Exception ex)
              {
                  throw ex;
              }
  
              try
              {
                  directorySearcher = new DirectorySearcher(directoryEntryGroup)
                  {
                      //Filter = "(objectCategory=group)", // Group
                      SearchScope = SearchScope.Subtree,
                      PageSize = intActiveDirectoryPageSize,
                  };
                  directorySearcher.PropertiesToLoad.Add("objectGUID");
                  searchResultCollection = directorySearcher.FindAll();
              }
              catch (Exception ex)
              {
                  throw ex;
              }
  
              try
              {
                  foreach (SearchResult searchResult in searchResultCollection)
                  {
                      directoryEntryGroupMembers = searchResult.GetDirectoryEntry();
  
                      foreach (object objGroupMember in directoryEntryGroupMembers.Properties["member"])
                      {
                          listGroupMemberDn.Add((string)objGroupMember);
                      }
                  }
                  return listGroupMemberDn;
              }
              catch (Exception ex)
              {
                  throw ex;
              }
              finally
              {
                  listGroupMemberDn = null;
                  strPath = null;
                  directoryEntryGroup.Dispose();
                  directoryEntryGroupMembers = null;
                  directorySearcher.Dispose();
                  searchResultCollection.Dispose();
                  objConverter = null;
              }
          }
  </code></pre>
  
  <p><strong>Method 4</strong>: (Loop with GetNextChunk() method implementation)</p>
  
  <pre><code> private static List&lt;string&gt; GetGroupMemberList(string strPropertyValue, string strActiveDirectoryHost, int intActiveDirectoryPageSize)
      {
          // Variable declaration(s).
          List&lt;string&gt; listGroupMemberDn = new List&lt;string&gt;();
          string strPath = strActiveDirectoryHost + "/&lt;GUID=" + strPropertyValue + "&gt;";
          string strMemberPropertyRange = null;
          DirectoryEntry directoryEntryGroup = null;
          DirectorySearcher directorySearcher = null;
          SearchResultCollection searchResultCollection = null;
          // https://msdn.microsoft.com/en-us/library/windows/desktop/ms676302(v=vs.85).aspx
          const int intIncrement = 1500;
  
          // Load the DirectoryEntry.
          try
          {
              // Setup a secure connection with Active Directory (AD) using Kerberos by setting the directoryEntry with AuthenticationTypes.Secure.
              directoryEntryGroup = new DirectoryEntry(strPath, null, null, AuthenticationTypes.Secure);
  
              // Load the property values for this DirectoryEntry object into the property cache.
              directoryEntryGroup.RefreshCache();
          }
          catch (Exception)
          { }
  
          #region Method1
          // Enumerate group members.
          try
          {
              // Check to see if the group has any members.
              if (directoryEntryGroup.Properties["member"].Count &gt; 0)
              {
                  int intStart = 0;
                  while (true)
                  {
                      // End of the range.
                      int intEnd = intStart + intIncrement - 1;
  
                      strMemberPropertyRange = string.Format("member;range={0}-{1}", intStart, intEnd);
  
                      directorySearcher = new DirectorySearcher(directoryEntryGroup)
                      {
                          // Set the Filter criteria that is used to constrain the search within AD.
                          Filter = "(|(objectCategory=person)(objectCategory=computer)(objectCategory=group))", // User, Contact, Group, Computer objects
  
                          // Set the SearchScope for how the AD tree is searched (Default = Subtree).
                          SearchScope = SearchScope.Base,
  
                          // The PageSize value should be set equal to the PageSize that is set by the AD administrator (Default = 0).
                          PageSize = intActiveDirectoryPageSize,
  
                          PropertiesToLoad = { strMemberPropertyRange }
                      };
  
                      try
                      {
                          // Populate the searchResultCollection with all records within AD that match the Filter criteria.
                          searchResultCollection = directorySearcher.FindAll();
  
                          foreach (SearchResult searchResult in searchResultCollection)
                          {
                              var membersProperties = searchResult.Properties;
  
                              var membersPropertyNames = membersProperties.PropertyNames.OfType&lt;string&gt;().Where(n =&gt; n.StartsWith("member;"));
  
                              foreach (var propertyName in membersPropertyNames)
                              {
                                  // Get all members from the ranged result.
                                  var members = membersProperties[propertyName];
  
                                  foreach (string memberDn in members)
                                  {
                                      // Add the member's "distinguishedName" attribute value to the list.
                                      listGroupMemberDn.Add(memberDn);
                                  }
                              }
                          }
                      }
                      catch (DirectoryServicesCOMException)
                      {
                          // When the start of the range exceeds the number of available results, an exception is thrown and we exit the loop.
                          break;
                      }
  
                      // Increment for the next range.
                      intStart += intIncrement;
                  }
              }
  
              // return the listGroupMemberDn;
              return listGroupMemberDn;
          }
          #endregion
  
          finally
          {
              // Cleanup objects.
              listGroupMemberDn = null;
              strPath = null;
              strMemberPropertyRange = null;
              directoryEntryGroup.Dispose();
              directorySearcher.Dispose();
              searchResultCollection.Dispose();
          }
      }
  </code></pre>