Click here to Skip to main content
15,895,606 members
Articles / Programming Languages / C#

C# Command Prompt class

Rate me:
Please Sign up or sign in to vote.
4.68/5 (13 votes)
13 Jun 2013CPOL3 min read 52.4K   2.6K   45  
This tip describes a class that allows you to run a command and get its output.
using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Text;

namespace CommandPrompt
{
    /// <summary>
    /// Class used to store string data.
    /// </summary>
    public class DataEventArgs : EventArgs
    {
        public string Data { get; private set; }

        public DataEventArgs(string data)
        {
            Data = data;
        }
    }

    /// <summary>
    /// Class that allows running commands and receiving output.
    /// </summary>
    internal class CommandPrompt
    {
        // Process object used to run command.
        private Process _process;

        // Process start info.
        private ProcessStartInfo _startInfo;

        // Stores the contents of standard output.
        private StringBuilder _standardOutput;

        // Stores the contents of standard error.
        private StringBuilder _standardError;

        /// <summary>
        /// No timeout.
        /// </summary>
        public const int NoTimeOut = 0;

        /// <summary>
        /// Value that indicates whether process is currently running.
        /// </summary>
        public bool IsRunning { get; private set; }

        /// <summary>
        /// Value that indicates whether process has exited.
        /// </summary>
        public bool HasExited { get; private set; }

        /// <summary>
        /// Process ID of the running command.
        /// </summary>
        public int ProcessId { get; private set; }

        /// <summary>
        /// Exit code of process. Only set if HasExited is True.
        /// </summary>
        public int ExitCode { get; private set; }

        /// <summary>
        /// Standard output of command.
        /// </summary>
        public string StandardOutput
        {
            get
            {
                return _standardOutput.ToString();
            }
        }

        /// <summary>
        /// Standard error of cmomand.
        /// </summary>
        public string StandardError
        {
            get
            {
                return _standardError.ToString();
            }
        }

        /// <summary>
        /// Raised when standard output receives data.
        /// </summary>
        public event EventHandler<DataEventArgs> OutputDataReceived = (sender, args) => { };

        /// <summary>
        /// Raised when standard error receievs data.
        /// </summary>
        public event EventHandler<DataEventArgs> ErrorDataReceived = (sender, args) => { };

        /// <summary>
        /// Raised when process has exited.
        /// </summary>
        public event EventHandler Exited = (sender, args) => { };

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="exe">Command to run.</param>
        /// <param name="arguments">Arguments to pass to exe.</param>
        /// <param name="workingDirectory">Working directory to run command in.</param>
        public CommandPrompt(string exe, string arguments = "", string workingDirectory = "")
        {
            _standardOutput = new StringBuilder();
            _standardError = new StringBuilder();

            _startInfo = new ProcessStartInfo()
            {
                FileName = exe,
                Arguments = arguments,
                WorkingDirectory = workingDirectory,
                UseShellExecute = false,                // This is required to redirect stdin, stdout and stderr
                CreateNoWindow = true,                  // Don't create a window
                RedirectStandardOutput = true,          // Capture standard output
                RedirectStandardError = true,           // Capture standard error
                RedirectStandardInput = true,           // Enable sending commands to standard input
            };

            _process = new Process()
            {
                StartInfo = _startInfo,
                EnableRaisingEvents = true,
            };
            _process.OutputDataReceived += _process_OutputDataReceived;
            _process.ErrorDataReceived += _process_ErrorDataReceived;
            _process.Exited += _process_Exited;
        }

        /// <summary>
        /// Run command synchronously.
        /// </summary>
        /// <param name="timeOutInMilliseconds">Timeout value in milliseconds (default is infinite timeout).</param>
        public void Run(int timeOutInMilliseconds = NoTimeOut)
        {
            if (!IsRunning && !HasExited)
            {
                BeginRun();

                if (timeOutInMilliseconds == NoTimeOut)
                {
                    _process.WaitForExit();
                }
                else
                {
                    _process.WaitForExit(timeOutInMilliseconds);
                }
            }
        }

        /// <summary>
        /// Run command asynchronously.
        /// </summary>
        public void BeginRun()
        {
            if (!IsRunning && !HasExited)
            {
                if (_process.Start())
                {
                    IsRunning = true;
                    ProcessId = _process.Id;

                    _process.BeginOutputReadLine();
                    _process.BeginErrorReadLine();
                }
            }
        }

        /// <summary>
        /// Write command to standard input.
        /// </summary>
        /// <param name="command">Command to write.</param>
        public void WriteToStandardInput(string command)
        {
            if (IsRunning && !HasExited)
            {
                _process.StandardInput.Write(command);
            }
        }

        /// <summary>
        /// Kill process.
        /// </summary>
        /// <param name="killChildProcesses">Kill child processes that were spawned from this process.</param>
        public void Kill(bool killChildProcesses = false)
        {
            if (killChildProcesses && ProcessId != 0)
            {
                // Kill this process and all child processes
                KillChildProcesses(ProcessId);
            }
            else if (IsRunning && !HasExited)
            {
                // Only kill this process
                _process.Kill();
            }
        }

        // Recursively kill child and grand-child processes of parent process
        private void KillChildProcesses(int parentPid)
        {
            // Get list of child processes of the parent process
            using (var searcher = new ManagementObjectSearcher("select ProcessId from Win32_Process where ParentProcessId=" + parentPid))
            using (ManagementObjectCollection objCollection = searcher.Get())
            {
                // Kill child processes recursively
                foreach (ManagementObject obj in objCollection)
                {
                    int pid = Convert.ToInt32(obj["ProcessID"]);
                    KillChildProcesses(pid);
                }
            }

            try
            {
                // Kill parent process
                Process.GetProcessById(parentPid).Kill();
            }
            catch (ArgumentException)
            {
                // Ignore; this exception is thrown if the process with the given ID has already exited
            }
        }

        // Handler for OutputDataReceived event of process.
        private void _process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            _standardOutput.AppendLine(e.Data);

            OutputDataReceived(this, new DataEventArgs(e.Data));
        }

        // Handler for ErrorDataReceived event of process.
        private void _process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            _standardError.AppendLine(e.Data);

            ErrorDataReceived(this, new DataEventArgs(e.Data));
        }

        // Handler for Exited event of process.
        private void _process_Exited(object sender, EventArgs e)
        {
            HasExited = true;
            IsRunning = false;
            ExitCode = _process.ExitCode;
            Exited(this, e);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer
United States United States
I have been developing software for several years, both personally and professionally. These days, I'm mostly coding in C++, C#, Objective-C and Python. In my spare time, I can usually be found playing video games, reading books, bicycling and hiking.

Comments and Discussions