Brian Mitchell
Brian Mitchell

Reputation: 929

C# - query large number of AD users / a device attached to the system is no longer functioning

I am retrieving a handful of LDAP (Active Directory) properties for about 10,000 users. I know that AD queries aren't the fastest in the world but at the 19 minute mark (almost exactly) the program stops processing and about 15 minutes after that I get the error

A device attached to the system is no longer functioning

on the DirectorySearcher.FindOne() method.

I don't think I'm doing anything weird in the code but I'm wondering if I need to re-write this to a FindAll() and then parse though that list.

searcher.Filter = "(sAMAccountName=" + u.LogonName + ")";

string[] properties = new string[]
         {
                "givenName",
                "sn",
                "displayName",
                "mail",
                "physicalDeliveryOfficeName",
                "division",
                "grpDivision"
         };

searcher.PropertiesToLoad.AddRange(properties);

SearchResult result = searcher.FindOne();

It doesn't stop on the same user every time and on the user it does stop on I've checked their attributes for anything that stands out and can't find anything out of the ordinary.

As you can imagine it gets quite tedious debugging in 35 minute increments so I'm hoping someone has seen this before or know about some hidden Active Directory connection time limit.

Thanks!

Upvotes: -1

Views: 1482

Answers (3)

BateTech
BateTech

Reputation: 6526

We ran into this recently, where a System.DirectoryServices.DirectoryServicesCOMException was thrown when attempting to query AD via DirectorySearcher.FindAll with the error message:

A device attached to the system is not functioning

When this happens, you can catch that specific exception type (DirectoryServicesCOMException) and check the ExtendedErrorMessage property (https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices.directoryservicescomexception.extendederrormessage?view=dotnet-plat-ext-8.0#system-directoryservices-directoryservicescomexception-extendederrormessage) for additional info.

For example: In our case the ExtendedErrorMessage returned "00000008: SysErr: DSID-03021BAA, problem 12 (Not enough space), data 0" (where the 8 characters after "DSID-" are pointers to the file and line number in the AD source code so is something that might be helpful to Microsoft support but not in general for normal troubleshooting, but the rest of the message is helpful). This indicated there was some issue going on with one of our domain controllers (either out of disk space, or running out of RAM while executing the LDAP query). Our infrastructure team was able to find an unresponsive DC, reboot it, and then the error went away.

The main point is that the generic error message "A device attached to the system is not functioning" can be caused by different things, so check DirectoryServicesCOMException.ExtendedErrorMessage for more info.

Upvotes: 0

Jerry Federspiel
Jerry Federspiel

Reputation: 1524

Let's get your results in the biggest chunks we can. Getting results one-at-a-time is very slow. Unless you have tweaked your DC's settings, you can't get all 10,000 members at once; the default settings are to return a max of 1000 results at a time. So we'll do 26 queries, one for each letter a sAMAccountName might start with, using the * operator.

public static IEnumerable<SearchResult> DirectMembers(string nameOfMyBigGroup)
{
    var namePrefixes = "abcdefghijklmnopqrstuvwxyz".Select(c=>c.ToString());
    foreach(var namePrefix in namePrefixes) 
    {
        searcher.Filter = "(&(sAMAccountName=" + namePrefix + "*)(memberOf=" + nameOfMyBigGroup + "))";

        string[] properties = new string[]
            {
                "givenName",
                "sn",
                "displayName",
                "mail",
                "physicalDeliveryOfficeName",
                "division",
                "grpDivision"
            };

        searcher.PropertiesToLoad.AddRange(properties);

        var results = searcher.FindAll();
        foreach (var result in results) yield return result;
    }
}

EDIT: This assumes that your domain is set up such that sAMAccountName is case-insensitive, and that your users all have names whose first letters are drawn from the English alphabet. If these assumptions are not met, you'd want to do a more robust solution involving paging.

Upvotes: 0

Brian Mitchell
Brian Mitchell

Reputation: 929

While I don't have a solid root cause - the problem has gone away. I haven't changed my code but when I tried it from home (on a VPN connection) the program successfully completes. It now takes 110 minutes due to the slower connection but it doesn't error out anymore.

Obviously it was something stemming from the server so I'm thinking I hit one of two possibilities.

  1. I was bombarding the DC while on the LAN and it couldn't keep up.
  2. The after-hours load on the DC is much lighter and allowing more resources to be allocated to my queries.

Upvotes: -1

Related Questions