PsExec v 1.98 Output Redirection Issue - c#

I dont think any of the previous questions on this topic gave an answer for this issue. I use psexec to execute a remote exe file . I am getting the output of the exe file when i run it in command line. psexec.exe \\machine C:\somename.exe.
When i use C sharp Process Execution it either hangs or it doesnt redirect the output. For some exe's it timesout and for some Redirected standard Output is empty and Error contains Exe exited with code 0. Is there any way to capture the output ?
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName =GetPsExecPath();
startInfo.Arguments = arguments;
Debug.WriteLine(arguments);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
error = process.StandardError.ReadToEnd();
output = process.StandardOutput.ReadToEnd();
Debug.WriteLine(error);
Debug.WriteLine(output);
process.close();
Edit: Soln
So the issue is primarily cause Psexec throws a lot of other things into the stderr and hence the order in which we read them, whtever it may be leads to deadlock if we use ReadToEnd(). So if we use BeginOutputReadLine it works like a charm!

This code snippet has very high odds for causing deadlock. Because you first read StandardError, then StandardOutput. Which means that process.StandardOutput.ReadToEnd() isn't going to get called until the process exits. Which means that psexec won't be able to flush its stdout output buffer when it fills up with enough characters. Which means that it will block and thus never terminate. Deadlock city.
You'll have much better odds if you swap the two calls, most programs send the bulk of output to stdout. However with still non-zero odds for deadlock if psexec writes a lot of characters to stderr for some reason. You eliminate that entirely by using BeginOutputReadLine and BeginErrorReadLine instead.

Related

Process output stream stuck on read even though process writes to console

Code snippet:
Process process = new Process();
process.StartInfo.FileName = Environment.CurrentDirectory + "\\KataGo\\katago.exe";
process.StartInfo.Arguments = "gtp";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
StreamReader reader = process.StandardOutput;
Console.WriteLine("A");
reader.Read();
Console.WriteLine("B");
Output:
A
KataGo v1.11.0
...
KataGo by itself uses a console to synchronously interact. It prints info at the start, then waits for a command, gives output, waits again etc.
The "A" indicates that my program starts reading before the program starts outputting. Yet it doesn't output "B" until I manually stop the program and the process is discarded. So it waits for something to read but doesn't get anything even though there are things getting written.
The same behavior occurs with reader.ReadLine() and reader.ReadToEnd().
Using process.OutputDataReceived and process.BeginOutputReadLine() instead also doesn't catch anything.
The only reason I can think of is that the console (it's a normal C# Console Application) reads everything before my stream does. But I don't know how to have the process use a custom stream instead of the standard to test it.
I also tried process.StartInfo.CreateNoWindow = true; and it doesn't output to the console. But reader.Read() still gets stuck, so I guess it breaks the executable.
As suggested by Mathias, The outside program wrote to StandardError.

C# Process WaitForExit hangs when starting python

I use a Process class to start Python like below (in a thread):
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "python.exe";
info.Arguments = "test.py";
Process p = new Process();
p.StartInfo = info;
p.RedirectStandardOutput = true;
p.RedirectStandardError = true;
...
p.Start();
p.WaitForExit();
when Python ends with errors (the python process is no longer showing in Windows Task Manager), WaitForExit still hangs. However, if I use IronPython instead, it works fine. Can anyone tell me why?
Resolved. Redirects and ErrorDataReceived/OutputDataReceived event implements causes this problem, use Redirects and StreamReader instead.
Try changing python.exe to pythonw.exe

Understanding how to control stdout using System.Diagnostics.Process

I see several questions about how to launch processes and push data into stdin, but not how to control where their output goes.
First here is my current code, run from a console mode C# application:
// Prepare the process to run
ProcessStartInfo start = new ProcessStartInfo();
// Enter in the command line arguments, everything you would enter after the executable name itself
start.Arguments = " -";
// Enter the executable to run, including the complete path
start.FileName = "doxygen.exe";
// Do you want to show a console window?
start.WindowStyle = ProcessWindowStyle.Normal;
start.CreateNoWindow = false;
start.RedirectStandardInput = true;
start.UseShellExecute = false;
// Run the external process & wait for it to finish
using (Process proc = Process.Start(start))
{
//doxygenProperties is just a dictionary
foreach (string key in doxygenProperties.Keys)
proc.StandardInput.WriteLine(key+" = "+doxygenProperties[key]);
proc.StandardInput.Close();
proc.WaitForExit();
// Retrieve the app's exit code
int exitCode = proc.ExitCode;
}
What happens when I run this is I do not see any new window (though I think I should) and all of doxygen.exe's stdout is printed to my app's console window.
What I would like to happen is one of two things:
Doxygen is launched in a visible window, and I can see its stdout in that window, not in my app's window.
Doxygen is launched in a hidden window, and it's stdout is written to a log file.
How can I achieve these?
In addition, why am I not getting a separate window for the spawned process, and why is the spawned process writing output to my window not its own?
One thing that you can do is use RedirectStandardOutput and instead of using WaitForExit you can use ReadToEnd
ProcessStartInfo start = new ProcessStartInfo();
start.RedirectStandardOutput = true;
//make other adjustments to start
Process p = new Process();
p.StartInfo = start;
p.Start();
string output = p.StandardOutput.ReadToEnd();
and then you can use string output at your leisure
If you want to get output in real-time the p.StandardOutput property has methods that allow you to get the output asynchronously. I don't know all the details to it offhand, I've only used it once before, but there's plenty of literature out there if you search for it.
Also be careful when redirecting both StandardOutput and StandardError at the same time, If they're long enough, it is possible for that to cause deadlocks.
You need to do two things:
1) Indicate that you want the standard output of the process to be directed to your app by setting the RedirectStandardOuput property to true in the process.
2) BEFORE the call to WaitForExit, start capturing the output:
string sOutput = p.StandardOutput.ReadToEnd();
If you do not start reading the output before calling wait for exit, you can encounter a deadlock.
However, it is important to know that standard output will only capture output information, not anything written to the standard error stream of the app.
In order to capture both streams of information, you can hook the process's OutputDataReceived and ErrorDataReceived events and write the event data directly into a log file or store it in a class property for use after the process has completed.

Issues with running a PsExec process from code

I am experiencing a weird issue when attempting to run a .NET command line tool remotely using PsExec.
When running PsExec from command line, it runs and completes fine.
When running it from a console application (creating a process,
running PsExec.exe with the necessary arguments to it) -- it is
running OK.
When running it from our in house custom tool that is
used to run different tasks, it either times out or does not
complete successfully.
Here is the code i am using:
Process p = new Process();
p.StartInfo.FileName = #"C:\PsExec.exe";
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
string arg = "-snapshot -display C:\*.msi -s";
p.StartInfo.Arguments = #"\\10.161.203.106 -u user -p pwd -cf C:\FVT.exe " + arg;
Logger.Info(this, "Starting process");
p.Start();
var ended = p.WaitForExit(60 * 1000);
if (!ended)
{
throw new Exception("Process timed out.");
}
Logger.Info(this, "Process ended");
using (StreamReader sr = p.StandardOutput)
{
string buffer = sr.ReadToEnd();
Logger.Info(this, buffer);
}
This code runs fine from cmd line, or from a standalone app!
I have no idea what else could be wrong here.
Our in house tool spawns a new thread and runs this code in it.
Update:
command line + args in command line window -- working.
Same cmd + args, run as a Process with RedirectOutput - stalls and returns on timeout.
Could this be a bug in .NET ? (this happens for other progarms, batch files, etc).
try adding -accepteula to your arguments to psexec
I don't know what the error is, but I have a hunch that if you redirect stderr (RedirectStandardError = true) and read the stderr stream (like you do with stdout) it will tell you. Alternatively, while debugging leave CreateNoWindow = false and maybe you'll see the console message (especially if it is waiting for a keypress; otherwise it might disappear too quickly to notice).
Note that you might need to set up async readers on stdout/stderr if the process isn't terminating. You can do that either on extra threads, or via the OutputDataReceived / ErrorDataReceived events (you need to set EnableRaisingEvents to true also).
If that still doesn't work; you could try running with UseShellExecute=true. This means you won't be able to redirect IO, so you might have to use > / >> etc to pipe the output to a file (ideally in temp), then read the file.

Getting a Process to terminate

I have a process object setup like the following:
Process p = new Process();
p.StartInfo.FileName = command;
p.StartInfo.UseShellExecute = true;
p.StartInfo.Arguments = String.Format(
commandArguments,
destinationLocation,
sourceLocation,
sourceDirName,
(string.IsNullOrEmpty(revisionNotes.Text)) ? "" : revisionNotes.Text);
(where undefined values are supplied externally to this code and are valid). The process in question launches and properly executes with p.Start(); but i need to catch it on termination. The console window flashes up briefly and goes away which would seem to indicate that the process is done, but none of the relevant events are fired (OutputDataRecieved, Exited, etc) and it's like the process never ends. (I'm trying to execute a lua script with some parameters if that's relevant). Can someone help me get this process to stop correctly?
WaitForExit
Have you set the EnableRaisingEvents property of the process to True? You won't catch the Exited event without it.

Categories