title: WMI: Editing the Registry Remotely
body: <p>I'm trying to use the following code (poorly written, but it's just a proof of concept) to edit the registry of a computer on a domain.  I have a domain account, and I've verified that the domain admin group is present in the local admin group on the machines I'm attempting to affect.  I've connected to these other machines to perform other administrative type tasks, so I'm sure that I have administrative privileges on these hosts.  </p>
  
  <p>All of StdRegProv's "get" methods work fine (<a href="http://msdn.microsoft.com/en-us/library/aa393664%28VS.85%29.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/library/aa393664%28VS.85%29.aspx</a>) but the "set" or "create" methods as well as check access all return "5" which is "Error_Access_Denied" according to winerror.h.  So there's the problem: why do I get access denied when attempting to modify the registry?  If anyone can help me figure this out, you'd have my utmost appreciation!</p>
  
  <p>I almost forgot, when I fire up Visual Studio in admin mode on my local machine and run the code against the local machine, it works flawlessly.  If I don't start in admin mode on the local machine, the code fails, so I suspect there's a UAC problem maybe?</p>
  
  <p><strong>UPDATE:</strong> Using regedit and connecting to the remote computer, I CAN change the registry key which leads me to believe that this is not a UAC issue, but it executes with a local WMI connection when running in elevated mode on my own machine, so maybe it is UAC.  Also, winXP machines return the same error-code (5, ERROR_ACCESS_DENIED) which leads me to believe that it's not UAC... this sucks.</p>
  
  <p>SOLVED: The ManagementClass object is using the wrong override; it must be parameterized with the ManagementScope, otherwise, you're just executing functions locally.</p>
  
  <pre><code>ManagementClass mc = new ManagementClass(scope, new ManagementPath("StdRegProv"), null);
  </code></pre>
  
  <p>Yes, I'm an epic-fail :/ 9K lines of code, and this line held me up the longest of them all.</p>
  
  <pre><code>using System;
  using System.Management;
  
  
  public class EditRemoteRegistry
  {
      public static void Main(string[] args)
      {
          ConnectionOptions options = new ConnectionOptions();
          options.EnablePrivileges = true;
          options.Impersonation = ImpersonationLevel.Impersonate;
          options.Password = "password goes here";
          //options.Authority = "my company's domain";
          //options.Username = "Admin username";
  
          ManagementScope scope = new ManagementScope("\\\\arbitraryhost\\root\\default", options);
          scope.Connect();
  
          ManagementClass mc = new ManagementClass("StdRegProv");
  
          ManagementBaseObject inParams = mc.GetMethodParameters("CreateKey");
          inParams["hDefKey"] = (UInt32)2147483650;
          inParams["sSubKeyName"] = "Software\\Test";
          ManagementBaseObject outParams = mc.InvokeMethod("CreateKey", inParams, null);
          //Should return a 0, but returns a 5, "Error_Access_Denied"
          Console.WriteLine("CreateKey Method returned " + outParams["returnValue"]);
  
          //This chunk works fine
          ManagementBaseObject inParams5 = mc.GetMethodParameters("GetDWORDValue");
          inParams5["hDefKey"] = 2147483650;
          inParams5["sSubKeyName"] = "Software\\Test";
          inParams5["sValueName"] = "testDWORDvalue";
          ManagementBaseObject outParams5 = mc.InvokeMethod("GetDWORDValue", inParams5, null);
          Console.WriteLine("GetDWORDValue returned " + (UInt32)outParams5["returnValue"] + " ");
          Console.WriteLine((UInt32)outParams5["uValue"]);
  
  
          ManagementBaseObject inParams6 = mc.GetMethodParameters("SetStringValue");
          inParams6["hDefKey"] = 2147483650;
          inParams6["sSubKeyName"] = "Software\\Test";
          inParams6["sValueName"] = "TestStringValue";
          inParams6["sValue"] = "Hello World!";
          ManagementBaseObject outParams6 = mc.InvokeMethod("SetStringValue", inParams6, null);
          //Should return a 0, but returns a 5, "Error_Access_Denied"
          Console.WriteLine("SetStringValue returned " + outParams6["returnValue"]);
  
          Console.ReadKey();
      }
  }
  </code></pre>