title: How can I change several Active Directory user passwords?
body: <p>I'm trying to programaticaly change several user's password, specifically without using System.DirectoryServices.AccountManagement (PrincipalContext)
  I have this piece of working code:</p>
  
  <pre><code>using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.DirectoryServices;
  
  namespace ADScriptService.core
  {
      class ExportTool
      {
          const AuthenticationTypes = AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind;
          private static DirectoryEntry directoryEntry = new DirectoryEntry(ADScriptService.Properties.Settings.Default.ActiveDirectoryPath, ADScriptService.Properties.Settings.Default.ServerAdminUser, ADScriptService.Properties.Settings.Default.ServerAdminPwd, AuthenticationTypes.Secure);
          private static DirectorySearcher search = new DirectorySearcher(directoryEntry);
      public void Export()
      {
  
          string path = ADScriptService.Properties.Settings.Default.ActiveDirectoryPath;
          string adminUser = ADScriptService.Properties.Settings.Default.ServerAdminUser;
          string adminPassword = ADScriptService.Properties.Settings.Default.ServerAdminPwd;
  
          string userName = "exampleUser";
          string newPassword = "P455w0rd";
          try
          {
              search.Filter = String.Format("sAMAccountName={0}", userName);
              search.SearchScope = SearchScope.Subtree;
              search.CacheResults = false;
              SearchResult searchResult = search.FindOne();
              if (searchResult == null) Console.WriteLine("User Not Found In This Domain");
              DirectoryEntry userEntry = searchResult.GetDirectoryEntry();
  
              userEntry.Path = userEntry.Path.Replace(":389", "");
              Console.WriteLine(String.Format("sAMAccountName={0}, User={1}, path={2}", userEntry.Properties["sAMAccountName"].Value, userEntry.Username, userEntry.Path));
              userEntry.Invoke("SetPassword", new object[] { newPassword });
              userEntry.Properties["userAccountControl"].Value = 0x0200 | 0x10000;
              userEntry.CommitChanges();
              Console.WriteLine("Se ha cambiado la contraseña");
  
  
          }
          catch (Exception ex)
          {
              Console.WriteLine(ex);
          }
      }
  }
  }
  </code></pre>
  
  <p>This is an example with a single user, but what my program should do is iterate through ~120k users.
  However, the operation of setting the search filter, finding one result and getting the DirectoryEntry takes about 2 or 3 seconds per user so I'm trying to use the DirectoryEntries structure given by the DirectoryEntry.Children property, which means replacing the six lines after "try{" with simply <code>DirectoryEntry userentry = directoryEntry.Children.Find("CN=" + userName);</code></p>
  
  <p>So the example's code would look like this:</p>
  
  <pre><code>using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.DirectoryServices;
  
  namespace ADScriptService.core
  {
      class ExportTool
      {
          const AuthenticationTypes = AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind;
          private static DirectoryEntry directoryEntry = new DirectoryEntry(ADScriptService.Properties.Settings.Default.ActiveDirectoryPath, ADScriptService.Properties.Settings.Default.ServerAdminUser, ADScriptService.Properties.Settings.Default.ServerAdminPwd, AuthenticationTypes.Secure);
          private static DirectorySearcher search = new DirectorySearcher(directoryEntry);
      public void Export()
      {
  
          string path = ADScriptService.Properties.Settings.Default.ActiveDirectoryPath;
          string adminUser = ADScriptService.Properties.Settings.Default.ServerAdminUser;
          string adminPassword = ADScriptService.Properties.Settings.Default.ServerAdminPwd;
  
          string userName = "exampleUser";
          string newPassword = "P455w0rd";
          try
          {
              DirectoryEntry userEntry = directoryEntry.Children.Find("CN=" + userName);
  
              userEntry.Path = userEntry.Path.Replace(":389", "");
              Console.WriteLine(String.Format("sAMAccountName={0}, User={1}, path={2}", userEntry.Properties["sAMAccountName"].Value, userEntry.Username, userEntry.Path));
              userEntry.Invoke("SetPassword", new object[] { newPassword });
              userEntry.Properties["userAccountControl"].Value = 0x0200 | 0x10000;
              userEntry.CommitChanges();
              Console.WriteLine("Se ha cambiado la contraseña");
  
  
          }
          catch (Exception ex)
          {
              Console.WriteLine(ex);
          }
      }
  }
  }
  </code></pre>
  
  <p>But this code gets the following error in the invocation line <code>(userEntry.Invoke("SetPassword", new object[] { newPassword });</code>:</p>
  
  <pre><code>System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---&gt; System.Runtime.InteropServices.COMException: The RPC server is unavailable. (Excepción de HRESULT: 0x800706BA)
  </code></pre>
  
  <p>which in english means RCP server unavailable. I've been stuck here for some days, and I've only found that it can be because of some authentication problem.
  Invoking the method "Groups" works (<code>userEntry.Invoke("Groups");</code>) and the administrator, which is the user I'm loging in with to the ActiveDirectory has all the privileges. Also the password policy is completly permissive with no minimum lenght or complexity.</p>
  
  <p>Again, because the program must iterate through, the real program actually iterates through the DirectoryEntry's children with:</p>
  
  <pre><code>foreach(DirectoryEntry child in directoryEntry.Children) 
  {
      child.Invoke("SetPassword", new object[] { newPassword });
      child.CommitChanges();
  }
  </code></pre>
  
  <p>Thank you very much!</p>