7

I am experiencing PsExec hang while being executed from a very simple c# or c++ gui program compiled as "windows application" (not as "console application"). Under section C) below I have pasted the code to reproduce the problem and under section D) I have pasted the c++ code to reproduce the same problem.

When the psexec hangs, the windbg output after being attached to psexec locally is pasted under section B).

My program hangs after dumping the output pasted under section A).

The program works fine if you replace psexec command with anything local e.g. ProcessStartInfo("cmd.exe", "/c dir c:\windows\*.*");

I was wondering if anybody experienced it and found the solution for it. Help will be greatly appreciated.

Thanks, Sharrajesh


A) My c# program output when psexec hang

PsExec v1.98 - Execute processes remotely Copyright (C) 2001-2010 Mark Russinovich Sysinternals - www.sysinternals.com

Volume in drive C has no label.


B) Windbg output for psexec while hang

3 Id: 1614.15e4 Suspend: 1 Teb: 7efac000 Unfrozen ChildEBP RetAddr Args to Child
02a3fe68 75a6d0c5 00000180 00000000 00000000 ntdll!NtReadFile+0x15 (FPO: [9,0,0]) 02a3fecc 75cb18aa 00000180 02a3ff44 00010000 KERNELBASE!ReadFile+0x118 (FPO: [SEH]) 02a3ff14 00403bde 00000180 02a3ff44 00010000 kernel32!ReadFileImplementation+0xf0 (FPO: [SEH]) WARNING: Stack unwind information not available. Following frames may be wrong. 02a3ff2c 00000000 00291e48 00000000 02a5ff80 psexec+0x3bde


C) The c# code to reproduce the problem

using System;
using System.Windows.Forms;
using System.Diagnostics;

namespace WindowsFormsApplication1 {
  static class Program {
    static void DataReceiveHandler(object sender, DataReceivedEventArgs e) {
      Debug.WriteLine(e.Data);
    }

    public static void NotWorkingPsExec() {
      ProcessStartInfo startInfo = new ProcessStartInfo("psexec.exe",
        "\\\\raj-2k3-32 cmd.exe /c dir c:\\windows\\*.*");
      startInfo.UseShellExecute        = false;
      startInfo.CreateNoWindow         = true;
      startInfo.RedirectStandardOutput = true;
      startInfo.RedirectStandardError  = true;

      Process proc = new Process();
      proc.StartInfo           = startInfo;
      proc.ErrorDataReceived  += new DataReceivedEventHandler(DataReceiveHandler);
      proc.OutputDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
      proc.Start();
      proc.BeginErrorReadLine();
      proc.BeginOutputReadLine();
      proc.WaitForExit();
      Debug.WriteLine("Exit code = {0}", proc.ExitCode);
    }

    public static void WorkingPsExec() {
      ProcessStartInfo startInfo = new ProcessStartInfo("psexec.exe", 
        "\\\\raj-2k3-32 cmd.exe /c dir c:\\windows\\*.*");
      startInfo.UseShellExecute = false;

      Process proc = new Process();
      proc.StartInfo = startInfo;
      proc.Start();
      proc.WaitForExit();
      Debug.WriteLine("Exit code = {0}", proc.ExitCode);
    }

    static void Main() {
      NotWorkingPsExec();
      //WorkingPsExec(); //If uncommented will work 
    }
  }
}

D) The c++ code to reproduce the problem

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

HANDLE g_hStdoutRd = NULL;
HANDLE g_hStdoutWr = NULL;

void StartCommand(TCHAR *szCmdline);
void ReadOutput();
void ErrorExit(PTSTR);

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
  SECURITY_ATTRIBUTES saAttr;
  saAttr.nLength              = sizeof(SECURITY_ATTRIBUTES);
  saAttr.bInheritHandle       = TRUE;
  saAttr.lpSecurityDescriptor = NULL;
  if (!CreatePipe(&g_hStdoutRd, &g_hStdoutWr, &saAttr, 0))
    ErrorExit(TEXT("Stdout SetHandleInformation"));
  if (!SetHandleInformation(g_hStdoutRd, HANDLE_FLAG_INHERIT, 0))
    ErrorExit(TEXT("Stdout SetHandleInformation"));
  TCHAR szCmdline[] = TEXT("psexec.exe \\\\raj-2k3-32 cmd.exe /c dir /s c:\\windows\\*.*"); // Not Working
  //TCHAR szCmdline[] = TEXT("cmd.exe /c dir /s c:\\windows\\*.*"); // Working
  StartCommand(szCmdline);
  ReadOutput();
  return 0;
}

void StartCommand(TCHAR *szCmdline) {
  PROCESS_INFORMATION piProcInfo  = {0};
  STARTUPINFO         siStartInfo = {0};
  siStartInfo.cb         = sizeof(STARTUPINFO);
  siStartInfo.hStdError  = g_hStdoutWr;
  siStartInfo.hStdOutput = g_hStdoutWr;
  siStartInfo.dwFlags   |= STARTF_USESTDHANDLES;
  BOOL bSuccess = CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);
  if (!bSuccess)
    ErrorExit(TEXT("CreateProcess"));
  else {
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
  }
}

void ReadOutput() {
  if (!CloseHandle(g_hStdoutWr))
    ErrorExit(TEXT("StdOutWr CloseHandle"));
  for (;; ) {
    CHAR    chBuf[4096] = {0};
    DWORD   dwRead;
    BOOLEAN bSuccess    = ReadFile(g_hStdoutRd, chBuf, ARRAYSIZE(chBuf), &dwRead, NULL);
    if (!bSuccess || dwRead == 0)
      break;
    OutputDebugStringA(chBuf);
  }
}

void ErrorExit(PTSTR lpszFunction) {
  OutputDebugString(lpszFunction);
  ExitProcess(1);
}
sharrajesh
  • 401
  • 1
  • 5
  • 12

6 Answers6

7

PSExec was hanging for me too randomly. I haven't put the effort into recreating the issue your way, but I have avoided my troubles by using "PAExec", a seemingly worthy successor in spirit: http://www.poweradmin.com/PAExec/

Johnny Kauffman
  • 3,613
  • 3
  • 21
  • 22
  • Yes, PSExec seems to hang all over the place; this seems to work as it should. Also the stdOutput redirect seems to actually work. Great find! – satnhak Jan 07 '14 at 09:50
3

I had a similar problem that was due to the eula, which may be yours:

Possible reasons:

1) psiexec.exe shows EULA message during first run.

2) Permissions

3) dll function can require user session.

To avoid these issues please try following scenarios:

1) with "-accepteula" argument

2) with "-s" argument

3) with "-i" argument

4) > 2 + 3 5) 2 + 3 + 1

See: http://www.appdeploy.com/messageboards/tm.asp?m=72376&mpage=1&key=𑪸

Even though I had checked the EULA several times

SeanDowney
  • 17,368
  • 20
  • 81
  • 90
  • Hi SeanDowney, Thanks for the response. This was not the problem in my case since I have already executed the psexec multiple times on remote machine. I end up doing a WCF based implementation for remote execution as PsExec won't cut it for me. – sharrajesh Jul 14 '11 at 16:27
  • @sharrajesh - ok, well, I thought I would post a response in case anyone else had this as a cause of issue, since it took a couple hours to debug. Sorry it did not solve your issue – SeanDowney Jul 14 '11 at 16:56
  • 1
    -i fixed my hanging issues however when doing it that way I don't get the output from the program... What I don't understand is that it was working fine then seemingly stopped. I see that the process called by PSEXESVC terminates normally, but PSEXESVC never ends itself and notifies PSEXEC. So annoying. – Brad Jun 20 '13 at 20:41
0

I have a simple solution for this,

  1. C# run the process like:

    Process.Start("start run.bat xx.txt");    //call it async
    
    //and then we make some code juse wait xx.txt appear and finish written .
    
  2. run.bat is :

    psexec.bat > %1           //redirect to a text file
    exit
    
  3. psexec.bat is:

    psexec.exe ..........................
     exit
    
Himanshu
  • 31,810
  • 31
  • 111
  • 133
timiil
  • 21
  • 4
0

Please also set the WorkingDirectory property on startInfo, as Sysinternals utilities use run-time unpacking of files and the kernel is unable to find the unpacked (real) exectutable file.

Vladislav Zorov
  • 2,998
  • 19
  • 32
  • Hi Vladislav, I donot see how setting WorkingDirectory will make any difference here. I tried it anyway to prove that. Just wanted to iterate that PsExec is definitely finding cmd.exe and running it but it never finishes. – sharrajesh Apr 13 '11 at 20:50
  • Oh sorry about that, I though psexec won't load... Obviously I missed something :) So if you call the `NotWorkingPsExec();` twice it works? – Vladislav Zorov Apr 13 '11 at 21:38
  • No Problem Vlad. Calling NotWorkingPsExec again and again does NOT help. (Sorry for my typo in the sample provided.) However calling WorkingPsExec instead work fine . The only difference between the two is that I am not enabling std redirection in the second case. In previous case when PsExec hangs, windbg stack trace of hung psexec (client side) is indicating that it is waiting on ReadFile. My suspicion is that it has hit some deadlock with PSEXESVC running on the remote machine. – sharrajesh Apr 13 '11 at 21:52
  • You could try Wireshark, it will show you what REALLY happens on the network. I would take a wild guess and say some buffer doesn't get flushed and you're stuck waiting for the data. – Vladislav Zorov Apr 13 '11 at 22:16
0

Build a generic Console Application which runs PsExec & PsKill and all of their friends. Call this ConsoleApp through your code instead of calling the NotWorkingPsExec method, and it'll work just fine.

Echilon
  • 10,064
  • 33
  • 131
  • 217
-1

Synchronous read on the stream works:

        ProcessStartInfo startInfo = new ProcessStartInfo("psexec.exe", @"\\localhost cmd.exe /c dir c:\windows\*.*");
        startInfo.UseShellExecute = false;
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardOutput = true;
        //startInfo.RedirectStandardError = true;
        //startInfo.RedirectStandardInput = true;

        Process proc = new Process();
        proc.StartInfo = startInfo;
        //proc.ErrorDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
        //proc.OutputDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
        proc.Start();
        //proc.BeginErrorReadLine();
        //proc.BeginOutputReadLine();
        string output = proc.StandardOutput.ReadToEnd();
        proc.WaitForExit();
        Console.WriteLine(output);
        Console.WriteLine("Exit code = {0}", proc.ExitCode);

Even here, note that the ReadToEnd() should be done before the WaitForExit().

I believe PSExec always had problems like this. When running under Java service, we used to redirect the output to nul and couldn't get the output of the running process, but can get the output of PSExec itself.

Refer to below given discussions:

http://forum.sysinternals.com/psexec-always-hangs-when-run-from-java_topic5013.html

http://forum.sysinternals.com/unusual-problem-with-psexecexe_topic6655.html

Edit:

Note on PSEXESVC cleanup: Delete the PSEXESVC.EXE file at C:\Windows ( or C:\Windows\system32 or both ) after killing the hung PSEXESVC process. Lingering process / file cause more problems.

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • Hi Manojids, Thanks for the reply. Even though I tried to mention it in my subject heading, but I should have emphasized more that the problem happens when my program is compiled as "Windows Application" instead of "Console Application". My program had been working fine if I compile it as a "Console Application". If I compile your effort as a "windows application" it has been hanging in the same place. I will tryout some of your other suggestions. Thanks bunch. – sharrajesh Apr 13 '11 at 23:04
  • >>Note on PSEXESVC cleanup: Delete the PSEXESVC.EXE file I am aware this step. Just to be sure on the remote machine I had been calling "net stop psexesvc" or rebooting my machine if psexesvc fail to stop. :) – sharrajesh Apr 13 '11 at 23:08