13

This morning I discovered a nice method (DirectoryEntry.Exists), that should be able to check whether an Active Directory object exists on the server. So I tried with a simple:

if (DirectoryEntry.Exists(path)) {}

Of course it lacks any overloads to provide credentials with it. Because, if credentials are not provided I get this Exception:

Logon failure: unknown user name or bad password. (System.DirectoryServices.DirectoryServicesCOMException)

Is there any other option that gives me the possibility to authenticate my code at the AD server? Or to check the existence of an object?

rae1
  • 6,066
  • 4
  • 27
  • 48
Herman Cordes
  • 4,628
  • 9
  • 51
  • 87

6 Answers6

18

In this case you can't use the static method Exists as you said :

DirectoryEntry directoryEntry = new DirectoryEntry(path);
directoryEntry.Username = "username";
directoryEntry.Password = "password";

bool exists = false;
// Validate with Guid
try
{
    var tmp = directoryEntry.Guid;
    exists = true;
}
catch (COMException)
{
   exists = false; 
}
JoeBilly
  • 3,057
  • 29
  • 35
  • That would be my preferred solution, but this property doesn't seem static to me, have a look: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.username.aspx – Herman Cordes Nov 26 '10 at 14:31
  • Oh I see nevermind. Yep you'll have to instanciate a new DirectoryEntry. Edited. – JoeBilly Nov 26 '10 at 15:31
  • Thanks for a nice code sample. Apparently that's the only way. It's a pitty that it's not possible with default .net methods, but at least a nice workaround does the job! – Herman Cordes Nov 29 '10 at 14:11
  • This will mostly work, but will return `false` in cases where it could not verify that it doesn't actually exist (network error, unknown domain, etc.). I just [posted an answer](https://stackoverflow.com/a/59651154/1202807) that borrows the [source code for `DirectoryEntry.Exists`](https://source.dot.net/#System.DirectoryServices/System/DirectoryServices/DirectoryEntry.cs,737) to return `false` only when it's known to not exist, and rethrows any other exception. – Gabriel Luci Jan 08 '20 at 17:45
5

I know this is an old question, but the source code is now available so you can just Steal and Modify™ to make a version that accepts credentials:

public static bool Exists(string path, string username, string password)
{
    DirectoryEntry entry = new DirectoryEntry(path, username, password);
    try
    {
        _ = entry.NativeObject;       // throws exceptions (possibly can break applications)
        return true;
    }
    catch (System.Runtime.InteropServices.COMException e)
    {
        if (e.ErrorCode == unchecked((int)0x80072030) ||
             e.ErrorCode == unchecked((int)0x80070003) ||   // ERROR_DS_NO_SUCH_OBJECT and path not found (not found in strict sense)
             e.ErrorCode == unchecked((int)0x800708AC))     // Group name could not be found
            return false;
        throw;
    }
    finally
    {
        entry.Dispose();
    }
}

The one change you must make is changing the use of Bind, since that's an internal method and can't be used by mere mortals like us. Instead, I just get the NativeObject property, which calls Bind() for us.

You can use that like this:

var ouExists = Exists("LDAP://hadoop.com/OU=Students,DC=hadoop,DC=com", "username", "password");
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
2

There is no way to do this and I have written a connect issue to hopefully resolve it.

DirectoryEntry.Exists Does Not Accept Credentials

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
1

Here you can read about impersonation in C#:

Patrik Svensson
  • 13,536
  • 8
  • 56
  • 77
1

So answer to the question: impossible.

Finally write an own method to get the DirectoryEntry by distinguised name, with credentials specified. In both cases of existence/inexistence I got an instance of DirectoryEntry. To check whether it's a valid object returned I do a simple try...catch to see if it results in an Exception. If so, it's invalid.

Nasty check, but it works. Too bad the default .net method DirectoryEntry.Exists doesn't provide an overload to provide credentials just like the DirectoryEntry constructor...

Herman Cordes
  • 4,628
  • 9
  • 51
  • 87
0

If the user who ran the process doesn't have permissions to call DirectoryEntry.Exists, then you can use impersonation.

This may be helpful (discusses impersonation in an AD context): http://www.codeproject.com/KB/system/everythingInAD.aspx

Btw, if you already have credentials of a user who has access to everything you need, why not just the process with that user (e.g. /runas)?

SpeksETC
  • 1,003
  • 2
  • 7
  • 13
  • Thanks. Found that like also, but doesn't provide me a descent solution to my problem. Runas is really not an option in my current project... Impersonation neither, but seems the best so far. – Herman Cordes Nov 26 '10 at 10:17