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
Related
I need to execute the following command, it works perfectly, if I execute it via command prompt, here the command line is using kodakprv.exe to send a print of a tiff file.
but when trying to execute it via c#, its not throwing any error but not sending the print either, tried to execute this command via xp_cmdshell in SQL, but it didn't work, in the xp_cmdshell documentation found that, quotes are not allowed for more then once, but kodakprv.exe print logic requires 3 pair of quotes
Please suggest can we use multiple quotes in C# while executing the command or suggest any better solution for it
String sCommand = "\"c:\\progra~1\\imagin~1\\kodakprv.Exe\" /pt \"D:\\SQLDev\\Dlls\\Testing.TIF\" \"\\\\Galactica\\C-Test1\"";
// Put your code here
System.Diagnostics.Process ExecuteCommand = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = #" /c " + sCommand.ToString();
MessageBox.Show(startInfo.Arguments);
ExecuteCommand.StartInfo = startInfo;
ExecuteCommand.Start();
You don't need all those quotes. Only paths with spaces require quotes. None of your paths have spaces.
Shortnames, as you are using, may not exist (they can be turned off), or may not have the name you think. Windows does not preserve short names, only long names.
You are running your program via CMD. Unless your command line has redirection characters (as CMD handles redirection characters) then CMD is not required. You can start your program directly, which would be the preferred way (faster, less resources used).
Your window is set to hidden. Therefore you cannot see the message it is telling you. Unhide your window.
Your program will likely exit and close the window before you can read it. Either stick a &pause at the end of the command line sent to CMD, or read what is on both StdErr and StdOut as you specify to capture them in your code.
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.
I have a Java .jar application that is ran from a .bat file to have arguments passed to the Java application. The application opens a console (cmd.exe to be exact), writes things to it regularly and accepts some commands. I'm trying to create a kind-of wrapper around it in C# Winforms to ease it's use. How can I run the .jar with the same arguments as are in the .bat file, capture realtime output and write execute commands?
Yes, it is possible to do this using the System.Diagnostics.Process class and the ProcessStartInfo class from the .NET Framework. The Process class is used to control (start / stop) the desired process (application) and the ProcessStartInfo class is used to configure the process instance that will be started (arguments, redirect input and output, show / hide process window, and so on).
The code for starting a jar file looks like this:
var jarFile = "D:\\software\\java2html\\java2html.jar");
// location of the java.exe binary used to start the jar file
var javaExecutable = "c:\\Program Files (x86)\\Java\\jre7\\bin\\java.exe";
try
{
// command line for java.exe in order to start a jar file: java -jar jar_file
var arguments = String.Format(" -jar {0}", jarFile);
// create a process instance
var process = new Process();
// and instruct it to start java with the given parameters
var processStartInfo = new ProcessStartInfo(javaExecutable, arguments);
process.StartInfo = processStartInfo;
// start the process
process.Start();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
The usual way to start a jar file is:
java -jar file.jar
To be sure, that the process will find the (in this case java) executable, it is a good practice to specify the fully qualified path to the process you want to start.
In order to redirect the standard output of the application you are starting, you need to set the ProcessStartInfo.RedirectStandardOutput property to true and then use the Process.StandardOutput property stream to fetch the output of the started application. The modified code for the application from the example above looks like this:
// command line for java.exe in order to start a jar file: java -jar jar_file
var arguments = String.Format(" -jar {0}", jarFile);
// indicate, that you want to capture the application output
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
// create a process instance
var process = new Process();
// and instruct it to start java with the given parameters
var processStartInfo = new ProcessStartInfo(javaExecutable, arguments);
process.StartInfo = processStartInfo;
// start the process
process.Start();
// read the output from the started appplication
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
If you want to control the input too, set the ProcessStartInfo.RedirectStandarInput property to true and then use the Process.StandardInput property stream to send input data to the started application.
I am currently faced with a problem, I need to execute a batch script within a programs memory (so it does not have to extract the batch file to a temporary location).
I am open to solutions in C# and C++
Any help would be appreciated
cmd.exe won't run a script from the memory of your process. The options which seem most obvious to me are:
Relax the constraint that stops you extracting the script to a temporary file.
Compress your script into a single line and use cmd.exe /C to execute it. You'll need to use the command separator &&.
Write your own batch command interpreter.
Use a different scripting language.
Options 3 and 4 aren't really very attractive! Option 1 looks pretty good to me but I don't know what's leading to your constraint.
Open a pipe to the command shell and write the program code into that pipe. Here is an example: http://support.microsoft.com/default.aspx?scid=kb;en-us;190351
In C# it's an easy way to use System.Diagnostics for the job.
How!?
Basically, every batch command is an .exe file so you can start it in a separate process.
Some code:
using System.Diagnostics;
static void Main()
{
Process batch;
batch = Process.Start("ping.exe", "localhost");
batch.WaitForExit();
batch.Close();
batch = Process.Start("choice.exe", "");
batch.WaitForExit();
batch.Close();
batch = Process.Start("ping.exe", "localhost -n 10");
batch.WaitForExit();
batch.Close();
}
If you don't want to start every command in a separate process the solution is with a simple stream redirection.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"cmd.exe"; // Specify exe name.
startInfo.UseShellExecute = false;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardInput = true;
//
// Start the process.
//
Process process = Process.Start(startInfo);
string[] batchFile = {"ping localhost", "ping google.com -n 10", "exit"};
int cmdIndex = 0;
while (!process.HasExited)
{
if (process.Threads.Count == 1 && cmdIndex < batchFile.Length)
{
process.StandardInput.WriteLine(batchFile[cmdIndex++]);
}
}
What's a good way to write batch scripts in C#?
I am trying to run a process in c# using the Process class.
Process p1 = new process();
p1.startinfo.filename = "xyz.exe";
p1.startinfo.arguments = //i am building it based on user's input.
p1.start();
So based on user input i am building the argument value. Now i have a case where i have to pipe the output of p1 to another process say grep. so i basically tried this
p1.startinfo.arguments = "-info |grep 1234" ;
what i intended is something like xyz.exe -info|grep 1234
but this doesn't seem to work in .net .. I can actually create another process variable and run "grep" as a separate process.. But i was wondering if there is any way to do as iam trying out above..
The much easier way would be to do just use cmd as your process.
Process test = new Process();
test.StartInfo.FileName = "cmd";
test.StartInfo.Arguments = #"/C ""echo testing | grep test""";
test.Start();
You can capture the output or whatever else you want like any normal process then. This was just a quick test I built, but it works outputting testing to the console so I would expect this would work for anything else you plan on doing with the piping. If you want the command to stay open then use /K instead of /C and the window will not close once the process finishes.