Search code examples
c#.netdirectoryentry

DirectoryEntry.Exist in C# taking more than 10 Sec time when AD/NT user is not present


Issue can also be triggered with the following simple application:

Stopwatch watch = new Stopwatch();
string[] userNames = {"JunkName", "DummyName"};

foreach (var name in userNames)
{
    watch.Reset();
    watch.Start();

    if (DirectoryEntry.Exists("WinNT://" + Environment.MachineName + "/" + name))
    {
        Console.WriteLine($"user {name} found in " + watch.ElapsedMilliseconds + "ms");
    }
    else
    {
        Console.WriteLine($"user {name} not found in " + watch.ElapsedMilliseconds + "ms");
    }
}

There is no proper root cause for this to tell is it Microsoft API issue or something else.

However most of the search results mention if you search for a user that does not exist, rather than return false, the DirectoryEntry.Exists method will throw an exception.

But in our sample application it is not throwing any exception.

Also I tried below few suggestions to check how much execution time these sample code takes and found these will also takes more than 11 seconds the first time.

Sample 1:

using (PrincipalContext pc = new PrincipalContext(ContextType.Machine))
{
    UserPrincipal up = UserPrincipal.FindByIdentity(pc,
                    IdentityType.SamAccountName, name);
 
    UserExists = (up != null);
}

Sample 2:

DirectoryEntry dirEntryLocalMachine =
    new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
 
bool UserExists =
    dirEntryLocalMachine.Children.Find(userIdentity, "user") != null;

It’s just a high level suspicion that OS updates would have caused the problem, may be my assumption is wrong.

Thanks in advance


Solution

  • I encoutered the same latence one day, so I wrote this function that is much faster, maybe it can help you:

        private string FindUserSID(string domain, string user)
        {
            string output;
    
            try
            {
                NTAccount account = new NTAccount(domain + @"\" + user);
                SecurityIdentifier s = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));
                output = s.ToString();
            }
            catch (IdentityNotMappedException)
            {
                output = null;
            }
    
            return output;
        }