Running an Executable and Collecting the Output

Sometimes in the middle of a .NET application (either C# or VB) you want to run an executable and collect the output.  This post presents a simple function (RunExecutable) that makes it easy to do this.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCI write a lot of documents that contain code.  Many of those documents also contain the expected output from the code.  When you have a very large document with many code snippets, it is useful to automate the testing of those snippets.  It gives me a warm and fuzzy feeling to verify that all of the code in my document(s) is validated just before I publish.  I’m going to use RunExecutable in an upcoming post that shows how to extract C# code from an Open XML document, compile it, run it, and validate that the output matches the output in the document.  This is particularly useful to, say, authors writing programming books.

But this code is useful in its own right.  Here is the code to run an executable, and collect the output:

using System;

using System.Text;

using System.IO;

using System.Diagnostics;

 

classRunResults

{

    publicint ExitCode;

    publicException RunException;

    publicStringBuilder Output;

    publicStringBuilder Error;

}

 

classProgram

{

    publicstaticRunResults RunExecutable(string executablePath, string arguments,

        string workingDirectory)

    {

        RunResults runResults = newRunResults

        {

            Output = newStringBuilder(),

            Error = newStringBuilder(),

            RunException = null

        };

        try

        {

            if (File.Exists(executablePath))

            {

                using (Process proc = newProcess())

                {

                    proc.StartInfo.FileName = executablePath;

                    proc.StartInfo.Arguments = arguments;

                    proc.StartInfo.WorkingDirectory = workingDirectory;

                    proc.StartInfo.UseShellExecute = false;

                    proc.StartInfo.RedirectStandardOutput = true;

                    proc.StartInfo.RedirectStandardError = true;

                    proc.OutputDataReceived +=

                        (o, e) => runResults.Output.Append(e.Data).Append(Environment.NewLine);

                    proc.ErrorDataReceived +=

                        (o, e) => runResults.Error.Append(e.Data).Append(Environment.NewLine);

                    proc.Start();

                    proc.BeginOutputReadLine();

                    proc.BeginErrorReadLine();

                    proc.WaitForExit();

                    runResults.ExitCode = proc.ExitCode;

                }

            }

            else

            {

                thrownewArgumentException("Invalid executable path.", "executablePath");

            }

        }

        catch (Exception e)

        {

            runResults.RunException = e;

        }

        return runResults;

    }

 

    publicstaticvoid Main()

    {

        RunResults runResults = RunExecutable("./ConsoleApplication2.exe", "aaa bbb ccc", ".");

        if (runResults.RunException != null)

            Console.WriteLine(runResults.RunException);

        else

        {

            Console.WriteLine("Output");

            Console.WriteLine("======");

            Console.WriteLine(runResults.Output);

            Console.WriteLine("Error");

            Console.WriteLine("=====");

            Console.WriteLine(runResults.Error);

        }

    }

}

After input from Jochan (see below), I've updated the code as shown.  Thanks, Jochan!

Code is attached.

Program.cs