3

I've been trying to get the console output from running psexec as a process in a c# windows forms application. I've found I can redirect the standardoutput(and standard error) to a specified text file fine in a console application, and can redirect the output when the process used is something other than PsExec (ping for instance), but when I try to use psexec from a windows forms application I usually get an empty line in my logs, or at best I've been able to get the first line. I know psexec has had issues with synchronous redirected output, but even asychronous runs into this problem, but only when used within a Windows Forms Application.

My code for the method called that runs the process:

class Tester
    {

        static readonly StringBuilder outputText = new StringBuilder();
        static readonly StringBuilder errorText = new StringBuilder();

        public void Installer(string command, string arguments)
        {
            using (var psexec = Process.Start(new ProcessStartInfo(
               command,
                arguments)
            {
                CreateNoWindow = true,
                ErrorDialog = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false
            }))
            {

                psexec.OutputDataReceived += (sendingProcess, outLine) =>
                    outputText.AppendLine(outLine.Data);

                psexec.ErrorDataReceived += (sendingProcess, errorLine) =>
                    errorText.AppendLine(errorLine.Data);

                psexec.BeginOutputReadLine();
                psexec.BeginErrorReadLine();

                psexec.WaitForExit();

                string text = outputText.ToString();
                File.AppendAllText(@"C:\test\psexec-test.log", text);

            }

        }
    }

The above works (gives me the output from psexec I expect in a designated file) when called within a console application like this:

class Program
{
    static void Main(string[] args)
    {
        Tester test1 = new Tester();

        test1.Installer("PsExec.exe", @"-h \\remoteserver ipconfig");
    }
}

However, if I call it from an equivalent Windows Forms Application like so:

public partial class Form1 : Form
{

    Tester test = new Tester();

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        string sendAddress = Address.Text;
        test.Installer("psexec.exe", @"-h \\remoteserver ipconfig");
    } }

I only get:

Windows IP Configuration

Done! Without the rest of the results from ipconfig.

In the larger application I made everything else does work and I know real work is done (it runs an installer on the remote machine, or multiple remote machines), but I don't get the output from psexec. Is there something I'm missing with the Windows Forms Applications, and how to get the redirection to work with psexec?

Bacteria
  • 8,406
  • 10
  • 50
  • 67

1 Answers1

0

Seems like you're jumping the gun on starting the process. It surprises me you're getting what you want in a console app. But I think you want to create your process, hook the events, and then start:

public void Installer( string command, string arguments, string logFile )
{
  var outputText = new StringBuilder( );
  var errorText = new StringBuilder( );

  var startInfo = new ProcessStartInfo( command, arguments )
  {
    CreateNoWindow = true,
    ErrorDialog = false,
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    UseShellExecute = false
  };

  using ( var psexec = new Process( ) )
  {
    psexec.StartInfo = startInfo;
    psexec.OutputDataReceived += ( _, dat ) => outputText.AppendLine( dat.Data );
    psexec.ErrorDataReceived += ( _, dat ) => errorText.AppendLine( dat.Data );
    psexec.Start( );
    psexec.BeginOutputReadLine( );
    psexec.BeginErrorReadLine( );
    psexec.WaitForExit( );

    File.AppendAllText( logFile, outputText.ToString( ) );
  }
}
Clay
  • 4,999
  • 1
  • 28
  • 45
  • BTW - be careful - in your `Tester`, you have static `StringBuilder` objects that you're using in an instance method. That's a recipe for problems - better to declare them in the method. Even then, why not just have your events wired to a stream over the log file? With in-memory objects, and an install process gone wrong, you could end up with enormous memory consumption is no-time flat! – Clay Aug 19 '15 at 22:16
  • Tried it out and this works again in the console application version, but still doesn't give me the output beyond the first line in the Winform application. Changed up the way I was handling the stringbuilders either way as your way makes more sense. – Brendan Foley Aug 20 '15 at 15:51
  • FWIW - I can get the same behavior by manually killing a process that never correctly terminates (I tested w/ command="cmd.exe" and arguments="/s dir"). I get a couple of lines of output - followed by nothing. In such a case, the ExitCode is not 0 and the errorText is empty. Have you looked at the ExitCode and the content of your errorText object? – Clay Aug 20 '15 at 17:30
  • 1
    If I send errorText to the file, I seem to get all of the psexec startup and exit text (version of psexec, copyright, connecting to server, exited with error code 0, etc) but none of the output that comes from running the process (such as ipconfig) on the remote machine which psexec otherwise provides. Checked ExitCode as well and it's 0. – Brendan Foley Aug 20 '15 at 18:17
  • Grasping at this point - but maybe something like @"psexec \\myserver ipconfig > ps.log". I'm wondering if psexec "knows" it's running w/o a window. Sorry I couldn't be more helpful. – Clay Aug 20 '15 at 19:15
  • Yea, I tried that one before, and some variations. I think Process doesn't allow redirecting of output that way, which is why it has it's own redirect output properties. Not sure, but it didn't work when I tried anyway. Thanks for trying, this has been driving me nuts! – Brendan Foley Aug 20 '15 at 19:20