Friday, April 29, 2011

WaitForExit for a process on a remote computer

Hi,

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);
From stackoverflow
  • 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.

  • 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'");
    
    ManagementEventWatcher wWatcher = new
    ManagementEventWatcher(scope, wQuery);
    
    bool stopped = false;
    
    while (!stopped)
    {
      ManagementBaseObject MBOobj = wWatcher.WaitForNextEvent();
    
      if (((ManagementBaseObject)MBOobj["TargetInstance"])["ProcessID"].ToString() == ProcID)
      {
        // the process has stopped
        stopped = true;
      }
    }
    
    wWatcher.Stop();
    
  • 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.

    0xA3 : That's a nice idea, thanks. This would probably be most efficient and quite simple. However, I would like to keep it as generic as possible so I can start any process remotely.

0 comments:

Post a Comment