Click here to Skip to main content
15,886,799 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hi
I am at a loss. I have tried several different ways to read the output from SysInternals PsExec with very intermittent and unrepeatable results. I have tried synchronous reads and asynchronous reads but seem to lose the output most of the time. Any assistance would be greatly appreciated. The command is working fine and very occasionally I get the output but usually only on the first execution if I do. I have hidden some event handler code for the combo box and text box initialisation as it holds company confidential info. May I also point out I always get the error output which shows the progress of PsExec but the standard output holds the actual data I need.

I have a few text boxes a comboBox and button on the forms surface to pass various parameters in and receive the output and I am using SysInternals DebugView to monitor the trace during initial development to avoid coding a listener. Here is the essence of the code which is fairly self explanatory:

C#
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace My_Namespace
{
    public partial class frmMain : Form
    {
        StringBuilder output;
        StringBuilder error;

        public frmMain()
        {
            InitializeComponent();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            try
            {
                ProcessStartInfo psi;
                Process proc;
                Stopwatch ExecutionStopWatch;
                output = new StringBuilder();
                error = new StringBuilder();
                txtStandardOutput.Clear();
                txtErrorOutput.Clear();
                Application.DoEvents();
                psi = new ProcessStartInfo();
                psi.CreateNoWindow = true;
                psi.ErrorDialog = false;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardError = true;
                psi.UseShellExecute = false;
                psi.FileName = txtPsExecPath.Text;
                psi.Arguments = txtArguments.Text;
                Trace.WriteLine(string.Format("Arguments: {0}",txtArguments.Text));
                proc = new Process();
                proc.EnableRaisingEvents = true;
                proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
                proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
                proc.StartInfo = psi;
                ExecutionStopWatch = new Stopwatch();
                ExecutionStopWatch.Start();
                Trace.WriteLine(string.Format("Execute PsExec command on server {0}.", cboServer.SelectedItem.ToString()));
                proc.Start();
                proc.BeginOutputReadLine();
                proc.BeginErrorReadLine();
                proc.WaitForExit();
                Trace.WriteLine(string.Format("Execution took {0} ms", ExecutionStopWatch.ElapsedMilliseconds.ToString()));
                Stopwatch outputDelay = new Stopwatch();
                outputDelay.Start();
                while (output.ToString().Length.Equals(0) && outputDelay.ElapsedMilliseconds < 5000)
                {
                    //Application.DoEvents();
                }
                outputDelay.Stop();
                Trace.WriteLine(string.Format("Output was delayed by {0} ms", outputDelay.ElapsedMilliseconds.ToString()));
                txtStandardOutput.Text = output.ToString();
                txtErrorOutput.Text = error.ToString();
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

        private void proc_OutputDataReceived(object sendingProcess, DataReceivedEventArgs message)
        {
            try
            {
                #region	Try
                if (!String.IsNullOrEmpty(message.Data))
                {
                    output.AppendLine(message.Data);
                }
                #endregion Try
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

        private void proc_ErrorDataReceived(object sendingProcess, DataReceivedEventArgs message)
        {
            try
            {
                #region	Try
                error.AppendLine(message.Data);
                #endregion Try
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

    }
<pre>


Any pointers would be greatly received. One other question is what is the best way to yield to the processor during a while loop ?

Thanks in advance
Andy
Posted
Updated 29-Feb-12 21:56pm
v2

As u r telling, you are getting the output, but usually only on the first execution.... Its so simple dear, in the form_closing event, write the stop() of your device. I think its "ProcessStopInfo". I dont have time to read and understand your code. I m enguage in solving one problem. As i free, i will check ur code also.
 
Share this answer
 
Comments
aaawesome 1-Mar-12 4:01am    
Sorry not so simple dear, this is not the solution. There is no such thing as a ProcessStopInfo and you can see from my code that I already wait for the program to finish executing using "proc.WaitForExit();".

The problem seems to be that the output has gone quicker than I can start the read process but I am sure this cannot be true as I assume the process class will buffer any output.

Thanks for the response.
It seems that the output is not delivered until after the process has exited. I have declared the process at a global level and implemented a timer to check for output after the process has exited and it seems to work!

Here is the code for reference (The timer interval is set to 10 (ms) so Iwait up to 5 seconds for the output):

C#
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace SCX_Server_Utilisation_Test_App
{
    public partial class frmMain : Form
    {
        StringBuilder output;
        StringBuilder error;
        ProcessStartInfo psi;
        Process proc;
        int timerExecutions;
        Stopwatch outputDelay;

        public frmMain()
        {
            InitializeComponent();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            try
            {
                btnGo.Enabled = false;
                Stopwatch ExecutionStopWatch;
                output = new StringBuilder();
                error = new StringBuilder();
                txtStandardOutput.Clear();
                txtErrorOutput.Clear();
                Application.DoEvents();
                psi = new ProcessStartInfo();
                psi.CreateNoWindow = true;
                psi.ErrorDialog = false;
                psi.RedirectStandardOutput = true;
                psi.RedirectStandardError = true;
                psi.UseShellExecute = false;
                psi.FileName = txtPsExecPath.Text;
                psi.Arguments = txtArguments.Text;
                Trace.WriteLine(string.Format("Arguments: {0}",txtArguments.Text));
                proc = new Process();
                proc.EnableRaisingEvents = true;
                proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
                proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
                proc.StartInfo = psi;
                ExecutionStopWatch = new Stopwatch();
                ExecutionStopWatch.Start();
                Trace.WriteLine(string.Format("Execute PsExec command on server {0}.", cboServer.SelectedItem.ToString()));
                proc.Start();
                proc.BeginOutputReadLine();
                proc.BeginErrorReadLine();
                proc.WaitForExit();
                Trace.WriteLine(string.Format("Execution took {0} ms", ExecutionStopWatch.ElapsedMilliseconds.ToString()));
                outputDelay = new Stopwatch();
                outputDelay.Start();
                timerWaitForOutput.Enabled = true;
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

        private void proc_OutputDataReceived(object sendingProcess, DataReceivedEventArgs message)
        {
            try
            {
                #region	Try
                if (!String.IsNullOrEmpty(message.Data))
                {
                    output.AppendLine(message.Data);
                }
                #endregion Try
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

        private void proc_ErrorDataReceived(object sendingProcess, DataReceivedEventArgs message)
        {
            try
            {
                #region	Try
                error.AppendLine(message.Data);
                #endregion Try
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception occured: " + ex.ToString());
            }
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            cboServer.SelectedIndex = 1;
        }

        private void cboServer_SelectedIndexChanged(object sender, EventArgs e)
        {
            txtArguments.Text = string.Format("\\\\{0}.<domain name=""> \"{1}\" {2}", cboServer.SelectedItem.ToString(), txtRemoteExePath.Text);
        }

        private void timerWaitForOutput_Tick(object sender, EventArgs e)
        {
            timerExecutions++;
            if (!output.ToString().Length.Equals(0) || timerExecutions >= 500)
            {
                proc.Close();
                timerExecutions = 0;
                timerWaitForOutput.Enabled = false;
                outputDelay.Stop();
                if (output.ToString().Length.Equals(0))
                {
                    Trace.WriteLine(string.Format("Waited {0} ms for output with no results.", outputDelay.ElapsedMilliseconds.ToString()));
                    txtStandardOutput.Text = string.Format("Waited {0} ms for output with no results.", outputDelay.ElapsedMilliseconds.ToString());
                }
                else
                {
                    Trace.WriteLine(string.Format("Output was delayed by {0} ms.", outputDelay.ElapsedMilliseconds.ToString()));
                }
                btnGo.Enabled = true;
            }
            if (!output.ToString().Length.Equals(0))
            {
                txtStandardOutput.Text = output.ToString();
            }
            if (!error.ToString().Length.Equals(0))
            {
                txtErrorOutput.Text = error.ToString();
            }
        }
    }
}
</domain>
 
Share this answer
 
Comments
Alan N 1-Mar-12 8:42am    
When a captured stream closes an event is raised with DataReceivedEventArgs.Data set to null. In your case the timer will not be needed if you know when both event handlers have received null data.

The examples on MSDN which treat a null string and an empty string in the same way have not helped and must have confused a great number of programmers, me included!

To clarify: an empty string is received when the process outputs a blank line and a null string is received when the stream closes and capture is complete.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900