0

I'm trying to verify all users in a table to make sure they still exist in AD. I modeled my code after the answer to this question. However, on the FindByIdentity call, it's giving me this error:

'The specified directory service attribute or value does not exist.'

Haven't been able to find any answer to this so far. What am I doing wrong?

    private void btnVerifyContactList_Click(object sender, System.EventArgs e)
    {
        txtList.Clear();
        List<string> lst = (List<string>)SQL.GetAllUserADIDs();
        StringBuilder sb = new StringBuilder();

        using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "us.company.com"))
        {
            foreach (string s in lst)
            {
                txtList.AppendText($"ADID: {s} ");
                try
                {

                    using (UserPrincipal foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, s))
                    {
                        if (foundUser == null)
                        {
                            txtList.AppendText($"01\r\n");
                            sb.AppendLine(s);
                        }
                        else
                        {
                            txtList.AppendText($"00\r\n");
                        }
                    }
                }
                catch (Exception)
                {
                    txtList.AppendText($"02\r\n");
                    sb.AppendLine(s);
                }
            }
        }

        txtList.Text = sb.ToString();
    }
tolsen64
  • 881
  • 1
  • 9
  • 22

1 Answers1

0

When you use UserPrincipal.FindByIdentity, it returns a UserPrincipal object. But when creating a UserPrincipal object, it gets all of the attributes for the user. That may be where the exception is occurring. But you also don't need to get that data.

I would suggest using DirectorySearcher directly, which is what FindByIdentity is using in the background anyway. But using it directly lets you control exactly how much information you're getting from AD. This should avoid whatever is causing the exception, but your loop will also run a whole lot faster.

It would look something like this:

private void btnVerifyContactList_Click(object sender, System.EventArgs e)
{
    txtList.Clear();
    List<string> lst = (List<string>)SQL.GetAllUserADIDs();
    StringBuilder sb = new StringBuilder();

    var searchRoot = new DirectoryEntry("LDAP://us.company.com");
    
    foreach (string s in lst)
    {
        txtList.AppendText($"ADID: {s} ");
        try
        {
            var search = new DirectorySearcher(
                searchRoot,
                $"(&(objectClass=user)(objectCategory=person)(sAMAccountName={s}))",
                new [] {"cn"} // without this, it will return every attribute for the user, which we don't need
            );
            
            if (search.FindOne() == null)
            {
                txtList.AppendText($"01\r\n");
                sb.AppendLine(s);
            }
            else
            {
                txtList.AppendText($"00\r\n");
            }
        }
        catch (Exception)
        {
            txtList.AppendText($"02\r\n");
            sb.AppendLine(s);
        }
    }
}

If you wanted to optimize performance even further, you could check all of the users at once (depending on how big the list is). I have an example of something similar in an article I wrote about getting better performance while programming against Active Directory, under the "Ask for as much as you can at a time" heading.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84