title: Unable to remotely terminate a process using WMI and C#
body: <p>I am trying to write a method that will terminate a service on a remote system, by process ID, if it fails to stop using the StopService method. I have tried two different ways of invoking the "Terminate" method on a ManagementObject, and I get two different errors. It's also important to me that I be able to get the return code from the Terminate method.</p>
  
  <p>If I declare a ManagementPath directly to the process I want to terminate, I get the error "System.Management.ManagementException: Invalid object path" at line:</p>
  
  <p><code>ManagementBaseObject processParams = processObj.InvokeMethod("Terminate", (ManagementBaseObject)null, null);</code></p>
  
  <p>If I get a ManagementObjectCollection and loop through it looking for the Process ID I want to terminate, I get the error "Invalid parameter" at line:</p>
  
  <p><code>ManagementBaseObject termParams = currentObj.InvokeMethod("Terminate", (ManagementBaseObject)null, null);</code></p>
  
  <p>So, in both cases, I get an error when I try to invoke the Terminate method, but the error differs depending on how I arrive at the object (direct path or loop through collection).</p>
  
  <p>I don't <em>think</em> this is related to SeDebugPrivilege, as I believe I'd be getting "access denied" or "insufficient privilege" if it was.</p>
  
  <p>Code if I attempt to directly specify the path to the process:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public int KillServiceWMI(string serviceName, string serverName, string serverUser, string serverDomain, string serverPassword)
  {
      try
      {
          ConnectionOptions options = new ConnectionOptions();
          options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
          options.Username = serverDomain + "\\" + serverUser;
          options.Password = serverPassword;
  
          ManagementScope scope = new ManagementScope("\\\\" + serverName + "\\root\\cimv2", options);
          Console.WriteLine("Connecting to scope");
          scope.Connect();
  
          Console.WriteLine("Getting ManagementPath");
          ManagementPath servicePath = new ManagementPath("Win32_Service.Name='" + serviceName + "'");
          Console.WriteLine("Getting ManagementObject");
          ManagementObject serviceObj = new ManagementObject(scope, servicePath, new ObjectGetOptions());
          Console.WriteLine("Name of service is " + serviceObj["DisplayName"].ToString());
          Console.WriteLine("Process ID of service is " + serviceObj["ProcessId"].ToString());
          ManagementPath processPath = new ManagementPath("Win32_Process.ProcessId='" + serviceObj["ProcessId"] + "'");
          ManagementObject processObj = new ManagementObject(scope, processPath, new ObjectGetOptions());
          ManagementBaseObject processParams = processObj.InvokeMethod("Terminate", (ManagementBaseObject)null, null);
          int returnCode = System.Convert.ToInt32(processParams.Properties["ReturnValue"].Value);
          return returnCode;
      }
      catch (Exception connectEx)
      {
          Console.WriteLine("Connecting to " + serverName + " caused an exception");
          Console.Write(connectEx);
          return 99;
      }
  }
  </code></pre>
  
  <p>Code if I loop through a collection of processes:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public int KillServiceWMI(string serviceName, string serverName, string serverUser, string serverDomain, string serverPassword)
  {
      try
      {
          ConnectionOptions options = new ConnectionOptions();
          options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
          options.Username = serverDomain + "\\" + serverUser;
          options.Password = serverPassword;
  
          ManagementScope scope = new ManagementScope("\\\\" + serverName + "\\root\\cimv2", options);
          Console.WriteLine("Connecting to scope");
          scope.Connect();
  
          Console.WriteLine("Getting ManagementPath");
          ManagementPath servicePath = new ManagementPath("Win32_Service.Name='" + serviceName + "'");
          Console.WriteLine("Getting ManagementObject");
          ManagementObject serviceObj = new ManagementObject(scope, servicePath, new ObjectGetOptions());
          Console.WriteLine("Name of service is " + serviceObj["DisplayName"].ToString());
          Console.WriteLine("Process ID of service is " + serviceObj["ProcessId"].ToString());
          ObjectQuery serviceQuery = new ObjectQuery("SELECT * from Win32_Process WHERE ProcessID = '" + serviceObj["ProcessId"].ToString() + "'");
          ManagementObjectSearcher serviceSearcher = new ManagementObjectSearcher(scope, serviceQuery);
          ManagementObjectCollection serviceColl = serviceSearcher.Get();
          int returnCode = 0;
          foreach (ManagementObject currentObj in serviceColl)
          {
              if (currentObj["ProcessId"].ToString().Equals(serviceObj["ProcessId"].ToString(), StringComparison.OrdinalIgnoreCase))
              {
                  Console.WriteLine("Found process " + currentObj["ProcessId"].ToString() + ". Terminating...");
  
                  ManagementBaseObject termParams = currentObj.InvokeMethod("Terminate", (ManagementBaseObject)null, null);
                  returnCode = System.Convert.ToInt32(termParams.Properties["ReturnValue"].Value);
              }
          }
          return returnCode;
      }
      catch (Exception connectEx)
      {
          Console.WriteLine("Connecting to " + vaultName + " caused an exception");
          Console.Write(connectEx);
          return 99;
      }
  }
  </code></pre>