Как установить/изменить пароль пользователя Active Directory через домены с помощью С#.NET?

Я уже довольно давно искал, как устанавливать/изменять пароль и отзывать/восстанавливать пользователя, но еще не найти решение, которое действительно работает для меня.

Я начинаю склоняться к тому, что я пересекаю домены как проблему, хотя я могу программно создавать/удалять/обновлять и даже подключать/отключать пользователей от групп.

В основном, я пробовал следующие способы:

DirectoryEntry account = new DirectoryEntry("LDAP://" + adHostname + "/" + dn, adUserName, adPassword);

account.Invoke("SetPassword", "Password1");
account.Properties["LockOutTime"].Value = 0;
account.CommitChanges();

А также

account.Invoke("SetPassword", new object[] { "Password1" });

Оба они в конечном счете выдают ошибку "Один или несколько входных параметров недействительны \r\n"

Затем я попытался использовать подход .NET 3.5 с использованием основного контекста.

using (var context = new PrincipalContext(ContextType.Domain, adHostname, myContainer, ContextOptions.SimpleBind, adUserName, adPassword))
    {
        using (var user = UserPrincipal.FindByIdentity(context, account.Properties["sAMAccountName"].Value.ToString()))
        {
             user.SetPassword(password);
        }
    }    

Этот подход также вызывает ту же ошибку, что и выше. Если я переключу некоторые вещи (я не могу вспомнить все комбинации, которые я пробовал), это иногда вызывает "Локальная ошибка" COM Exception.

Любая помощь очень ценится.

Ответ 1

См. статью: https://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C#7

Вы заметите, что во всех образцах мы привязываемся непосредственно к directoryEntry и не указываем сервер или учетные данные. Если вы не хотите использовать класс олицетворения, вы можете отправлять учетные данные непосредственно в конструктор DirectoryEntry. Класс олицетворения полезен для тех времен, когда вы хотите использовать статический метод и не хотите, чтобы возникли проблемы с созданием объекта DirectoryContext для хранения этих деталей. Аналогично, вы можете настроить таргетинг на определенный контроллер домена.

Специальные контроллеры домена или учетные данные

Везде в коде, который вы видите: LDAP://вы можете заменить LDAP://MyDomainControllerNameOrIpAddress, а также везде, где вы строите класс DirectoryEntry, вы можете отправлять также определенные учетные данные. Это особенно полезно, если вам нужно работать в Active Directory, для которого ваш компьютер не является его членом или доменом, или вы хотите настроить таргетинг на DC, чтобы внести изменения.

//Переименовать объект и указать контроллер домена и учетные данные напрямую

public static void Rename(string server,
    string userName, string password, string objectDn, string newName)
{
    DirectoryEntry child = new DirectoryEntry("LDAP://" + server + "/" + 
        objectDn, userName, password);
    child.Rename("CN=" + newName);
}

Ответ 2

"new DirectoryEntry" не привязывает учетную запись пользователя. Пользователю необходимо найти пароль для установки пароля. Вот так:

DirectoryEntry account = new DirectoryEntry("LDAP://" + adHostname + "/" + dn, null, null, AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.Signing);

DirectorySearcher search = new DirectorySearcher(account);
search.Filter = "(&(objectClass=user)(sAMAccountName=" + adUserName + "))";
account = search.FindOne().GetDirectoryEntry();

account.Invoke("SetPassword", "Password1");
account.Properties["LockOutTime"].Value = 0;
account.CommitChanges();

Ответ 3

Этот всегда работает для меня. Надеюсь, поможет. Сначала добавьте ссылку на System.DirectoryServices.AccountManagement

    string hostName = "myDomain";
    string adminName = "admin";
    string adminPassword = "password";

    public static void ResetPassword(string username, string password)
            {
        using (PrincipalContext pContext = new PrincipalContext(ContextType.Domain, hostName, adminName, adminPassword))
                                {
                                    UserPrincipal up = UserPrincipal.FindByIdentity(pContext, username);
                                    if (up != null)
                                    {
                                        up.SetPassword(password);
                                        up.Save();
                                    }
                                }
                        }

Вы также можете делать все возможное для UserPrincipal, например, для учетной записи блокировки, истечения срока действия пароля, получения последнего входа и т.д.