How To Execute CMD Commands In C# (Multi-Threaded Example)

Today I was asked how to initiate CMD commands in windows and execute them in a C# application. And I thought Iā€™d share some insight into the subject and demonstrate how to do it. Lets start with our using directives:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

We will first need a delegate. This delegate will be used to allow us to talk to our UI from a non UI thread which will be created using Task. Delegate:

 public delegate void DelegateCallback(string s);

Next we want to go to our form and we want to click on the lightening Icon in the Properties Box; this is done on the designer window after clicking the button. You need to click the lightening icon, and look for Click Event, and just double click it.

 private void button1_Click(object sender, EventArgs e)
 {
 string[] ips = { "127.0.0.1", "google.com" };
 MainMethod(ips);
 }

The above code demonstrates the array of strings which will hold some IP addresses we will be passing on to our MainMethod a little bit later on. Our MainMethod(ips) passed on the string array, as our MainMethod takes only one parameter, and this will be the parameter being passed in.

Next, we will add a new method, and this method is what our Delegate will interact with when it wishes to update our UI with new information from our processing thread which will perform the CMD command in our C Sharp code. Our UpdateUI method:

 private void UpdateUI(string item)
 {
 StringBuilder stringBuilder = new StringBuilder();
 stringBuilder.Insert(0, textBox1.Text);
 stringBuilder.Append(item);
 textBox1.Text = stringBuilder.ToString();
 }

First we define a new String Builder, and then we Insert the contents of the Textbox and the zero based index of the String Builder. Zero means we are inserting the first occurrence at the start of the string.

Then we append the String Builder, with the Item string which is the value being passed to our delegate to update our UI from the MainMethod we spoke of earlier. Lastly, with the String Builder, we set the textbox1 text property of the textbox to the StringBuilder, by calling the .ToString() method. And the method doing all the work is our MainMethod:

 private void MainMethod(string[] of_addresses)
 {
 List<string> addresses = new List<string>();
 addresses.AddRange(of_addresses);
 Task.Run(() =>
 {
 Process cmd = new Process();
 addresses.ForEach(delegate (string current_address)
 {
 cmd.StartInfo.FileName = "cmd.exe";
 cmd.StartInfo.UseShellExecute = false;
 cmd.StartInfo.CreateNoWindow = true;
 cmd.StartInfo.Arguments = $"/c ping {current_address}";
 cmd.StartInfo.RedirectStandardOutput = true;
 cmd.Start();
 textBox1.Invoke(new DelegateCallback(UpdateUI), new string[] { cmd.StandardOutput.ReadToEnd() });
 });
 });
 }

Our MainMethod takes a string array parameter. This will be the addresses we will pass in. Next we instantiate a new AddRange method and pass in the string array of Addresses.

Next step is to utilise a Task and begin executing the process. Defining a new process : Process cmd = new Process(); ā€“ and also iterating over each string in out addresses list by delegating the value of each string to the process parameters using the List.ForEach() method of the List<string> which I will now explain what those properties are and what they do :

cmd.StartInfo.FileName = "cmd.exe"; => simply sets the file to execute.
cmd.StartInfo.UseShellExecute = false; => indicates whether to use the operating system shell to start the process.
cmd.StartInfo.CreateNoWindow = true; => if enabled prevents a window from showing, otherwise if false, will display the window of the executable being launches by this process.
cmd.StartInfo.Arguments = $"/c ping {current_address}"; => sets the arguments to be passed to the executable process being launched. In this case, I am setting the argument to ping each address in our list as it iterates each string address.
cmd.StartInfo.RedirectStandardOutput = true; => indicates whether the textual output of an application is written to the StandardOutput stream.

With all that explained, cmd.Start(); simply launches the process.

textBox1.Invoke(new DelegateCallback(UpdateUI), new string[] { cmd.StandardOutput.ReadToEnd() });

Given that this method is executed in a task, we are not able to update the UI (User Interface) without invoking the control in which we want to sent the output stream of our command window too. So we delegate to our UI by calling our callback method which we mentioned earlier, and we pass it the new string value of the commands standard output stream.

All in all, if finished and you have followed this tutorial to the letter, you should have something whick looks like this:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestCSharpApp
{
 public partial class Form1 : Form
 {
 public Form1()
 {
 InitializeComponent();
 }

 public delegate void DelegateCallback(string s);

 private void MainMethod(string[] of_addresses)
 {
 List<string> addresses = new List<string>();
 addresses.AddRange(of_addresses);
 Task.Run(() =>
 {
 Process cmd = new Process();
 addresses.ForEach(delegate (string current_address)
 {
 cmd.StartInfo.FileName = "cmd.exe";
 cmd.StartInfo.UseShellExecute = false;
 cmd.StartInfo.CreateNoWindow = true;
 cmd.StartInfo.Arguments = $"/c ping {current_address}";
 cmd.StartInfo.RedirectStandardOutput = true;
 cmd.Start();
 textBox1.Invoke(new DelegateCallback(UpdateUI), new string[] { cmd.StandardOutput.ReadToEnd() });
 });
 });
 }
 private void UpdateUI(string item)
 {
 StringBuilder stringBuilder = new StringBuilder();
 stringBuilder.Insert(0, textBox1.Text);
 textBox1.Clear();
 stringBuilder.Append(item);
 textBox1.Text = stringBuilder.ToString();
 }

 private void button1_Click(object sender, EventArgs e)
 {
 string[] ips = { "127.0.0.1", "google.com" };
 MainMethod(ips);
 }
 }
}

I hope you found this blog interesting and somewhat useful.