Call Windows Shell and Pass it some arguments .NET c# - c#

Here my problem, I want to use gpg.exe to decrypt some data. Before this, I want to test and make an "ipconfig" through the Windows Shell. I've tried :
Process.Start("cmd","ipconfig");
without success. Did someone know a way to help me please?
Thanks.

Take a look at this function (taken from here)
public static string ExecuteCmd(string arguments)
{
// Create the Process Info object with the overloaded constructor
// This takes in two parameters, the program to start and the
// command line arguments.
// The arguments parm is prefixed with "#" to eliminate the need
// to escape special characters (i.e. backslashes) in the
// arguments string and has "/C" prior to the command to tell
// the process to execute the command quickly without feedback.
ProcessStartInfo _info =
new ProcessStartInfo("cmd", #"/C " + arguments);
// The following commands are needed to redirect the
// standard output. This means that it will be redirected
// to the Process.StandardOutput StreamReader.
_info.RedirectStandardOutput = true;
// Set UseShellExecute to false. This tells the process to run
// as a child of the invoking program, instead of on its own.
// This allows us to intercept and redirect the standard output.
_info.UseShellExecute = false;
// Set CreateNoWindow to true, to supress the creation of
// a new window
_info.CreateNoWindow = true;
// Create a process, assign its ProcessStartInfo and start it
Process _p = new Process();
_p.StartInfo = _info;
_p.Start();
// Capture the results in a string
string _processResults = _p.StandardOutput.ReadToEnd();
// Close the process to release system resources
_p.Close();
// Return the output stream to the caller
return _processResults;
}

The first parameter is the file executed, "cmd" is a shortcut for "C:\Windows\System32\cmd".
The second parameter are the arguments to give to the program. Here, you can't just write "ipconfig". You have to use /r or /c or /k to give the arguments to cmd:
/c or /r : Carries out the command specified by string and then stops.
/k : Carries out the command specified by string and continues.
Process.Start("cmd", "/r ipconfig");

Note that in the statement
ProcessStartInfo("cmd", #"/C " + arguments);
Contrary to the comment in the code, the # sign only affects the string "/C " and does not the affect the contents of the string arguments. In this case it doesn't hurt anything, but doesn't do anything either.
Contrary to the comment in the code, any \s in arguments would indeed need to be escaped.

Related

c# start a exe until it is completely started and then append the arguments

I was trying to start a exe with arguments by Process.Start.
My first try is using Process.Start("Path/of/the/exe", "arguments of exe").
Here's my code snippets:
Process.Start(#"D:\Program Files\ITASCA\UDEC700\Exe64\udecConsole2017.exe", #"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'");
However the initialization of this exe is a bit slow, and the result is, I can only start the exe but the failed passing arguments. The following is the screenshot:
which is exactly the same result that starts without arguments.
By referencing this post C# - Making a Process.Start wait until the process has start-up, I changed my code as follows:
var process = Process.Start(#"D:\Program Files\ITASCA\UDEC700\Exe64\udecConsole2017.exe", #"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'");
while (string.IsNullOrEmpty(process.MainWindowTitle))
{
System.Threading.Thread.Sleep(100);
process.Refresh();
}
however these changes does not work.
I think my goal is to wait until exe completely started and then run it with arguments, but I dont know how to implement this.
=====================================================
New additions:
if I type in arguments call 'D:\Work\202205\20220525\tunnel-for-cmd.txt' in this started process, I will get my result:
SO I think the input arguments should be OK?
=======================================
new addition 2:
code for checking outputstream end
It appears this is a console application and you are typing in the console after it starts. This typing is not arguments: Arguments are provided only when starting a new process and never change.
What you are doing is providing something to the standard input of the program. Console programs have three streams the OS provides (one input and two output). You need to redirect these to detect when the program has started and to provide the proper input.
Something like this:
// Start with stdio redirected
var psi = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = #"your exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
};
var p = System.Diagnostics.Process.Start(psi);
// Read until the udec> prompt
while(true)
{
var line = p.StandardOutput.ReadLine();
if(line.StartsWith("udec>"))
break;
}
// Write the command
p.StandardInput.WriteLine(#"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'");
// Read the result
p.StandardOutput.ReadToEnd();

How to use CSSLint?

I found some command line arguments to run generate the CSSLint report in xml format. It is working fine while running through command prompt.
Arguments:
csslint --format=csslint-xml "{SourceDir}\bootstrap.css" > "C:\temp\csslint.xml"
I want to execute it through C# application. I tried the below code.
Process process = new Process()
{
StartInfo =
{
FileName = "cmd.exe",
Arguments = "csslint --format=csslint-xml " + #"""{SourceDir}\bootstrap.css""" + #" > ""C:\Temp\CssLint.xml""",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
}
};
process.Start();
process.WaitForExit();
But it is not working. Can i have a solution or idea for this issue?
Also is there any way to generate the CSSLint report for the specified directory? I want to give the directory path instead of file name.
You need to add /Kor /C to cmd to execute a process passed as a parameter, thus:
Arguments = "/C csslint --format=csslint-xml " + #"""{SourceDir}\bootstrap.css""" + #" > ""C:\Temp\CssLint.xml""",
From the documentation:
Options
/C Run Command and then terminate
/K Run Command and then return to the CMD prompt.
This is useful for testing, to examine variables
One caveat... the piping (the > "C:\temp\csslint.xml" part of your command line) is not an argument, it's a redirection.
If you are redirecting your stdout (the RedirectStandardOutput = true) from your app, you can capture it directly from C#, no need to pipe it to a file like you are trying to do: you'd need to handle the Process.OutputDataReceived event between your Start and WaitForExit calls, or read from the Process.StandardOutput stream).
As for your second question, the csslint CLI allows passing in a directory instead of a file

Writing and executing multiple lines sequentially in an elevated command prompt using c#

Am a Newbie in C# and I have 3 commands(command2, command3 and command4) I need to execute in the elevated command prompt and I will also like to view the execution process as it happens. Currently, the problem is that the code below just opens the elevated command prompt and without executing the commands. I also seek better interpretations of the lines if wrong.
My code and Interpretation/Understanding of each line based on reviews of similar cases: ConsoleApp1
class Program
{
static void Main(string[] args)
{
string command2 = #"netsh wlan";
string command3 = #" set hostednetwork mode=true ssid=egghead key=beanhead keyusage=persistent";
string command4 = #" start hostednetwork";
string maincomm = command2.Replace(#"\", #"\\") + " " + command3.Replace(#"\", #"\\") ; //I merged commands 2 and 3
ProcessStartInfo newstartInfo = new ProcessStartInfo();
newstartInfo.FileName = "cmd"; //Intend to open cmd. without this the newProcess hits an error saying - Cannot run process without a filename.
newstartInfo.Verb = "runas"; //Opens cmd in elevated mode
newstartInfo.Arguments = maincomm; //I intend to pass in the merged commands.
newstartInfo.UseShellExecute = true; //
newstartInfo.CreateNoWindow = true; // I intend to see the cmd window
Process newProcess = new Process(); //
newProcess.StartInfo = newstartInfo; //Assigns my newstartInfo to the process object that will execute
newProcess.Start(); // Begin process and Execute newstartInfo
newProcess.StartInfo.Arguments = command4; //I intend to overwrite the initial command argument hereby passing the another command to execute.
newProcess.WaitForExit(); //
}
}
This is what I did to overcome the challenge and It gave me exactly what I wanted. I modified my code to use the System.IO to write directly to the elevated command prompt.
ProcessStartInfo newstartInfo = new ProcessStartInfo();
newstartInfo.FileName = "cmd";
newstartInfo.Verb = "runas";
newstartInfo.RedirectStandardInput = true;
newstartInfo.UseShellExecute = false; //The Process object must have the UseShellExecute property set to false in order to redirect IO streams.
Process newProcess = new Process();
newProcess.StartInfo = newstartInfo;
newProcess.Start();
StreamWriter write = newProcess.StandardInput ; //Using the Streamwriter to write to the elevated command prompt.
write.WriteLine(maincomm); //First command executes in elevated command prompt
write.WriteLine(command4); //Second command executes and Everything works fine
newProcess.WaitForExit();
Referrence: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardinput(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx
I think an understanding of some properties of the ProcessStartInfo might clear things.
The verb - Gets or sets the verb to use when opening the application or document specified by the FileName property.,
+The UseShellExecute - Gets or sets a value indicating whether to use the operating system shell to start the process.
+The FileName - Gets or sets the application or document to start MSDN Docs
When you use the operating system shell to start processes, you can start any document (which is any registered file type associated with an executable that has a default open action) and perform operations on the file, such as printing, by using the Process object. When UseShellExecute is false, you can start only executables by using the Process object Documentation from MSDN.
In my case, cmd is an executable. the verb property is some thing that answers the question "How should my I run my FileName(for executables e.g cmd or any application)?" for which I answered - "runas" i.e run as administrator. When the FileName is a document (e.g `someFile.txt), the verb answers the question "What should I do with the file for which answer(verb) could be -"Edit","print" etc. also?"
use true if the shell should be used when starting the process; false if the process should be created directly from the executable file. The default is true MSDN Docs - UserShellInfo.
Another thing worth noting is knowing what you are trying to achieve. In my case, I want to be able to run commands via an executable(cmd prompt) with the same process - i.e starting the cmd as a process I can keep track of.

Stop Command Prompt from closing so quickly

I'm trying to troubleshoot why the following function isn't working.
public void RunCmd()
{
string strCmdText;
strCmdText = "/C [enter command stuff here]";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
}
However whenever I try to run it or throw in some breakpoints, command opens, shows an error, and then closes really quickly (so quickly that I can't read anything).
Is there a way I can halt the program or figure out what's going on? Breakpoints don't seem to be working.
When I directly type it in Command Prompt instead of running it via this c# script, it the command works fine.
try this:
strCmdText = "/K [enter command stuff here]";
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
Maybe try adding a pause command?
There are a various options. Using /K will prevent the window from closing.
You can also edit your command to add a SLEEP after the main call. For example, the following will wait 2 seconds before exiting:
public void RunCmd()
{
string strCmdText = "/C \"[enter command stuff here]\" & \"SLEEP 2\"";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
}
Process.Start has two parameters there: the process name and the arguments to pass to the process. CMD is having a problem understanding what the argument "[enter" is. If it is not an argument CMD understands, it will immediately exit.
cin.get()
That waits for a keyboard press from the user.
create temp folder under c: then append " < c:\temp\log.txt" to the end of command. this writes the output to a file
In addition to the tip about using /K vs /C to create a shell that 'lingers', you'll probably want to inject an empty "set" command to see what environmental variables (and paths) are set in the spawned shell. In all likelihood, the difference between the successful run of your script in your own shell session and the one that fails in the spawned shell, is the environment settings in which it is run.

How to send series of commands to a command window process?

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)
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
Process.Start method
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.
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

Categories