Sunday, March 6, 2011

Wait for a remote process to finish in .net

We all know and love Process.WaitForExit().

Given a pid of a process on a remote machine (created by WMI/psexec), how do I wait for it to end?

From stackoverflow
  • Process.GetProcessById(processId, machineName).WaitForExit();
    

    HTH, Kent

  • Poll the remote computer using SysInternals' PSLIST.

  • For me Process.GetProcessByID() just didn't work (it claimed it couldn't connect to the machine). This worked:

    public static bool WaitForProcess(int pid, string machine, TimeSpan timeout)
    {
      // busy wait
      DateTime start = DateTime.Now;
      while (IsAlive(pid, machine))
      {
        if (start.Add(timeout).CompareTo(DateTime.Now) <= 0)
          return false;
    
        Thread.Sleep(1000);
      }
      return true;
    }
    
    public static bool IsAlive(int pid, string machine)
    {
      // doesn't work for me (throws "The network path was not found" exception)
      //return Process.GetProcessById(pid, @"\\" + machine) != null;
      string user;
      string domain;
      GetProcessInfoByPID(pid, machine, out user, out domain);
      return !string.IsNullOrEmpty(user);
    }
    
    public static string GetProcessInfoByPID(int PID, string machine, out string User, out string Domain)
    {
      // copied from http://www.codeproject.com/KB/cs/processownersid.aspx?fid=323674&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2076667
      // with slight modifications
      ConnectionOptions connOptions = new ConnectionOptions();
      connOptions.Impersonation = ImpersonationLevel.Impersonate;
      connOptions.EnablePrivileges = true;
      ManagementScope manScope = new ManagementScope(String.Format(@"\\{0}\ROOT\CIMV2", machine), connOptions);
      manScope.Connect();
    
      User = String.Empty;
      Domain = String.Empty;
      string OwnerSID = String.Empty;
      string processname = String.Empty;
      try
      {
        ObjectQuery sq = new ObjectQuery
          ("Select * from Win32_Process Where ProcessID = '" + PID + "'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(manScope, sq);
        if (searcher.Get().Count == 0)
          return OwnerSID;
        foreach (ManagementObject oReturn in searcher.Get())
        {
          string[] o = new String[2];
          //Invoke the method and populate the o var with the user name and domain
          oReturn.InvokeMethod("GetOwner", o);
    
          //int pid = (int)oReturn["ProcessID"];
          processname = (string)oReturn["Name"];
          //dr[2] = oReturn["Description"];
          User = o[0];
          if (User == null)
            User = String.Empty;
          Domain = o[1];
          if (Domain == null)
            Domain = String.Empty;
          string[] sid = new String[1];
          oReturn.InvokeMethod("GetOwnerSid", sid);
          OwnerSID = sid[0];
          return OwnerSID;
        }
      }
      catch
      {
        return OwnerSID;
      }
      return OwnerSID;
    }
    

0 comments:

Post a Comment