10

I have an application that checks to see if a user exists (if not create it) every time it starts. This is done as follows:

bool bUserExists = false;
DirectoryEntry dirEntryLocalMachine = 
    new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");

DirectoryEntries dirEntries = dirEntryLocalMachine.Children;

foreach (DirectoryEntry dirEntryUser in dirEntries)
{
    bUserExists = dirEntryUser.Name.Equals("UserName", 
        StringComparison.CurrentCultureIgnoreCase);

    if (bUserExists)
      break;
}

The problem is on the majority of the systems where it is deployed. This can take 6 - 10 seconds, which is too long ... I need to find a way to reduce this (as much as possible). Is there a better or faster way I can use to verify if a user exists on the system or not?

I know there are other ways to solve this, like have the other applications sleep for 10 seconds, or have this tool send a message when it is ready, etc... But if I can greatly reduce the time it takes to find the user, it would make my life much easier.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shaitan00
  • 303
  • 1
  • 6
  • 20

4 Answers4

26

.NET 3.5 supports new AD querying classes under the System.DirectoryServices.AccountManagement namespace.

To make use of it, you'll need to add "System.DirectoryServices.AccountManagement" as a reference AND add the using statement.

using System.DirectoryServices.AccountManagement;


using (PrincipalContext pc = new PrincipalContext(ContextType.Machine))
{
    UserPrincipal up = UserPrincipal.FindByIdentity(
        pc,
        IdentityType.SamAccountName,
        "UserName");

    bool UserExists = (up != null);
}

< .NET 3.5

For versions of .NET prior to 3.5, here is a clean example I found on dotnet-snippets

DirectoryEntry dirEntryLocalMachine =
    new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");

bool UserExists =
    dirEntryLocalMachine.Children.Find(userIdentity, "user") != null;
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Michael La Voie
  • 27,772
  • 14
  • 72
  • 92
  • Sadly I cannot use .NET 3.5, I am stuck with .NET 2.0... Is there an equivalent? – Shaitan00 Nov 04 '09 at 19:04
  • I updated my answer to include a great article on exactly what you're looking for. It is very similar to your current method, but instead of enumerating through every object, it uses the Children.Find() function. Please click the link as the article has a complete class to handle this and it is very nice. – Michael La Voie Nov 04 '09 at 19:54
  • :( - That's too bad and I don't know any other solutions that weren't mentioned. Of course, you could re-evaluate whether that logic needs to be called every time or if it needs to be called on start up. Perhaps put it in a thread to let the user start working? Otherwise, perceptions play a big role, showing a progress bar with an exponential acceleration (ie: slow for 2 sec, medium speed for 2 sec, then super fast for last two) can create the perception of fast loading. If all else fails, try this:http://stackoverflow.com/questions/182112/funny-loading-statements-to-keep-users-amused – Michael La Voie Nov 04 '09 at 22:42
6

You want to use the DirectorySearcher.

Something like this:

static bool userexists( string strUserName ) {
    string adsPath = string.Format( @"WinNT://{0}", System.Environment.MachineName );
    using( DirectoryEntry de = new DirectoryEntry( adsPath ) ) {
        try {
            return de.Children.Find( strUserName ) != null;
        } catch( Exception e ) {
            return false;
        }
    }
}

That should be quicker. Also, you can reduce the properties if all you are doing is checking for existence.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Beached
  • 1,608
  • 15
  • 18
  • This is a fast method AND it works with .NET versions prior to 3.5 (if that is your environment). – Michael La Voie Nov 04 '09 at 19:04
  • I'm not that familiar with DirectoryEntry (active directory and stuff), which properties are not needed to be 100% certain the user does not already exist if I only have the UserName to go by? – Shaitan00 Nov 04 '09 at 19:08
  • Actually, don't include any and it should be fine. I was just giving a generic example in case you wanted info on them too. So the filter is what you want and then the searchresult. – Beached Nov 04 '09 at 19:34
  • Beached: There are a couple of issues with that snipplet of code, for example string strDomainName uses ds but ds is created later and uses de which ises strDomainName (cyclic issue)... – Shaitan00 Nov 04 '09 at 19:37
  • I was wrong about DirectorySearcher. It only works with AD. I have updated the solution to use the Find method on the DirectoryEntry object. – Beached Nov 04 '09 at 23:04
1

Another way is the following (supports either local or domain user):

bool UserExists(string userName)
{
    var user = new NTAccount(userName);
    try
    {
        var sid = (SecurityIdentifier)user.Translate(typeof(SecurityIdentifier));
        return true;
    }
    catch (IdentityNotMappedException)
    {
        return false;
    }
}

User may be either unqualified, or qualified by machine/domain name (DOMAIN\UserName). If you need to specifically detect if the account exists on local machine, qualify it by Environment.MachineName ($"{Environment.MachineName}\\{userName}").

Mike Rosoft
  • 628
  • 7
  • 10
0

The following in a command prompt returns 1 if 'username' exists.

net user | find "username" /c

kenny
  • 21,522
  • 8
  • 49
  • 87