1

I want to write a c# code to execute some command prompt lines and store the result into a global variable in c# to be used for further processing in other part of the code in c#.

I bought a device and I installed its driver. The only way for me to obtain its data is using command line in command prompt. There is no API available. But, I want to do in c# so that is why I am having trouble.

I have some code and it doesn't works for some reason. Note, I used argument input = "date" is only for illustration purpose. My work is not using "date" but some arguments to obtain data.

static void Main(string[] args)
{
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    // the cmd program
    startInfo.FileName = "cmd.exe";
    // set my arguments. date is just a dummy example. the real work isn't use date.
    startInfo.Arguments = "date";
    startInfo.RedirectStandardOutput = true;
    startInfo.UseShellExecute = false;
    process.StartInfo = startInfo;
    process.Start();
    // capture what is generated in command prompt
    var output = process.StandardOutput.ReadToEnd();
    // write output to console
    Console.WriteLine(output);
    process.WaitForExit();

    Console.Read();
}

Any help is appreciated.

2
  • 5
    so that is why I am having trouble what trouble? "it doesn't work" isn't a description of the problem. What does it do? Crash? Give an error? Collapse into a singularity? Do nothing at all? What did you expect it to do? Commented Oct 8, 2014 at 15:09
  • Your problem is probably that date, by itself, prompts you to enter a new date (try it from the command line). Try date /T which will output the date and not require you to give it any input. Alternatively, you might be able to just write an enter to the standard input. Commented Oct 8, 2014 at 15:12

2 Answers 2

2

you'll need to use /c date to get cmd to launch date like that.

static void Main(string[] args)
{
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    // the cmd program
    startInfo.FileName = "cmd.exe";
    // set my arguments. date is just a dummy example. the real work isn't use date.
    startInfo.Arguments = "/c date";
    startInfo.RedirectStandardOutput = true;
    startInfo.UseShellExecute = false;
    process.StartInfo = startInfo;
    process.Start();
    // capture what is generated in command prompt
    var output = process.StandardOutput.ReadToEnd();
    // write output to console
    Console.WriteLine(output);
    process.WaitForExit();

    Console.Read();
}

the flags /c and /k are your friends when using cmd.exe to launch other programs. /c is used to execute a program then exit CMD. /k is used to execute a program then leave CMD running.

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

6 Comments

In the case of date you also need the /T flag for date or else you need to redirect StandardInput and WriteLine to it.
thanks. but the code still doesn't give date. its empty.
actually it works. something maybe wrong with the date. i tried ipconfig and it gives data. good job.
hi..how do i pass in multiple arguments? I need to browse to a directory and enter an argument. I know you can do something like that like process.start("cmd.exe", "arg1 arg2 arg3")
I edited my previous answer post with the c# equivalent of the class. It makes this argument largely moot as it would pass the whole command chain as a single string, every time, regardless of syntax....
|
2

I would also guess not all applications use stderr and stdout properly so it is possible what you see in a "Console Application" is not delivering the information where you expect it.

If nothing more redirecting stderr as well, will also allow you to see if it is syntax related and the application is tossing an exception.

startInfo.RedirectStandardError = true;

I want to add to that, by wrapping it up in a class, you can interact with the cmd shell, not just run and return... If you are trying to automate an application silently, this is likely the approach you want...

I just wrote a sample of this for a guy in VB, the syntax is probably rough because I had not launched VB in years, but you get the gist of it and should be able to replicate in C# fairly easily. This was a rough draft How to type approach, not a piece of code I would call production ready, teach a man to fish sample ;)

#Region " Imports "

Imports System.Threading
Imports System.ComponentModel

#End Region

Namespace Common

    Public Class CmdShell

#Region " Variables "

        Private WithEvents ShellProcess As Process

#End Region

#Region " Events "

        ''' <summary>
        ''' Event indicating an asyc read of the command process's StdOut pipe has occured.
        ''' </summary>
        Public Event DataReceived As EventHandler(Of CmdShellDataReceivedEventArgs)

#End Region

#Region " Public Methods "

        Public Sub New()
            ThreadPool.QueueUserWorkItem(AddressOf ShellLoop, Nothing)
            Do Until Not ShellProcess Is Nothing : Loop
        End Sub

        ''' <param name="Value">String value to write to the StdIn pipe of the command process, (CRLF not required).</param>
        Public Sub Write(ByVal value As String)
            ShellProcess.StandardInput.WriteLine(value)
        End Sub

#End Region

#Region " Private Methods "

        Private Sub ShellLoop(ByVal state As Object)
            Try
                Dim SI As New ProcessStartInfo("cmd.exe")
                With SI
                    .Arguments = "/k"
                    .RedirectStandardInput = True
                    .RedirectStandardOutput = True
                    .RedirectStandardError = True
                    .UseShellExecute = False
                    .CreateNoWindow = True
                    .WorkingDirectory = Environ("windir")
                End With
                Try
                    ShellProcess = Process.Start(SI)
                    With ShellProcess
                        .BeginOutputReadLine()
                        .BeginErrorReadLine()
                        .WaitForExit()
                    End With
                Catch ex As Exception
                    With ex
                        Trace.WriteLine(.Message)
                        Trace.WriteLine(.Source)
                        Trace.WriteLine(.StackTrace)
                    End With
                End Try
            Catch ex As Exception
                With ex
                    Trace.WriteLine(.Message)
                    Trace.WriteLine(.Source)
                    Trace.WriteLine(.StackTrace)
                End With
            End Try
        End Sub

        Private Sub ShellProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.ErrorDataReceived
            If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data))
        End Sub

        Private Sub ShellProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.OutputDataReceived
            If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data & Environment.NewLine))
        End Sub

#End Region

    End Class

    <EditorBrowsable(EditorBrowsableState.Never)> _
       Public Class CmdShellDataReceivedEventArgs : Inherits EventArgs
        Private _Value As String

        Public Sub New(ByVal value As String)
            _Value = value
        End Sub

        Public ReadOnly Property Value() As String
            Get
                Return _Value
            End Get
        End Property

    End Class

End Namespace

Just to make sure there were no pitfalls, I went ahead and did this dirty in c#

 public class cmdShell
    {
        private Process shellProcess;

        public delegate void onDataHandler(cmdShell sender, string e);
        public event onDataHandler onData;

        public cmdShell()
        {
            try
            {
                shellProcess = new Process();
                ProcessStartInfo si = new ProcessStartInfo("cmd.exe");
                si.Arguments = "/k";
                si.RedirectStandardInput = true;
                si.RedirectStandardOutput = true;
                si.RedirectStandardError = true;
                si.UseShellExecute = false;
                si.CreateNoWindow = true;
                si.WorkingDirectory = Environment.GetEnvironmentVariable("windir");
                shellProcess.StartInfo = si;
                shellProcess.OutputDataReceived += shellProcess_OutputDataReceived;
                shellProcess.ErrorDataReceived += shellProcess_ErrorDataReceived;
                shellProcess.Start();
                shellProcess.BeginErrorReadLine();
                shellProcess.BeginOutputReadLine();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        void shellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            doOnData(e.Data);
        }

        void shellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            doOnData(e.Data);
        }

        private void doOnData(string data)
        {
            if (onData != null) onData(this, data);
        }

        public void write(string data)
        {
            try
            {
                shellProcess.StandardInput.WriteLine(data);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }
    }

So now using like this

cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("ping 127.0.0.1");

with this on place

 void test_onData(cmdShell sender, string e)
        {
            Trace.WriteLine(e);
        }

You have a fully interactive cmd process to write to and receive async data from.

outputs to the window

C:\Windows>ping 127.0.0.1

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

Coffee, sleep... lol

If you really want date...

cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("date");

Yields output

C:\Windows>date
The current date is: Wed 10/08/2014

or

    cmdShell test = new cmdShell();
    test.onData += test_onData;
    test.write("echo %date%");

Yields output

C:\Windows>echo %date%
Wed 10/08/2014

By the way, in case you have not actually used the code yet, this method gives the data async, meaning as the program outputs it is delivered to you, so if you run a process that takes time, like 100 pings, traceroute, etc... you see them as they happen, not have to wait for it to complete and return.

Also you can pass commands back to the application during that, like canceling, reacting to and changing syntax, or simply running something else similar based on the result of the first run.

essentially you can treat it just like you were typing in a cmd window, and receiving the feedback there, wrap the whole think in a properly threaded form (Careful when updating windows controls from other threads), and you would have an emulated cmd prompt.

5 Comments

Thank you very much for your answer!!!))))) It's very-very useful and great! I have little question: how to get output from command like "python.exe" with your tool?
as long as python is in your path statement, you should be able to work with it just like you would with a cmd prompt. Did you want to launch python and interact with it? Or did you want to automate a command to python and just view the output? I cannot test from where I am, however if it outputs to stderr and stdout you should be able to just replace cmd with python (or full path to python executable if not in path) I would have to test to know for sure. I have written a few apps that automate the .NET compilers installed with the CLR this way.
I want to automate working with python.exe through cmd.exe, but I have a problem. I can not get python stdout and stderror (((It's look like that I redirect them to my application and python could not get them to himself for output and errors. If I run process with python.exe instead of cmd.exe this behavior repeats. I think, that the problem connected with streams redirection.
I would have to play with it to know for sure, and I bet it would vary based on the version of python. Can you let me know the details of exactly what version you are using and an example of what you are trying to achieve, I will see what I can do.
Python version 2.7, but I think, that nothing depends of it's version :((. As for details, I create Process with executable file "cmd.exe" and want working with it like I work with windows console in interactive mode. So, when I working with console in interactive mode, I can get answer from it immediately after command was sended. And I want python to return me result after my command immediately, but now I can get result only after python process has exited.

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.