37

I want to run some cmd command from c#code. I followed some blogs and tutorial and got the answer, but I am in little bit confused i.e how should I pass multiple arguments?

I use follow code:

System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = 
...

What will be the startInfo.Arguments value for the following command line code?

  • makecert -sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My MyAdHocTestCert.cer

  • netsh http add sslcert ipport=127.0.0.1:8085 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF} clientcertnegotiation=enable

Esko
  • 4,109
  • 2
  • 22
  • 37
Amit Pal
  • 10,604
  • 26
  • 80
  • 160

6 Answers6

53

It is purely a string:

startInfo.Arguments = "-sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My MyAdHocTestCert.cer"

Of course, when arguments contain whitespaces you'll have to escape them using \" \", like:

"... -ss \"My MyAdHocTestCert.cer\""

See MSDN for this.

Sjors Ottjes
  • 1,067
  • 2
  • 12
  • 17
bash.d
  • 13,029
  • 3
  • 29
  • 42
  • 1
    And if I need to execute them using the | symbol like in this command? netstat -ano |find /i "listening" |find /i "17328" – Revious Mar 06 '15 at 13:14
  • My guess would be to escape the " by using \", give it a shot. – bash.d Mar 09 '15 at 13:18
  • 2
    Maybe I don't understand this answer, but your code appears to add only one instruction, the first that OP mentioned. How could they add their second instruction with the same startInfo? – ThePartyTurtle Jul 01 '16 at 15:03
4
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = @"/c -sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My MyAdHocTestCert.cer"

use /c as a cmd argument to close cmd.exe once its finish processing your commands

Zaid Amir
  • 4,727
  • 6
  • 52
  • 101
3
startInfo.Arguments = "/c \"netsh http add sslcert ipport=127.0.0.1:8085 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF} clientcertnegotiation=enable\"";

and...

startInfo.Arguments = "/c \"makecert -sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My MyAdHocTestCert.cer\"";

The /c tells cmd to quit once the command has completed. Everything after /c is the command you want to run (within cmd), including all of the arguments.

sparky68967
  • 637
  • 1
  • 5
  • 8
3

Remember to include System.Diagnostics

ProcessStartInfo startInfo = new ProcessStartInfo("myfile.exe");        // exe file
startInfo.WorkingDirectory = @"C:\..\MyFile\bin\Debug\netcoreapp3.1\"; // exe folder

//here you add your arguments
startInfo.ArgumentList.Add("arg0");       // First argument          
startInfo.ArgumentList.Add("arg2");       // second argument
startInfo.ArgumentList.Add("arg3");       // third argument
Process.Start(startInfo);                 
  • 1
    For space separated arguments, or name/value pairs, this is the best answer. There's a caveat here though. If you need an argument like: `--arg1="value1"`. This will be escaped and won't work as expected. – CodeAngry Jun 04 '21 at 02:01
2

Just use "&&" in your command line.

 StartInfo.Arguments = @"/C cd C:\Users\yoooo\Desktop && echo This is a sample text file > sample.txt" 
Lucid
  • 21
  • 2
1

.NetStandard 2.1 includes a nice feature called ArgumentList that automatically escapes arguments for you when given a Collection<string>. But (like in my case) if you cannot target .NetStandard 2.1 you are out of luck...BUT! I dug into the ProcessStartInfo source code for .NetStandard 2.1 and was able to extract this class:

internal static class PasteArguments {
        internal static void AppendArgument(StringBuilder stringBuilder, string argument) {
            // from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs
            if (stringBuilder.Length != 0) {
                stringBuilder.Append(' ');
            }

            // Parsing rules for non-argv[0] arguments:
            //   - Backslash is a normal character except followed by a quote.
            //   - 2N backslashes followed by a quote ==> N literal backslashes followed by unescaped quote
            //   - 2N+1 backslashes followed by a quote ==> N literal backslashes followed by a literal quote
            //   - Parsing stops at first whitespace outside of quoted region.
            //   - (post 2008 rule): A closing quote followed by another quote ==> literal quote, and parsing remains in quoting mode.
            if (argument.Length != 0 && ContainsNoWhitespaceOrQuotes(argument)) {
                // Simple case - no quoting or changes needed.
                stringBuilder.Append(argument);
            } else {
                stringBuilder.Append(Quote);
                int idx = 0;
                while (idx < argument.Length) {
                    char c = argument[idx++];
                    if (c == Backslash) {
                        int numBackSlash = 1;
                        while (idx < argument.Length && argument[idx] == Backslash) {
                            idx++;
                            numBackSlash++;
                        }

                        if (idx == argument.Length) {
                            // We'll emit an end quote after this so must double the number of backslashes.
                            stringBuilder.Append(Backslash, numBackSlash * 2);
                        } else if (argument[idx] == Quote) {
                            // Backslashes will be followed by a quote. Must double the number of backslashes.
                            stringBuilder.Append(Backslash, numBackSlash * 2 + 1);
                            stringBuilder.Append(Quote);
                            idx++;
                        } else {
                            // Backslash will not be followed by a quote, so emit as normal characters.
                            stringBuilder.Append(Backslash, numBackSlash);
                        }

                        continue;
                    }

                    if (c == Quote) {
                        // Escape the quote so it appears as a literal. This also guarantees that we won't end up generating a closing quote followed
                        // by another quote (which parses differently pre-2008 vs. post-2008.)
                        stringBuilder.Append(Backslash);
                        stringBuilder.Append(Quote);
                        continue;
                    }

                    stringBuilder.Append(c);
                }

                stringBuilder.Append(Quote);
            }
        }

Example Usage:

static string GetArgumentStr(List<string> argList) {
        if(argList == null || argList.Count == 0) {
            return string.Empty;
        }
        var sb = new StringBuilder();
        foreach(var arg in argList) {
            PasteArguments.AppendArgument(sb, arg);
        }
        return sb.ToString();
    }
tkefauver
  • 491
  • 5
  • 19