问题
Problem
Executing PSExec as a process from C# with Asynchronous redirection enabled My data received event handlers never gets called.
Context
I have a C# application meant to connect to and manage a slave application on multiple other computers on the same local network. Both the main application and the slave applications are windows forms apps. One function of my application is to be able to launch the slave application remotely. Since doing this takes some time I was hoping to use the output from PSexec to show that something is actually happening. Below is the code I use to launch the remote application.
ProcessStartInfo start = new ProcessStartInfo();
start.CreateNoWindow = true;
start.RedirectStandardError = true;
start.RedirectStandardOutput = true;
start.RedirectStandardInput = true;
start.UseShellExecute = false;
start.WorkingDirectory = System.Windows.Forms.Application.StartupPath + "\\PSTools\\";
start.FileName = start.WorkingDirectory + "PsExec.exe";
start.Arguments = "\\\\" + ComName + " -u \"" + UserName + "\" -p \"" + Password +
"\" -i -w " + RemoteDrectory + "\" \"" + RemoteDrectory + "\\" + ApplicationName + "\"";
try
{
if (proc != null)
{
if (proc.HasExited == false)
{
proc.Kill();
proc.Close();
}
proc.Dispose();
proc.OutputDataReceived -= ProcDataReceaved;
proc.ErrorDataReceived -= ProcDataReceaved;
}
proc = new Process();
proc.EnableRaisingEvents = true;
proc.OutputDataReceived += new DataReceivedEventHandler(ProcDataReceaved);
proc.ErrorDataReceived += new DataReceivedEventHandler(ProcErrorReceaved);
proc = Process.Start(start);
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
catch(Exception e)
{
Console.WriteLine("An error occurred while launching slave application\r\n" + e.ToString());
}
This actually has the desired effect of launching the slave application on the remote machine with no issues. Additionally if I disable the output redirection the console shows the following:
PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com
Starting PSEXESVC service on ComName...
The last line gets removed once the connection is established. If it matters for now the event handlers are defined as follows:
public void ProcDataReceaved(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Data Received from process\r\n" + e.Data);
}
public void ProcErrorReceaved(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Data Received from process\r\n" + e.Data);
}
Optional Objective
The slave application is not expected to have much console output If any. But, if I could ready any output from the slave through the PSexec output as well that would be sweet.
Potential Lead 3/8/17
Today I've talked to the reps at https://www.poweradmin.com/paexec/, specifically a rep named David. There version of PSExec (PAExec) uses WriteConsole commands to write the output I'm trying to receive. Thus this output is not written to either stderr or stdout but directly to the console's screen buffer. Obviously this does not say anything PSExec since they are not the same people. But it does suggest that this is potentially my problem. If so I need another way to track the connection progress.
回答1:
It seems everything boils down to speed. If the process runs too quickly, the events don't raise. See below.
using System;
namespace PSExec_42280413
{
class Program
{
static void Main(string[] args)
{
DoIt();
}
private static void DoIt()
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.ErrorDataReceived += Proc_ErrorDataReceived;
proc.OutputDataReceived += Proc_OutputDataReceived;
proc.Exited += Proc_Exited;
proc.StartInfo.FileName = @"c:\windows\syswow64\psexec_64.exe";
proc.StartInfo.Arguments = @"-i -u usr -p pwd \\server -c M:\StackOverflowQuestionsAndAnswers\PSExec_42280413\PSExec_42280413\TheBatFile.bat";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.EnableRaisingEvents = true;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
//if the process runs too quickly, the event don't have time to raise and the application exits.
//this here takes care of slooowwwwwiiinnnnnggggg things down
//there are more elegant ways to wait and it does not have to be this long
Int64 bigone = 200000000;
while (bigone > 0)
{
bigone--;
}
}
private static void Proc_Exited(object sender, EventArgs e)
{
//string out = ((System.Diagnostics.Process)sender).StandardError.ReadToEnd();//not while BeginErrorReadLine() is set.
Console.WriteLine("done");
System.Diagnostics.Debugger.Break();
}
private static void Proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
Console.Write("1");
//System.Diagnostics.Process process = (System.Diagnostics.Process)sender;
//System.Diagnostics.Debugger.Break();
}
private static void Proc_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
Console.Write("0");
//System.Diagnostics.Process process = (System.Diagnostics.Process)sender;
//System.Diagnostics.Debugger.Break();
}
}
}
回答2:
It took me some time but I found a solution, I hope that's the case.
The only way to get the output the easy way is to echo the result through CMD.
I did it to get info of available websites remotely, which returned only the PSExec text, and it didn't return the text that AppCmd.exe(or psexesvc) returns.
There are 2 solutions I found to get the data.(String is escaped because there's a small game with the quotation mark)
[Hard Way] Use the command to create a text file on the remote computer or on local compute** r and then just check if what I'm looking for exist
"\\\\hostIP -u user -p password cmd /c \"%systemroot%\\system32\\inetsrv\\AppCmd.exe list sites > c:\\sites.txt\""
Then you can just use a command to read out of the sites.txt file
\\\\hostIP -u user -p password find \"Site\" c:\\sites.txt"
[Easy Way] Use ECHO that will reflect as console output therefore you'll be able to read the text that psexesvc returns. The way I did it that didn't work was like that:
"\\\\hostIP -u user -p password cmd ECHO /c \"%systemroot%\\system32\\inetsrv\\AppCmd.exe list sites\""
Hope this helps, enjoy.
来源:https://stackoverflow.com/questions/42280413/cant-receive-asynchronous-output-from-psexec-when-launching-application-remotel