Skip to main content

By default, Active Directory imposes a attribute value page limit of 1500 - in short, Active Directory will return the values of that attribute in sets of 1500, and its up to the developer to page through those sets looking for the desired value. Without modification, this function allows you to check to see whether or not a user is in a particular group, however, this code can be easily extended to populate a local cache or collection for a variety of operations.

// ============================================================================
// Using LDAP to Enumerate Large Groups
//
// In your day-to-day usage of the UW Windows Infrastructure, you may notice
// several groups that have an extremely large membership list - for example,
// most of the affiliation-based groups exceed 100,000 members.  If you use an
// application that relies on LDAP as its underlying directory protocol, you may
// notice some odd behavior when checking the membership of these groups.
//
// By default, Active Directory imposes a attribute value page limit of 1500 -
// in short, Active Directory will return the values of that attribute in sets
// of 1500, and its up to the developer to page through those sets looking for
// the desired value.
//
// During the development and implementation of the UW Windows Infrastructure,
// the project team encountered this scenario and developed code to work around
// it. This code has been made available below.
//
// The code samples are written in Visual Basic .NET and C#, tested against
// Microsoft .NET Framework v2.0.  Without modification, this function allows
// you to check to see whether or not a user is in a particular group, however,
// this code can be easily extended to populate a local cache or collection for
// a variety of operations.
//
// These code samples are provided as-is, and no support will be offered.
//
// http://www.netid.washington.edu/documentation/enumeratinglargegroups.aspx
// ============================================================================

using System.DirectoryServices;

/// <summary>
/// Determines whether or not the specified user is a member of the group.
/// </summary>
/// <param name="UserDN">A System.String containing the user's distinguished name (DN).</param>
/// <param name="Group">A System.DirectoryServices.DirectoryEntry object of the target group.</param>
private Boolean IsMemberOfLargeGroup( String UserDN, DirectoryEntry Group )
{
    Boolean userFound = false;
    Boolean isLastQuery = false;
    Boolean exitLoop = false;
    Int32 rangeStep = 1500;
    Int32 rangeLow = 0;
    Int32 rangeHigh = rangeLow + ( rangeStep - 1 );
    String attributeWithRange;

    DirectorySearcher groupSearch = new DirectorySearcher( Group );
    SearchResult searchResults;

    groupSearch.Filter = "(objectClass=*)";

    do
    {
        if ( !isLastQuery )
            attributeWithRange = String.Format( "member;range={0}-{1}", rangeLow, rangeHigh );
        else
            attributeWithRange = String.Format( "member;range={0}-*", rangeLow );

        groupSearch.PropertiesToLoad.Clear();
        groupSearch.PropertiesToLoad.Add( attributeWithRange );

        searchResults = groupSearch.FindOne();
        groupSearch.Dispose();

        if ( searchResults.Properties.Contains( attributeWithRange ) )
        {
            if ( searchResults.Properties[ attributeWithRange ].Contains( userDN ) )
                userFound = true;

            if ( isLastQuery )
                exitLoop = true;
        }
        else
        {
            isLastQuery = true;
        }

        if ( !isLastQuery )
        {
            rangeLow = rangeHigh + 1;
            rangeHigh = rangeLow + ( rangeStep - 1 );
        }
    }
    while ( ! ( exitLoop | userFound ) );

    return userFound;
}