WMI remote process fails to start, starts locally fine - c#

The following code works when "SelectedMachine" is the localhost where the C# exe is being launched from. When "SelectedMachine" is a remote machine, the process simply doesn't launch. No exceptions, no errors, acts as if it's successful, however, the process never starts. Any ideas?
object[] processToRun = { "notepad.exe" };
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.Authentication = AuthenticationLevel.PacketPrivacy;
connOptions.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", SelectedMachine), connOptions);
manScope.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_Process");
ManagementClass processClass = new ManagementClass(manScope, managementPath, objectGetOptions);
processClass.InvokeMethod("Create", processToRun );
Edit: When I go through wbemtest, same behavior occurs. When the Namespace is root\cimv2 (local), the process executes, when it is \RemoteMachineName\root\cimv2, it claims success but never starts on the remote machine. Not sure what I'm missing here.

This behavior is described in the Win32_Process.Create method documentation.
For security reasons the Win32_Process.Create method cannot be used to
start an interactive process remotely.

Related

C# WMI Error Message "Not Supported"

I'm trying to install/add a networked printer on a remote computer using WMI. The below code works perfectly when i enter my local computer name but i get an error message "Not Supported" when i use any remote computer name. I looked up the WMI Error on MSDN and read "Feature or operation is not supported." But also noticed on MSDN they have a 'howto' add a new printer connection to a remote computer and there VBs example. I copied the VBs example and ran it and also recieved the same error "Not Supported". What am i missing? Any idea on what I'm doing wrong?
ConnectionOptions conOp = new ConnectionOptions();
conOp.Impersonation = ImpersonationLevel.Impersonate;
conOp.Authentication = AuthenticationLevel.Default;
conOp.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(#"\\pcname\ROOT\CIMV2", conOp);
manScope.Connect();
ManagementClass manClass = new ManagementClass(manScope, new ManagementPath("Win32_Printer"), null);
ManagementBaseObject inParams = manClass.GetMethodParameters("AddPrinterConnection");
inParams["Name"] = #"\\server\printer";
////////Error Occurs Here
ManagementBaseObject outParams = manClass.InvokeMethod("AddPrinterConnection", inParams, null);

Lauch a process on a remote machine with impersonation c#

I'm trying to launch a process using impersonation with WMI and C#.
Here's what I have so far:
var coptions = new ConnectionOptions();
coptions.Username = String.Format(#"{0}\{1}", machine.Domain, machine.Username);
coptions.Password = machine.Password;
coptions.Impersonation = ImpersonationLevel.Impersonate;
coptions.EnablePrivileges = true;
var mScope = new ManagementScope(String.Format(#"\\{0}\root\cimv2", machine.Address), coptions);
var mClass = new ManagementClass(mScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
object[] generatorProcess = { #"C:\test\test1.exe" };
mClass.InvokeMethod("Create", generatorProcess);
Exception:
E_ACCESSDENIED at mClass.InvokeMethod
How can I do it?
PS: The user I'm launching the process with does not have admin privileges, is it required?
EDIT: It works with an admin, looks like it's the user..
I've followed this guide here to try and give permissions without sucess.
https://support.infosim.net/demo/wmi/wmi.html
Help please
Basically, you can't do it with an account that has limited permissions. You can tweak the permissions on the WMI object to read but not to write it does not work at all.

Run command on remote computer

I want to run a command in command prompt on a remote computer using C#. Per this link How to execute a command in a remote computer?, I am trying to do this using the following code:
public static void RunRemoteCommand(string command, string RemoteMachineName)
{
ManagementScope WMIscope = new ManagementScope(
String.Format("\\\\{0}\\root\\cimv2", RemoteMachineName));
WMIscope.Connect();
ManagementClass WMIprocess = new ManagementClass(
WMIscope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
object[] process = { command };
object result = WMIprocess.InvokeMethod("Create", process);
Log.Comment("Creation of process returned: " + result);
}
This returns an exit code of 0 and no errors are thrown, yet nothing is executed. Please help.
Hope this will help
http://www.petri.co.il/command-line-wmi-part-2.htm
Have a look into "Alternate Credentials" section. i believe you are able to do the little modification yourself.
If you are willing to try it out, psexec is great for this sort of thing.
I know the post is old but for others who come across this page and also completeness:
RRUZ's comment is correct , but there is also one more thing you might need in order to run on the remote machine, credentials.
To do that you need to add connection options:
public static void RunRemoteCommand(string command, string RemoteMachineName,
string username,string password)
{
var connection = new ConnectionOptions();
connection.Username = username;
connection.Password = password;
ManagementScope WMIscope = new ManagementScope(
String.Format("\\\\{0}\\root\\cimv2", RemoteMachineName), connection);
WMIscope.Connect();
ManagementClass WMIprocess = new ManagementClass(
WMIscope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
object[] process = { command };
object result = WMIprocess.InvokeMethod("Create", process);
Log.Comment("Creation of process returned: " + result);
}

WMI Namespace "Not Found"

I'm trying to run a bat file remotely (from XP to 2003) and running into a problem connecting to any WMI namespace other than cimv2. The code below hits a "Not Found" exception in the "GetMethodParameters" call. But if I replace "directory" with "cimv2", everything is gravy.
ConnectionOptions theConnection = new ConnectionOptions();
theConnection.Username = conDet.User;
theConnection.Password = conDet.Pwd;
theConnection.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope theScope = new ManagementScope(String.Format(#"\\{0}\root\directory", conDet.Server), theConnection);
theScope.Connect();
ManagementClass processClass = new ManagementClass(theScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
enter code here
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
inParams["CommandLine"] = filename;
ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);
I've checked the security on my machine and the server and the two namespaces have identical security settings. Any ideas what's going on?
Thanks.
you are using a wrong namespace, the Win32_Process WMI class is defined in root\cimv2.
So you must rewrite your code to
ManagementScope theScope = new ManagementScope(String.Format(#"\\{0}\root\cimv2", conDet.Server), theConnection);

WaitForExit for a process on a remote computer

I'm using WMI to start a process on a remote machine. The call to create the process returns immediately and I also get the id of the process on the remote machine.
I would like to wait for the remote process to be completed. One option would be to poll whether a process on the remote machine with the given id still exists.
However, I was wondering whether there is a better way to achieve this, maybe using native WinAPI functions?
Just for additional information, this is the code that I am currently using to start the remote process:
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
connOptions.Username = domainUserName;
connOptions.Password = password;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", host), connOptions);
manScope.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_Process");
ManagementClass processClass = new ManagementClass(manScope, managementPath, objectGetOptions);
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
inParams["CommandLine"] = commandLine;
ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);
I don't know how effective this can be, you can use ManagementEventWatcher to watch a query.
Here is something I found on the net.
WqlEventQuery wQuery =
new WqlEventQuery("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'");
using (ManagementEventWatcher wWatcher = new ManagementEventWatcher(scope, wQuery))
{
bool stopped = false;
while (stopped == false)
{
using (ManagementBaseObject MBOobj = wWatcher.WaitForNextEvent())
{
if (((ManagementBaseObject)MBOobj["TargetInstance"])["ProcessID"].ToString() == ProcID)
{
// the process has stopped
stopped = true;
}
}
}
wWatcher.Stop();
}
The native Win32 way of achieving this would be to perform a WaitForSingleObject() on the process handle returned by CreateProcess(), however I don't think this handle is made available to you from WMI.
This article offers another option you could consider - instead of polling the process list and waiting for your process to disappear, it repeatedly queries for process deletion events matching your process ID:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objWMIService.Create "notepad.exe", null, null, intProcessID
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
Do Until i = 1
Set objLatestProcess = colMonitoredProcesses.NextEvent
If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
i = 1
End If
Loop
You could also improve on this by using a ManagementEventWatcher object and its WaitForNextEvent method to avoid having to poll for the deletion events.
If the process on the remote machine is your code then you could open up a socket on the calling machine and let the remote machine 'ping' it when it has finished.
If you want to use this method for any remote process you could have a helper app/service on the remote computer that monitors your process and returns the completed ping.
I havent had chance to check this yet,
int pid = (int)managementBaseObject["processId"];
Process remPrc = Process.GetProcessById(pid, RemoteMachine);
remPrc.WaitForExit();

Categories

Resources