Determine current domain controller programmatically
Asked Answered
B

4

7

I need to query current domain controller, probably primary to change user password.

(P)DC name should be fully qualified, i.e. DC=pdc,DC=example,DC=com (how to properly name such notation?)

How can it be done using C#?

Badman answered 25/10, 2010 at 14:14 Comment(0)
B
2

(requires System.DirectoryServices.AccountManagement.dll):

using (var context = new System.DirectoryServices.AccountManagement.PrincipalContext(ContextType.Domain))
{
    string server = context.ConnectedServer; // "pdc.examle.com"
    string[] splitted = server.Split('.'); // { "pdc", "example", "com" }
    IEnumerable<string> formatted = splitted.Select(s => String.Format("DC={0}", s));// { "DC=pdc", "DC=example", "DC=com" }
    string joined = String.Join(",", formatted); // "DC=pdc,DC=example,DC=com"

    // or just in one string

    string pdc = String.Join(",", context.ConnectedServer.Split('.').Select(s => String.Format("DC={0}", s)));
}
Badman answered 25/10, 2010 at 14:35 Comment(1)
This won't work for a cross-domain situation (e.g. your machine isn't part of the domain where the Domain Controller exists). See my answer for such a solution.Merrymerryandrew
M
6

To retrieve the information when the DomainController exists in a Domain in which your machine doesn't belong, you need something more.

  DirectoryContext domainContext =  new DirectoryContext(DirectoryContextType.Domain, "targetDomainName", "validUserInDomain", "validUserPassword");

  var domain = System.DirectoryServices.ActiveDirectory.Domain.GetDomain(domainContext);
  var controller = domain.FindDomainController();
Merrymerryandrew answered 13/11, 2012 at 14:44 Comment(3)
I don't want to pass user name and password.Badman
Unfortunately if you're crossing domains, you need to. Your existing Identity won't be recognized otherwise. Even with the "new" 3.5 System.DirectoryServices.AccountManagement namespace you would have to include a valid username/password on the external domain.Merrymerryandrew
This doesn't work because your local computer will not be able to find a DC for that domain.Supersensible
B
2

(requires System.DirectoryServices.AccountManagement.dll):

using (var context = new System.DirectoryServices.AccountManagement.PrincipalContext(ContextType.Domain))
{
    string server = context.ConnectedServer; // "pdc.examle.com"
    string[] splitted = server.Split('.'); // { "pdc", "example", "com" }
    IEnumerable<string> formatted = splitted.Select(s => String.Format("DC={0}", s));// { "DC=pdc", "DC=example", "DC=com" }
    string joined = String.Join(",", formatted); // "DC=pdc,DC=example,DC=com"

    // or just in one string

    string pdc = String.Join(",", context.ConnectedServer.Split('.').Select(s => String.Format("DC={0}", s)));
}
Badman answered 25/10, 2010 at 14:35 Comment(1)
This won't work for a cross-domain situation (e.g. your machine isn't part of the domain where the Domain Controller exists). See my answer for such a solution.Merrymerryandrew
C
2

We are using something like this for our internal applications.

Should return something like DC=d,DC=r,DC=ABC,DC=com

public static string RetrieveRootDseDefaultNamingContext()
{
    String RootDsePath = "LDAP://RootDSE";
    const string DefaultNamingContextPropertyName = "defaultNamingContext";

    DirectoryEntry rootDse = new DirectoryEntry(RootDsePath)
    {
        AuthenticationType = AuthenticationTypes.Secure;
    };
    object propertyValue = rootDse.Properties[DefaultNamingContextPropertyName].Value;

    return propertyValue != null ? propertyValue.ToString() : null;
}
Celebrity answered 25/10, 2010 at 15:23 Comment(3)
Yes you're right. We normally have some custom logging code in the catch statement but I took it out for this example.Celebrity
@abatishchev: that statement is wrong - calling just throw will preserve the stack trace; creating a new exception or doing throw ex; would break the call stack; see: weblogs.asp.net/fmarguerie/archive/2008/01/02/…Bough
@marc_s: yea, you're right, i was wrong (in phrase about stack trace). anyway this makes no sense until logging, etc as @Celebrity saidBadman
C
0

If you are looking to interact the Active Directory, you shouldn't have to know where the FSMO roles are for the most part. If you want to change the AD topology from your program (I wouldn't), look at the DomainController class.

If you want to change a user password, you can invoke those actions on the User object, and Active Directory will make sure that the changes are properly replicated.

copied from http://www.rootsilver.com/2007/08/how-to-change-a-user-password

public static void ChangePassword(string userName, string oldPassword, string newPassword)
{
        string path = "LDAP://CN=" + userName + ",CN=Users,DC=demo,DC=domain,DC=com";

        //Instantiate a new DirectoryEntry using an administrator uid/pwd
        //In real life, you'd store the admin uid/pwd  elsewhere
        DirectoryEntry directoryEntry = new DirectoryEntry(path, "administrator", "password");

        try
        {
           directoryEntry.Invoke("ChangePassword", new object[]{oldPassword, newPassword});
        }
        catch (Exception ex)  //TODO: catch a specific exception ! :)
        {
           Console.WriteLine(ex.Message);
        }

        Console.WriteLine("success");
}
Cantwell answered 25/10, 2010 at 14:36 Comment(1)
how do you think, can I change my current password using my own user name and current password?Badman

© 2022 - 2024 — McMap. All rights reserved.