9

We have a few commands(batch files/executables) on our network path which we have to call to initialize our 'development environment' for that command window. It sets some environmental variables, adds stuff to the Path etc. (Then only whatever working commands we type will be recognized & I don't know what goes inside those initializing commands)

Now my problem is, I want to call a series of those 'working commands' using a C# program, and certainly, they will work only if the initial setup is done. How can I do that? Currently, I'm creating a batch file by scratch from the program like this for example:

file.Writeline("InitializationStep1.bat")
file.Writeline("InitializeStep2.exe")
file.Writeline("InitializeStep3.exe")

Then the actual commands

file.Writeline("Dowork -arguments -flags -blah -blah")
file.Writeline("DoMoreWork -arguments -flags -blah -blah")

Then finally close the file writer, and run this batch file.

Now if I directly execute this using Process.<strike>Run</strike>Start("cmd.exe","Dowork -arguments"); it won't run.

How can I achieve this in a cleaner way, so that I have to run the initialization commands only once? (I could run cmd.exe each time with all three initializers, but they take a lot of time so I want to do it only once)

Piyush Soni
  • 1,356
  • 3
  • 17
  • 40
  • Hi friends, sorry for the confusion, I meant Process.Start only and not Process.Run. Also, I guess I was not clear enough in explaining my problem. I know how to execute these kind of basic commands using Process.Start and ProcessStartInfo as well. My problem is, once I execute it, it's all over - while I want to call the 'initialize' batch file with that process, and THEN the actual working commands in the SAME process as only that one has correct environment variables and proper Path set. – Piyush Soni Jan 25 '11 at 12:18
  • also, by "it won't run" I meant it won't run because the prerequisites for running the command are set in the command prompt only by calling those initializer batch and exe files. So this command Dowork is not even recognized if I run directly with process. – Piyush Soni Jan 25 '11 at 13:48
  • Is this the control flow: 1. Create batch file (without arguments), 2. Execute commands in the batch file with a specified arguments in another process.? If I am incorrect, then what is the exact control flow? You above comments are not very precise. – Devendra D. Chavan Jan 27 '11 at 03:00

2 Answers2

15

As @Hakeem has pointed out, System.Diagnostic.Process does not have a static Run method. I think you are referring to the method Start.
Once you have completed building the batch file, then simply execute it using the following code,

Process p = new Process();
p.StartInfo.FileName = batchFilePath;
p.StartInfo.Arguments = @"-a arg1 -b arg2";
p.Start();

Note that the @ symbol is required to be prefixed to the argument string so that escape sequence characters like \ are treated as literals.

Alternative code

Process.Start(batchFilePath, @"-a arg1 -b arg2");

or

ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = batchFilePath;
processStartInfo.Arguments = @"-a arg1 -b arg2";
Process.Start(processStartInfo);


More information

Example of multi command batch file

dir /O
pause
dir
pause

Save this file as .bat and then execute using the Start method. In this case you can specify the argument with the command in the batch file itself (in the above example, the /O option is specified for the dir command.
I suppose you already have done the batch file creation part, now just append the arguments to the commands in the batch file.

Redirecting Input to a process
Since you want to send multiple commands to the same cmd process, you can redirect the standard input of the process to the take the input from your program rather than the keyboard.

Code is inspired from a similar question at: Execute multiple command lines with the same process using C#

private string ProcessRunner()
{
    ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
    processStartInfo.RedirectStandardInput = true;
    processStartInfo.RedirectStandardOutput = true;
    processStartInfo.UseShellExecute = false;

    Process process = Process.Start(processStartInfo);

    if (process != null)
    {
        process.StandardInput.WriteLine("dir");
        process.StandardInput.WriteLine("mkdir testDir");
        process.StandardInput.WriteLine("echo hello");
        //process.StandardInput.WriteLine("yourCommand.exe arg1 arg2");

        process.StandardInput.Close(); // line added to stop process from hanging on ReadToEnd()

        string outputString = process.StandardOutput.ReadToEnd();
        return outputString;
    }

    return string.Empty;
}

The method returns the output of the command execution. In a similar fashion, you could also redirect and read the StandardOuput stream of the process.

Community
  • 1
  • 1
Devendra D. Chavan
  • 8,871
  • 4
  • 31
  • 35
  • Hi Devendra, as also edited in the question, Process.Run was a typo, it was Process.Start. My problem is not running just one command or batch file. It is how to run a series of commands, in the same cmd window created once. Do you know how to do that? – Piyush Soni Jan 26 '11 at 16:20
  • @Piyush, you can programmatically create a batch file with each command on a separate line. I have edited the answer to add an example. – Devendra D. Chavan Jan 27 '11 at 02:47
  • Hi Devendra, that is what I was originally doing(which was working as well), but I wanted a cleaner approach of executing a series of steps in the same command window process. – Piyush Soni Jan 27 '11 at 20:22
  • @Piyush, batch files are the way to execute a series of commands. But you could put all the commands in a single batch file requiring a single call initializer commands. An alternative would be to communicate with the child process (cmd.exe) using IPC, but this would complicate the existing solution. Nevertheless, you can have a look at: http://stackoverflow.com/questions/50153/interprocess-communication-for-windows-in-c-net-2-0 and a similar question at: http://stackoverflow.com/questions/1515965/how-to-input-a-string-from-user-into-evnironment-variable-from-cmd-script – Devendra D. Chavan Jan 28 '11 at 01:50
  • As far as I know, IPC is useful only when both of the programs communicating are written by us (or we know about the code of the other one). I don't know how to communicate with cmd.exe. And the second link is not at all related to my question. The essence of my original question was actually very short :"How to send a sequence of commands to a SINGLE command prompt process, without using a batch file, which I was anyway doing." – Piyush Soni Jan 29 '11 at 00:44
  • @Piyush, I have updated the answer according to my understanding of your previous comment. Look under the last section 'Redirecting Input to a process'. – Devendra D. Chavan Jan 29 '11 at 03:22
  • You can have a single cmd.exe sequentially execute multiple commands without using a batch file by invoking them like this: command1 && command2 This will execute command1 followed by command 2 without creating new cmd processes and thus preserving the environment between calls – Crippledsmurf Jan 29 '11 at 05:29
  • Thanks Devendra, yes, the solution of redirecting the input works. (I wish I had waited before asking the question on experts-exchange.com and losing some points for getting the same answer). Thanks a lot for your help! – Piyush Soni Jan 30 '11 at 18:12
  • @Crippledsmurf: Yup, I am aware of the && operator for running cmd (and am actually using it as a short cut for quickly initialize my cmd prompt), but my commands are way too many to include in one cmd with &&, and I'm afraid this will have a character limit we can pass in one line. The redirecting standard input to cmd prompt works. – Piyush Soni Jan 30 '11 at 18:44
  • Hi Devendra, after the redirect input to cmd worked, I thought of reading the standard output also. But it hangs on reading the standard output. Even your example given above hangs forever on ReadToEnd(). Does it work on your machine? How to get it working? – Piyush Soni Feb 02 '11 at 06:52
  • @Piyush, there seems to a deadlock in the method call. Please check the Remakes section at [ProcessStartInfo.RedirectStandardOutput Property](http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx). – Devendra D. Chavan Feb 02 '11 at 08:25
  • @Devendra D. Chavan, I saw that description on msdn's page, but didn't get a lot of it. I am not reading both error and output at once. I just want to read the output synchronously after executing each of the single commands (howsoever time it takes, it should wait before that). Is there a way to do that, or it's necessary to use multi-threaded readers for this simple requirement? Thanks! – Piyush Soni Feb 04 '11 at 23:09
  • @Piyush, it seems to be problem when both the input and output stream are being redirected. I have found a workaround and it seems to work. I have edited the answer to reflect this change [process.StandardInput.Close()]. Let me know if it works. – Devendra D. Chavan Feb 06 '11 at 16:45
  • @Piyush, As I have pointed out earlier, there is deadlock occurring when 2 stream are access synchronously. The solution to this problem can be 2 fold: 1. Read ouput asynchronously [process.BeginOutputReadLine()] or, 2. Call Close() on one stream before accessing the next. I have edited the answer for the later solution [process.StandardInput.Close()]. More information at: [Process.StandardOutput Property](http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx) – Devendra D. Chavan Feb 06 '11 at 16:53
  • Redirecting the input is a very good solution, but the is there an option to see the output in the console too ? I am able to read in the process, this way the user can know what's going on – Afaque Oct 18 '16 at 12:29
0

The Process.Run method that you mentioned, is that from the Process class in System.Diagnostics namespace? AFAIK, the Process type doesn't have either a static or instance method named Run. If you haven't already I'd try with the Start method on Process, either instance or static

Hakeem
  • 346
  • 1
  • 8