2

Requirement :

Run multiple commands in cmd.exe simultaneously and write the output to a single text file using c# including the start time and end time of the executed command

Do note that I want to use dot net version 2.0 because this code needs to run on legacy OS like XP . Parallel and ConcurrentBag feature is under .net 4.5 version

Code Summary :

  1. Created a string list which holds all the commands to be executed.
  2. Iterate through the string list and pass the command as a parameter to a class which has a static method runCommand(string command)

  3. using thread to make sure each command is executed in a separate thread in parallel.

Problem :

The code runs fine but the output gets mixed up with returns from all the commands when writing to console and i am sure the same problem would arise when writing to file ! How do i ensure that all the commands run in parallel + output looks neat and not mixed up . Also note that when i try to write to a file it errors out because multiple processes are trying to write to the same file.

Main

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using BaileySoft.Utility;

namespace Diagnostic_Commands
{
    class Program
    {
        static void Main(string[] args)
        {

            // Log file creation
            string strDestopPath = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            strDestopPath += "\\Diagnostic_Today.txt";
            StreamWriter w = File.AppendText(strDestopPath);

            List<String> commands = new List<String>();
            commands.Add("nslookup www.google.com");
            commands.Add("Tracert -d  www.apple.com");         
            commands.Add("ipconfig /all");
            commands.Add("ping www.google.com -n 10");       
            commands.Add("nslookup www.apple.com");


            foreach (string cmd in commands)
            {


                    Thread tReturn = new Thread(() => { Test_Con.runCommand(cmd); });
                    tReturn.IsBackground = true;
                    tReturn.Priority = ThreadPriority.AboveNormal;
                    tReturn.IsBackground = true;
                    tReturn.Start();

            }

            Console.ReadLine();


        }

    }
}

Class

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

public static class Test_Con
{
    static string d = null;

    public static void runCommand(string command)
    {
        string starttime;
        string endtime;

        //* Create your Process
        Process process = new Process();
        process.StartInfo.FileName = "cmd.exe";
        process.StartInfo.Arguments = "/c" + command;

        starttime = "Started at " + DateTime.Now + "\n";

        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        //* Set your output and error (asynchronous) handlers
        process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
        process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
        //* Start process and handlers
        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        process.WaitForExit();
        endtime = "Completed at " + DateTime.Now + "\n";

        d+= "========================================================================";
        d+= starttime + endtime ;

        Console.WriteLine(d);
    }
    static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        //* Do your stuff with the output (write to console/log/StringBuilder)
        Console.WriteLine(outLine.Data); //This will keep writing all the command output irrespective    

    }

    }

}
3
  • 1
    The better you can do is have some type of collection (per example a dictionary of pid and string), then add the outputs to it and when all the commands have finished write the dictionary content to the file. Commented Jul 8, 2016 at 15:58
  • 1
    stackoverflow.com/a/8055430/366904 Commented Jul 8, 2016 at 15:58
  • stackoverflow.com/questions/8035029/… Commented Jul 8, 2016 at 16:00

1 Answer 1

3

You can work with Parallel and ConcurrentBag. Bellow is an example, but you have to improve it.

static void Main(string[] args)
        {
            // Log file creation
            var strDestopPath = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            strDestopPath += "\\Diagnostic_Today.txt";
            var w = File.AppendText(strDestopPath);

            var commands = new ConcurrentBag<string>();
            //List<String> commands = new List<String>();
            commands.Add("nslookup www.google.com");
            commands.Add("Tracert -d  www.apple.com");
            commands.Add("ipconfig /all");
            commands.Add("ping www.google.com -n 10");
            commands.Add("nslookup www.apple.com");

            var results = new ConcurrentBag<Tuple<string, string>>();

            Parallel.ForEach(commands, cmd => {
                new Test_Con(results).runCommand(cmd);
            });


            //Your results are here:
            foreach (var result in results)
            {
                Console.WriteLine("Command: {0}",result.Item1);
                Console.WriteLine("OutPut: {0}",result.Item1);
                Console.WriteLine("----------------------------");
            }

            Console.ReadLine();
        }
    }

    public class Test_Con
    {
        static string d = null;
        private ConcurrentBag<Tuple<string, string>> results;
        private string command;

        public Test_Con(ConcurrentBag<Tuple<string, string>> results)
        {
            this.results = results;
        }

        public void runCommand(string command)
        {
            this.command = command;
            string starttime;
            string endtime;

            //* Create your Process
            Process process = new Process();
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.Arguments = "/c" + command;

            starttime = "Started at " + DateTime.Now + "\n";

            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            //* Set your output and error (asynchronous) handlers
            process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
            process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
            //* Start process and handlers
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            process.WaitForExit();
            endtime = "Completed at " + DateTime.Now + "\n";

            d += "========================================================================";
            d += starttime + endtime;

            Console.WriteLine(d);
        }
        void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            //* Do your stuff with the output (write to console/log/StringBuilder)
            Console.WriteLine(outLine.Data); //This will keep writing all the command output irrespective    

            results.Add(new Tuple<string, string>( command, outLine.Data ));
        }

    }
Sign up to request clarification or add additional context in comments.

1 Comment

Do note that i want to use dot net version 2.0 because this code needs to run on legacy OS like XP . Parallel and ConcurrentBag feature is under .net 4.5 version

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.