Execute Command Prompt commands from C#

Execute Command Prompt commands from C#

We are partnering up with TechInDeep to bring you more C# Tips and Tricks.

Before continuing with this post make sure to check out some other articles as well:

In this new post, I am going to demonstrate how to Execute Command Prompt commands from C#

One of the biggest issues I have found so far is calling “cmd.exe” using Process in C# always hangs. There are two possible solutions to the problem. One being the following code snipet:

var processInfo = new ProcessStartInfo("cmd.exe", "/c systeminfo") 
{
    CreateNoWindow = true,
    UseShellExecute = false,
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    WorkingDirectory = @"C:\Windows\System32\"
};

StringBuilder sb = new StringBuilder();
Process p = Process.Start(processInfo);
p.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
p.BeginOutputReadLine();
p.WaitForExit();
Console.WriteLine(sb.ToString());

But then I would have to pass my input arguments at process creation time, which in my case was not an option.

The other solution was to redirect the StandardInput and StandardOutput. But it came with a price. If you redirect the streams you are effectively using async operations. In my particular situation that was not an option as well. See, I wanted to be able to execute command, return the result to my app, and then continue on with the rest of my code.

So let’s look at the code that allowed me to solve this problem correctly.

Create a instance from System.Diagnostics.Process Class

private Process _cmdProcess;

But I will need additional fields such as:

private StreamWriter _streamWriter;
private AutoResetEvent _outputWaitHandle;
private string _cmdOutput;

OK, so what are they?

  • StreamWriter will be responsible for redirecting the input to the command prompt
  • AutoResetEvent will be the thread synchronizer. When reading from the Command Prompt output is done it will signal the main thread to resume and return the result
  • cmdOutput is just a string field that will hold the complete string output from the Command Prompt

Next we need to create an instance of ProcessStartInfo class and initialize it correctly.

ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = cmdPath;
            processStartInfo.UseShellExecute = false;
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.RedirectStandardInput = true;
            processStartInfo.CreateNoWindow = true;

_cmdProcess.OutputDataReceived += _cmdProcess_OutputDataReceived;

cmdPath for me it always represents “cmd.exe” because I have set my Environment path variable for cmd to point to my cmd.exe location. If you don’t have it set, please do or just set the full path to your cmd.exe

  • UseShellExecute Gets or sets a value indicating whether to use the operating system shell to start the process.
  • RedirectStandardOutput redirects the standard output (we will see in just a bit where)
  • RedirectStandardInput redirects the standard input to our StreamWriter, which we will use to pass commands to Command Prompt
  • CreateNoWindow true if the process should be started without creating a new window to contain it; otherwise, false. The default is false. (We don’t want additional cmd windows, we only want ours)

You can see all properties and their documentation here

Once we initialize our constructor, we can actually call:

_cmdProcess.BeginOutputReadLine();

which in term begins asynchronous read operations on the redirected StandardOutput stream of the application. Which is exactly what we wanted. Now all we have to do is execute a command and get the output.

Execute Command Prompt Command

I will define a method in the CmdService class called ExecuteCommand which as input gets the user typed command. The method implementation is as follows:

        public string ExecuteCommand(string command)
        {
            _cmdOutput = String.Empty;

            _streamWriter.WriteLine(command);
            _streamWriter.WriteLine("echo end");
            _outputWaitHandle.WaitOne();
            return _cmdOutput;
        }

Here happens the most interesting logic. First we execute the users command. In order to do that, we use the streamWriter (since we’ve already redirected the standard input to the Command Prompt). So after this command is executed, I am going to execute one more command

echo end

which will print “end” at the StandardOutput. We’ll get to that in just a little bit.

_outputWaitHandle.WaitOne();

The WaitOne() call will stop the execution of the main thread. Since the whole Command Prompt Output process is asynchronous this is a safe operation to do. So while the main thread is stopped from executing, the _cmdProcess_OutputDataReceived method is executing in async fashion. Meaning that it will receive the Command Prompt Output. In order not to hang we set the condition as follows:

            if (e.Data == null || e.Data == "end")
                _outputWaitHandle.Set();
            else
                _cmdOutput += e.Data + Environment.NewLine;

Which basically means that as long as the output is not Null or prints out “end” gather the output in the _cmdOutput string field. The “echo end” command allows us to bypass the “hang” problem of “cmd” command execution.

Test The Application

In order to Execute Command Prompt commands from C# we will now put to use our CmdService class we wrote earlier.

            using (CmdService cmdService = new CmdService("cmd.exe"))
            {
                string consoleCommand = String.Empty;
                do
                {
                    consoleCommand = Console.ReadLine();
                    string output = cmdService.ExecuteCommand(consoleCommand);
                    Console.WriteLine(">>> {0}", output);
                }
                while (!String.IsNullOrEmpty(consoleCommand));
            }

Just read the user’s input and pass it to ExecuteCommand function. The main thread will stop execution until the CMD prompt returns a result. Then just print out the result.

Commands

Execution of "echo Hello" command
Execution “echo Hello” command
Execution of "dir" command
Execution of “dir” command

Here you can see that the output of the Command Prompt is not only one line. As well you can see the “echo end” command that prevents the process from hanging.

Please note that this output CAN be filtered to your needs.

Execute Anaconda Command

Execution of "conda env list" command
Execution of “conda env list” command

I can also use the Anaconda prompt to execute commands from Anaconda. Here you can see the output of all my environments. Now let’s activate “Python3″ environment.

Execution of "activate Python3" command from Anaconda Prompt
Execution of “activate Python3” command from Anaconda

So as you can see I successfully activated my Python3 environment and the only thing that is left for me to do is execute a python script.

Now with my environment activated I can do the following:

Execution of Python Script
Execution of Python script

And inside the script the code is:

print("Hello from Python")

Execute Command Prompt commands from C# : Conclusion

We have just created our own Command Prompt for command execution. This is only the part one of a two part series in which I intend to explain how to execute Python code via C# (no matter your python DEV environment) and write Python code using dynamics.

More Tutorials