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    

    }

    }

}
Prix
  • 19,417
  • 15
  • 73
  • 132
Cryptonology
  • 21
  • 1
  • 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. – Gusman Jul 08 '16 at 15:58
  • 1
    http://stackoverflow.com/a/8055430/366904 – Cody Gray - on strike Jul 08 '16 at 15:58
  • http://stackoverflow.com/questions/8035029/how-to-write-in-a-single-file-with-multiple-threads – Rick S Jul 08 '16 at 16:00

1 Answers1

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 ));
        }

    }
Ricardo França
  • 2,923
  • 2
  • 18
  • 18
  • 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 – Cryptonology Jul 09 '16 at 04:13