2010-10-25 3 views
6

Мне нужно запросить текущий контроллер домена, возможно, основной для изменения пароля пользователя.Определить текущий контроллер домена программно

(P) имя DC должно быть полным, т.е. DC=pdc,DC=example,DC=com (как правильно назвать такие обозначения?)

Как это можно сделать с помощью C#?

ответ

1

(требуется 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))); 
} 
+0

Это не будет работать для ситуации в междоменном пространстве (например, ваш компьютер не является частью домена, где существует контроллер домена). См. Мой ответ для такого решения. –

+0

@Firo: Спасибо, исправлено. Ошибка была исправлена ​​с помощью 'string []' -> 'IEnumerable ' – abatishchev

0

Если вы хотите, чтобы взаимодействовать с Active Directory, вы не должны знать, где FSMO роли по большей части. Если вы хотите изменить топологию AD из своей программы (я бы этого не сделал), посмотрите на класс DomainController.

Если вы хотите изменить пароль пользователя, вы можете вызвать эти действия в объекте User, а Active Directory будет убедиться, что изменения были правильно реплицированы.

скопирована из 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"); 
} 
+0

Как вы думаете, могу ли я изменить свой текущий пароль, используя собственное имя пользователя и текущий пароль? – abatishchev

2

Мы используем что-то подобное для наших внутренних приложений.

Если вернуть что-то вроде 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; 
} 
+0

Да, вы правы. Обычно у нас есть определенный код ведения журнала в инструкции catch, но я взял его для этого примера. – Lareau

+1

@abatishchev: это утверждение неверно - вызов просто 'throw' будет ** сохранять ** трассировку стека; создавая новое исключение или делая «throw ex;», нарушит стек вызовов; см .: http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx –

+0

@marc_s: да, вы правильно, я ошибся (по фразе о трассировке стека). в любом случае это не имеет смысла до регистрации и т. д., поскольку @Lareau сказал – abatishchev

5

Чтобы получить информацию, когда DomainController существует в домене, в котором ваша машина не принадлежит, вам нужно что-то другое.

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

    var domain = System.DirectoryServices.ActiveDirectory.Domain.GetDomain(domainContext); 
    var controller = domain.FindDomainController(); 
+0

Я не хочу передавать имя пользователя и пароль. – abatishchev

+0

К сожалению, если вы пересекаете домены, вам нужно. В противном случае ваша существующая идентификация не будет распознана. Даже с «новым» пространством имен 3.5 'System.DirectoryServices.AccountManagement' вам нужно будет указать действительное имя пользователя/пароль в * внешнем * домене. –

+0

Это не работает, потому что ваш локальный компьютер не сможет найти DC для этого домена. – Bluebaron

Смежные вопросы