How to run multiple cmd commands from c# console app - c#

I'm looking to automate nupkg creation in a c# app. I'm aiming to include nuget.exe in my project and use System.Diagnostics to launch cmd.exe as a process and then pass the required commands, which would be 'cd project\path\here', 'nuget spec something.dll' and 'nuget pack something.nuspec'.
The code I have so far is:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\System32\cmd.exe", #"mkdir testdir");
p.StartInfo = info;
p.Start();
Console.ReadLine();
However, it doesn't even create the testdir, and I've got no idea how to chain those commands. There is a method called WaitForInputIdle on my p Process, but it raises events and I've got no idea how to handle those to be honest.
A perfect solution would also let me read output and input. I've tried using StreamWriter p.StandardInput, but then there's the problem of checking whether a command is finnished and what was the result.
Any help would be much appreciated.
Edit: Success! I've managed to create a directory :)
Here's my code now:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\System32\cmd.exe");
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
sw.WriteLine("mkdir lulz");
}
Still no idea how to await for input and follow up with more commands, though.

You can do this by three ways
1- The easiest option is to combine the two commands with the '&' symbol.
var processInfo = new ProcessStartInfo("cmd.exe", #"command1 & command2");
2- Set the working directory of the process through ProcessStartInfo.
var processInfo = new ProcessStartInfo("cmd.exe", #"your commands here ");
processInfo.UseShellExecute = false;
processInfo.WorkingDirectory = path;
3- Redirecting the input and output of the process. (Also done through the ProcessStartInfo).This is required when you like to send more input to the process, or when you want to get the output of the process
Also see this answer

Related

Multiple process commands fail to get back any response

Having a challenge being able to send commands to cmd.exe from via the C# Process class.
Basically I want to call R.exe and then send it several commands to stage the data before I run some R functions and then pull out the result.
But I can't get the result back from a simple 'dir' statemenet :(
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
string pathToR = #"C:\Program Files\R\R-3.3.1\bin";
p.StartInfo = info;
p.Start();
List<string> output = new List<string>();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("cd " + pathToR);
sw.WriteLine("dir");
while (p.StandardOutput.Peek() > -1)
{
var peekVal = p.StandardOutput.Peek();
output.Add(p.StandardOutput.ReadLine());
}
}
}
foreach (var line in output)
{
Console.WriteLine(line);
}
p.StandardInput.Close();
p.StandardOutput.Close();
p.WaitForExit();
p.Close();
Console.ReadLine();
Output:
Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.
c:\users\micah_000\documents\visual studio 2015\Projects\RStagingTestApp\RStagingTestApp\bin\Debug>cd C:\Program Files\R\R-3.3.1\bin
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
I've seen several variations on this result, but I've never seen any kind of response from my commands :(
A lot of places say the async reads work best. I've seen some persuasive, comprehensive explanations for this, but I haven't been able to get it to work for me.
This one seemed to work. It might have been setting AutoFlush to true. Or just reading once at the end.

How to pass arguments to an already open terminal via System.Diagnostics.Process()

I have been messing around with triggering a bash script via C#. This all works fine when I first call the "open" command with arguments which in turn opens my .command script via Terminal.
Once the "open" command is used once Terminal or iTerm will remain open in the background, at which point calling the "open" command with arguments then has no further effect. I sadly have to manually quit the application to trigger my script again.
How can I pass arguments to an already open terminal application to restart my script without quitting?
I've searched online ad can't seem to work it out, it already took a good amount of time solve the opening code. Your help is much appreciated.
Here is the C# code I'm using to start the process:
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "open";
p.StartInfo.WorkingDirectory = installFolder;
p.StartInfo.Arguments = "/bin/bash --args \"open \"SomePath/Commands/myscript.command\"\"";
p.Start();
Thanks
EDIT:
Both answers were correct, this might help others:
ProcessStartInfo startInfo = new ProcessStartInfo("/bin/bash");
startInfo.WorkingDirectory = installFolder;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("echo helloworld");
process.StandardInput.WriteLine("exit"); // if no exit then WaitForExit will lockup your program
process.StandardInput.Flush();
string line = process.StandardOutput.ReadLine();
while (line != null)
{
Debug.Log("line:" + line);
line = process.StandardOutput.ReadLine();
}
process.WaitForExit();
//process.Kill(); // already killed my console told me with an error
You can try:
before calling p.Start():
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
// for the process to take commands from you, not from the keyboard
and after:
if (p != null)
{
p.StandardInput.WriteLine("echo helloworld");
p.StandardInput.WriteLine("executable.exe arg1 arg2");
}
(taken from here)
This is what you may be looking for :
Gets a stream used to write the input of the application.
MSDN | Process.StandardInput Property
// This could do the trick
process.StandardInput.WriteLine("..");

Robocopy Success/Failure reported via Window's application

thanks in advance for your time.
I'm working on an application to automate some of the things that I have to check each day.
One of them is making sure that all of our daily Robocopies took place successfully.
I'm having issues figuring out the best way to communicate this to my program. I've looked into the various Exit codes that Robocopy uses which would be very useful, but is there anyway to output this to a file, and would there be anyway to know which backup it was associated with?
Sorry if this is vague, please let me know of any other info that could be of use.
Thanks,
Will
If you start the robocopy process from your application you could check the exit code from there.
Process myProcess = null;
// Start the process.
myProcess = Process.Start("robocopy ....");
myProcess.WaitForExit(1000);
Console.WriteLine("Process exit code: {0}", myProcess.ExitCode);
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.exitcode(v=vs.110).aspx
You could write the Robocopy output to a file and read that in, like
robocopy c:\Test\ c:\temp /LOG+:myLogFile
Then experiment with the log options to get a useful verbosity ( see http://ss64.com/nt/robocopy.html )
You could do something like this:
public static void Main()
{
// Prepare the process.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "robocopy.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "WHATEVER YOU NEED"
// Start process and wait for it to end
Process exeProcess = Process.Start(startInfo)
exeProcess.WaitForExit();
// Display what the exit code was
Console.WriteLine();
Console.WriteLine("Process exit code: {0}", exeProcess.ExitCode);
}
Create a Robocopy-process like this:
string command = $"Robocopy {sourcePath} {targetPath} /MIR /w:1 /r:10";
var copyTask = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "CMD.exe"
Arguments = $"/c {command}",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
Use it like this:
copyTask.Start()
string Output = copyTask.StandardOutput.ReadToEnd();
copyTask.WaitForExit();
Now you have the whole log in the "string output". This is useful if you want to find out WHAT went wrong.

Running Phantomjs using C# to grab snapshot of webpage

I'm trying to grab snapshots of my own website using phantomjs - basically, this is to create a "preview image" of user-submitted content.
I've installed phantomjs on the server and have confirmed that running it from the command line against the appropriate pages works fine. However, when I try running it from the website, it does not appear to do anything. I have confirmed that the code is being called, that phantom is actually running (I've monitored the processes, and can see it appear in the process list when I call it) - however, no image is being generated.
I'm not sure where I should be looking to figure out why it won't create the images - any suggestions? The relevant code block is below:
string arguments = "/c rasterize.js http://www.mysite.com/viewcontent.aspx?id=123";
string imagefilename = #"C:\inetpub\vhosts\mysite.com\httpdocs\Uploads\img123.png";
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = false;
p.StartInfo.FileName = #"C:\phantomjs.exe";
p.StartInfo.Arguments = arguments + " " + imagefilename;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
I check the errors that phantomjs throws during its process.
You can read them from Process.StandardError.
var startInfo = new ProcessStartInfo();
//some other parameters here
...
startInfo.RedirectStandardError = true;
var p = new Process();
p.StartInfo = startInfo;
p.Start();
p.WaitForExit(timeToExit);
//Read the Error:
string error = p.StandardError.ReadToEnd();
It will give you an idea of what happened
The easiest way for executing phantomjs from C# code is using wrapper like NReco.PhantomJS. The following example illustrates how to use it for rasterize.js:
var phantomJS = new PhantomJS();
phantomJS.Run( "rasterize.js", new[] { "https://www.google.com", outFile} );
Wrapper API has events for stdout and stderr; also it can provide input from C# Stream and read stdout result into C# stream.

how to send command and receive data in command prompt in C# GUI application

I am new to C# so please sorry if i make no sense in my question. In my application which is C# DLL need to open command prompt, give a plink command for Linux system to get a system related string and set that string as environment variable. I am able to do this when i create C# console application, using plink command to get the string on command prompt and use to set it environment variable using process class in C# to open plink as separate console process. But, in C# DLL i have to open cmd.exe 1st and then give this command which i don't know how can i achieve? I tried through opening cmd.exe as process and then trying to redirect input and output to process and give command and get string reply, but no luck. Please let me know any other way to solve this.
Thanks for answers,
Ashutosh
Thanks for your quick replys. It was my mistake in writing code sequence. Now few changes and the code is working like charm. Here is code,
string strOutput;
//Starting Information for process like its path, use system shell i.e. control process by system etc.
ProcessStartInfo psi = new ProcessStartInfo(#"C:\WINDOWS\system32\cmd.exe");
// its states that system shell will not be used to control the process instead program will handle the process
psi.UseShellExecute = false;
psi.ErrorDialog = false;
// Do not show command prompt window separately
psi.CreateNoWindow = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
//redirect all standard inout to program
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
//create the process with above infor and start it
Process plinkProcess = new Process();
plinkProcess.StartInfo = psi;
plinkProcess.Start();
//link the streams to standard inout of process
StreamWriter inputWriter = plinkProcess.StandardInput;
StreamReader outputReader = plinkProcess.StandardOutput;
StreamReader errorReader = plinkProcess.StandardError;
//send command to cmd prompt and wait for command to execute with thread sleep
inputWriter.WriteLine("C:\\PLINK -ssh root#susehost -pw opensuselinux echo $SHELL\r\n");
Thread.Sleep(2000);
// flush the input stream before sending exit command to end process for any unwanted characters
inputWriter.Flush();
inputWriter.WriteLine("exit\r\n");
// read till end the stream into string
strOutput = outputReader.ReadToEnd();
//remove the part of string which is not needed
int val = strOutput.IndexOf("-type\r\n");
strOutput = strOutput.Substring(val + 7);
val = strOutput.IndexOf("\r\n");
strOutput = strOutput.Substring(0, val);
MessageBox.Show(strOutput);
I explained the code so far..., thanks a lot

Categories