1
  1. I want to run a series of commands on cmd.exe from C#.
  2. I need to open only one window of cmd
  3. I need to keep the cmd window open through the execution and after the completion.
  4. I need to display the commands [edit]in the opened cmd window[/edit] executed as well as the output of the commands.

So basically I want to open and use the cmd.exe just like a manual user would. I tried some methods, but none could do all 4 items above.

Below code works but does not display the commands/outputs and terminates after completion. Any help?

Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.RedirectStandardInput = true;
info.UseShellExecute = false;
info.CreateNoWindow = false;
info.Arguments = "/k";

p.StartInfo = info;
p.Start();

using (StreamWriter sw = p.StandardInput)
{
    if (sw.BaseStream.CanWrite)
    {
         sw.WriteLine("dir");
         sw.WriteLine("ipconfig");
    }
}
hkn
  • 13
  • 1
  • 4

2 Answers2

4

The RedirectStandard...-properties are misleading. As soon as you set one of them, all three streams will be redirected. This is because the underlying Windows API only has a single flag to control redirection - STARTF_USESTDHANDLES.

Because you didn't set the RedirectStandardOutput property to true, the stdout streams isn't made available to your code, but instead will be redirected to the Console.Out stream of your own process. Thus, your code works fine as long as the parent process is a console application; but in a Windows application, the output gets redirected into nothingness.

An easy workaround is to temporarily turn your parent process into a console application:

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeConsole();

static void Main(string[] args)
{
    Process p = new Process();
    ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
    info.RedirectStandardInput = true;
    info.UseShellExecute = false;
    info.CreateNoWindow = false;

    p.StartInfo = info;
    AllocConsole();
    p.Start();
    FreeConsole();


    using (StreamWriter sw = p.StandardInput)
    {
        if (sw.BaseStream.CanWrite)
        {
             sw.WriteLine("dir");
             sw.WriteLine("ipconfig");
        }
    }
}

As for keeping the console open: you could just remove the FreeConsole() call so that the parent process keeps the console around even after cmd.exe exits. However this may be a problem if you need multiple consoles, as your parent process can't be associated with more than one console at a time.

Alternatively, don't close the input stream so that cmd.exe keeps running.

Daniel
  • 15,944
  • 2
  • 54
  • 60
  • Thanks Daniel, i was wondering why the output was redirected to console while debugging even when i did not set the RedirectStandardOutput to true. Your code does pretty much what i need visually. However there are 2 limitations. 1- I can only open one console which you pointed out. 2 - If i close the console, the application terminates which i do not want. Would it be possible to create a child process and run the console from that one so it would be an independent console or do child processes share the console? – hkn Apr 11 '13 at 10:29
  • Those two problems don't occur if you call `FreeConsole()`. In that case, you'll have to keep the input stream open (no `using` block) so that cmd.exe keeps running. – Daniel Apr 11 '13 at 10:37
  • I did try that but it just resulted in the console hanging without doing anything. When i tried it the release build it works like a charm though:) Still it works so thanks – hkn Apr 11 '13 at 12:22
0

For seeing the out put insert Console.ReadLine();(application stop until you send a key so you can see the result) after command executed.

  static void Main(string[] args)
            {
                Process p = new Process();
                ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
                info.RedirectStandardInput = true;
                info.UseShellExecute = false;
                info.CreateNoWindow = false;

                p.StartInfo = info;
                p.Start();

                using (StreamWriter sw = p.StandardInput)
                {
                    if (sw.BaseStream.CanWrite)
                    {
                        sw.WriteLine("dir");

                        sw.WriteLine("ipconfig");
                    }
                }
                Console.ReadLine();
            }
KF2
  • 9,887
  • 8
  • 44
  • 77
  • Thanks IRSOG but, I need both the commands and the output displayed on the opened cmd window not just read it into memory – hkn Apr 11 '13 at 10:40