Execute commands from command prompt in c# web application - c#

I have a C# web application in which I want to execute Unix commands one by one. I want the command prompt window to appear and then after each command execution , move to the next command and then exit the window. I have tried the below, but the command prompt window does not appear and the commands are not getting executed after each wait
public void connecterOne()
{
try
{
using (Process p = new Process())
{
// set start info
p.StartInfo = new ProcessStartInfo("cmd.exe")
{
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WorkingDirectory = #"c:\"
};
// event handlers for output & error
p.OutputDataReceived += p_OutputDataReceived;
p.ErrorDataReceived += p_ErrorDataReceived;
// start process
p.Start();
// send command to its input
p.StandardInput.Write("ftp server" + p.StandardInput.NewLine);
p.StandardInput.Write("username" + p.StandardInput.NewLine);
p.StandardInput.Write("pwd" + p.StandardInput.NewLine);
string output = p.StandardOutput.ReadToEnd();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Process p = sender as Process;
if (p == null)
return;
Console.WriteLine(e.Data);
}
static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Process p = sender as Process;
if (p == null)
return;
Console.WriteLine(e.Data);
}
How to execute commands one by one and have the command prompt window open which shows the commands being executed. I am not getting any errors, but there is no output seen.

This is a security issue A web application has no access to user pc command prompt ,
A web application deployed on IIS on web server not on user pc.
If you run a process it will execute on that server but you need to allow server to execute these commands.But I think it is bad practice.

To execute a command on a remote Linux based machine, you need to connect first with ssh. For C#, you can use the SSH.NET
Also, this article might help you.

Related

cant get process error output using process.ErrorDataReceived c#

I've built Form App that I use for some time , Now I want to Catch the StandardError of my process as well as its standartOutput
I've looked at answers in SO and MSDN and yet and cant get it right
My code :
public void RunProcess(string FileName, string Arguments,, bool IsPrintOutput = true)
{
process = new Process();
process.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
if (IsPrintOutput) process.OutputDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = FileName;
process.StartInfo.Arguments = Arguments;
if (EventWhenExit)
{
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(myprocess_Exited);
}
process.Start();
process.BeginOutputReadLine();
//run polling on stored logs to print them to screen
PollingService();
}
I've check it with Iperf and I see that when I run it with correct argument I get correct output
but when I just send it with out any argumnet I see that with cmd I get
C:\>iperf.exe
Usage: iperf [-s|-c host] [options]
Try `iperf --help' for more information.
And my App I get Nothing !
what am I missing here ?
Thanks
You can stop reading here ! If you want to see the details of inner method continue below :
private void OnDataReceivedEvent(object sender, DataReceivedEventArgs e)
{
string ProcessOutput = e.Data;
ProcessLog.Add(e.Data);
}
private void PollingService()
{
var T = new Thread (()=>
{
while (true /* ProcessRunning*/)
{
if (ProcessLogIndex < ProcessLog.Count)
{
lock (this)
{
var tempList = ProcessLog.GetRange(ProcessLogIndex, ProcessLog.Count - ProcessLogIndex);
ProcessLogIndex = ProcessLog.Count;
foreach (var ToSend in tempList)
{
onDataOutputFromProcess(this, ToSend, sProcessNameID.ToString());
}
}
}
Thread.Sleep(400);
}
});
T.IsBackground = true;
T.Start();
}
I don't see a call to BeginErrorReadLine() anywhere in the code you posted. If you don't call that method, then the Process class won't actually redirect the stderr to your event handler.
I believe the above is the issue, but if you are actually calling that somewhere (and just didn't show it), then it is worth considering that there are some strange console programs out there that don't actually used stderr (or stdout) for error output. Instead, they write directly to the console window or some other non-standard mechanism. In those cases, you won't be able to receive the error output by redirecting stderr.
You can identify those programs by redirecting their output at the command like with e.g. iperf.exe 2> foo.txt. The stderr file handle is 2, and so that syntax redirects that file handle to a file named foo.txt. If the file is empty and you see errors on the screen, then the program is one of those strange programs.
But really, I think you probably just forgot to call BeginErrorReadLine(). :)

C# process start firefox.exe fires the exited immediately after launch

Similar to
Process.Start("IEXPLORE.EXE") immediately fires the Exited event after launch.. why?
The -nomerge option does not seem to work for firefox.
Updated:
Here's a preview of the C# code inside a console app
static bool exitCalled = false;
static string baseUrl = <some url to display in the browser>;
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Firefox.exe"
Arguments = " -url " + baseUrl + " -no-remote -P MyProfile "
}
}
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(delegate(Object o, EventArgs e)
{
// process has exited
Console.WriteLine("Exited event called");
Console.ReadLine();
exitCalled = true;
}
process.Start();
while (!exitCalled)
{
Thread.Sleep(100);
}
Running this piece of code displays the "Exited event called" message before the browser is invoked.
That because -nomerge is an IE specific program argument, for firefox you need to use -no-remote. You will also need to pass it the -P program argument as well since it is not recommend to start another firefox process with the default profile. Refer to the following link on starting a new FireFox instance:
http://kb.mozillazine.org/Opening_a_new_instance_of_Firefox_with_another_profile

NET VIEW behaves differently when used with Process.Start()

I use net.exe in my program to view all computers in a workgroup.
The code is as follows:
var net = new Process();
net.StartInfo.FileName = "net.exe";
net.StartInfo.CreateNoWindow = true;
net.StartInfo.Arguments = #"VIEW /DOMAIN:my-workgroup";
net.StartInfo.RedirectStandardOutput = true;
net.StartInfo.UseShellExecute = false;
net.StartInfo.RedirectStandardError = true;
net.Start();
The command works fine when I execute in a shell, but when I use the shown code, the command returns the device is not connected.
I also tried running the program as administrator, that makes no difference.
The domain name specified is actually a workgroup.
For net.exe running in the shell specifying a workgroup works fine.
Furthermore the code also works when I try a net view for a different domain. So there must be some difference in the environment when I run the command from the shell or with Process.Start().
What would be the reasons for the command to behave differently in the shell and with Process.Start()?
I don't know if it will solve what you're looking for, but this works for me;
You need to hook into the capture the output to bring it to the console
class Program
{
static void Main(string[] args)
{
var net = new Process()
{
StartInfo = new ProcessStartInfo("net.exe", #"view /domain:domain")
{
RedirectStandardOutput = true,
UseShellExecute = false,
},
};
net.OutputDataReceived += WriteToConsole;
net.ErrorDataReceived += WriteToConsole;
net.Start();
net.BeginOutputReadLine();
net.WaitForExit();
Console.ReadLine();
}
private static void WriteToConsole(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
}

Sending commands to cmd prompt in C#

For one of my implementations I am working on a tool that is supposed to send/retrieve commands/results to/from the cmd window. Everything works fine but the Use case below fails to do anything. It seems as if my application is waiting for something (instead of displaying the result)
From my tool I navigate to the python folder . From the python folder I try to launch python.exe but at this point, my editor does not do anything. it simply keeps on waiting.
For your kind consideration I am also linking the video here. It would be easier for you guys to understand what I am trying to say.
View the Video here (on youtube)
I am also attaching the code that I currently have.
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
string argument = null;
if (!string.IsNullOrEmpty(startingDirectory) && System.IO.Directory.Exists(startingDirectory))
{
argument += #"cd\";
}
else
{
argument += "\"";
}
info.Arguments = argument;
info.CreateNoWindow = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
this.shellProcess = System.Diagnostics.Process.Start(info);
this.shellProcess.EnableRaisingEvents = true;
//this.InputStream.AutoFlush = true;
this.shellProcess.Exited += new EventHandler(ProcessExited);
this.ErrorBeginRead();
this.OutputBeginRead();
private void OutputBeginRead()
{
this.shellProcess.StandardOutput.BaseStream.BeginRead(outputBuffer, 0, outputBuffer.Length, new AsyncCallback(this.OnOutputInput), this.shellProcess);
}
private void ErrorBeginRead()
{
this.shellProcess.StandardError.BaseStream.BeginRead(errorBuffer, 0, errorBuffer.Length, new AsyncCallback(this.OnErrorInput), this.shellProcess);
}
Thank you !
EDIT:
Launching python is just an example. I need to use the same method for other normal cmd line commands as well.It would be nice, if somebody can point what i am doing wrong with the code that I have or what I must do , in order to achieve the intended functionality.
EDIT 2 : The normal cmd commands are working perfectly. The command line tools like python,perl are not working .
Edit 3 : So I managed to do move a wee bit forward following Jamie's suggestions. The ui is not "hanging" anymore. but when i access the python interpreter , the interpreter's output is still not visible in my tool. Any suggestions why that might be happening ?
You cannot send commands to a shell this way. The string in info.Arguments is the arguments provided to the program on the command line. If you want the cmd.exe shell to execute a series of command and then quit you will have to provide the /c argument. If you have multiple commands that you want it to perform you will either have to put the commands in a batch file and execute that or enclose them in quotes and separate them with &&, i.e. info.Arguments = #"/c ""cd \ && dir""";. Your other issue with never returning is that cmd.exe opens in interactive mode by default when it is executed without any, or proper, arguments. The /c option tells cmd.exe to execute the relevant commands and then quit.
Additionally, interpreters like python and perl sometimes have weird behaviors when launched directly from ProcessStartInfo. If info.Arguments = #"""MyPerlProgram.pl"""; with perl.exe doesn't work, you may find it necessary to launch them inside cmd.exe to get normal behavior out of them, i.e. info.Arguments = #"/c ""perl.exe ""MyPerlProgram.pl""""";.
See Cmd and ProcessStartInfo.Arguments Property.
To answer your Edit 3 problem, you're probably not correctly hooking into the outputs. Instead of trying to hook the StreamReader's BaseStream, hook the OutputDataReceived event with this.shellProcess.OutputDataReceived += ProcessOutputHandler; before you call Start where ProcessOutputHandler has a signature like public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine). Immediately after calling Start, call this.shellProcess.BeginOutputReadLine();. The process is similar for the error ouput as well. See Process.BeginOutputReadLine Method and Process.BeginErrorReadLine Method for more details.
If you still have a problem, what do you get if you just try process.StartInfo.Arguments = #"/c ""python.exe -c ""import sys; print 'Test.';""""";?
Also, the code below demonstrates most of the necessary concepts for shell communication:
public static void Main()
{
using (Process process = new Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = #"C:\";
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
// Redirects the standard input so that commands can be sent to the shell.
process.StartInfo.RedirectStandardInput = true;
// Runs the specified command and exits the shell immediately.
//process.StartInfo.Arguments = #"/c ""dir""";
process.OutputDataReceived += ProcessOutputDataHandler;
process.ErrorDataReceived += ProcessErrorDataHandler;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
// Send a directory command and an exit command to the shell
process.StandardInput.WriteLine("dir");
process.StandardInput.WriteLine("exit");
process.WaitForExit();
}
}
public static void ProcessOutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine.Data);
}
public static void ProcessErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine.Data);
}
You may have threading issues causing your problems. I've done some further work with this and was able to get a textbox on a form to update with the following code:
using System;
using System.Diagnostics;
using System.IO;
using System.Timers;
namespace DummyFormsApplication
{
class ProcessLauncher : IDisposable
{
private Form1 form;
private Process process;
private bool running;
public bool InteractiveMode
{
get;
private set;
}
public ProcessLauncher(Form1 form)
{
this.form = form;
process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = #"C:\";
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
// Redirects the standard input so that commands can be sent to the shell.
process.StartInfo.RedirectStandardInput = true;
process.OutputDataReceived +=new DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
process.Exited += new EventHandler(process_Exited);
}
public void Start()
{
if (running == false)
{
running = true;
InteractiveMode = true;
// Runs the specified command and exits the shell immediately upon completion.
process.StartInfo.Arguments = #"/c ""C:\python27\python.exe -i""";
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
}
public void Start(string scriptFileName)
{
if (running == false)
{
running = true;
InteractiveMode = false;
// Runs the specified command and exits the shell immediately upon completion.
process.StartInfo.Arguments = string.Format(#"/c ""C:\python27\python.exe ""{0}""""", scriptFileName);
}
}
public void Abort()
{
process.Kill();
}
public void SendInput(string input)
{
process.StandardInput.Write(input);
process.StandardInput.Flush();
}
private void process_OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
form.Invoke(form.appendConsoleTextDelegate, new object[] { outLine.Data });
}
}
private void process_ErrorDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
form.Invoke(form.appendConsoleTextDelegate, new object[] { outLine.Data });
}
}
private void process_Exited(object sender, EventArgs e)
{
running = false;
}
public void Dispose()
{
if (process != null)
{
process.Dispose();
}
}
}
}
I created a form and added a textbox and the following code in the form:
public delegate void AppendConsoleText(string text);
public AppendConsoleText appendConsoleTextDelegate;
private void Form1_Load(object sender, EventArgs e)
{
appendConsoleTextDelegate = new AppendConsoleText(textBox1_AppendConsoleText);
using (ProcessLauncher launcher = new ProcessLauncher(this))
{
launcher.Start();
launcher.SendInput("import sys;\n");
launcher.SendInput("print \"Test.\";\n");
launcher.SendInput("exit()\n");
}
}
private void textBox1_AppendConsoleText(string text)
{
textBox1.AppendText(string.Format("{0}\r\n", text));
}
One thing to note is that if the Form1_Load event doesn't complete, Invoke will hang until it does. If you have long-running code in an event you'll either need to invoke asynchronously using BeginInvoke, or periodically call DoEvents in your long-running code.
EDIT
Per your comment, I've modified the code to work with interactive submissions. There is, however, a problem. The python prompt (>>>) is provided on the StandardError output and it does not echo the StandardInput. It also does not terminate the line. This makes detecting a prompt difficult and causes some out of order output of the prompt characters due to the process_ErrorDataReceived not firing until either the process ends or a line end is seen.
There's not enough code in your question to figure out exactly what your application is hanging on. There are some things in your code which look odd. For example, why are you starting your own error and output read loops instead of using the ones built into the Process class? Like this:
var shellProcess = System.Diagnostics.Process.Start(info);
shellProcess.EnableRaisingEvents = true;
shellProcess.Exited += ProcessExited;
shellProcess.OutputDataReceived += ShellProcess_OutputDataReceived;
shellProcess.ErrorDataReceived += ShellProcess_ErrorDataReceived;
shellProcess.BeginOutputReadLine();
shellProcess.BeginErrorReadLine();
void ShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
// Do Something
}
void ShellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
// Do Something
}
Since your error and output async events are not firing, it leads me to believe that there might be a lifetime issue with the shellProcess. If you post more of your code, we can give better guidance.
I can't see all your code, but you can easily use Steam objects to write/send commands to the CMD Window created by you. e.g.:
StreamWriter inputStream = shellProcess.StandardInput;
//send command to cmd prompt and wait for command to execute with thread sleep
inputStream.WriteLine("echo "CMD just received input");
inputStream.Flush();
In the above example for instance, Command prompt will receive the echo command just like it was entered in the window. To show the output you will have to create StreamReader object and assign it to the process's StandardOutput.

Restart an application by itself

I want to build my application with the function to restart itself. I found on codeproject
ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info);
Application.Exit();
This does not work at all...
And the other problem is, how to start it again like this?
Maybe there are also arguments to start applications.
Edit:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=31454&av=58703
I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();
The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.
Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.
Hope this helps!
Why not use
Application.Restart();
??
More on Restart
Why not just the following?
Process.Start(Application.ExecutablePath);
Application.Exit();
If you want to be sure the app does not run twice either use Environment.Exit(-1) which kills the process instantaneously (not really the nice way) or something like starting a second app, which checks for the process of the main app and starts it again as soon as the process is gone.
You have the initial application A, you want to restart.
So, When you want to kill A, a little application B is started, B kill A, then B start A, and kill B.
To start a process:
Process.Start("A.exe");
To kill a process, is something like this
Process[] procs = Process.GetProcessesByName("B");
foreach (Process proc in procs)
proc.Kill();
A lot of people are suggesting to use Application.Restart. In reality, this function rarely performs as expected. I have never had it shut down the application I am calling it from. I have always had to close the application through other methods such as closing the main form.
You have two ways of handling this. You either have an external program that closes the calling process and starts a new one,
or,
you have the start of your new software kill other instances of same application if an argument is passed as restart.
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
if (e.Args.Length > 0)
{
foreach (string arg in e.Args)
{
if (arg == "-restart")
{
// WaitForConnection.exe
foreach (Process p in Process.GetProcesses())
{
// In case we get Access Denied
try
{
if (p.MainModule.FileName.ToLower().EndsWith("yourapp.exe"))
{
p.Kill();
p.WaitForExit();
break;
}
}
catch
{ }
}
}
}
}
}
catch
{
}
}
Winforms has the Application.Restart() method, which does just that. If you're using WPF, you can simply add a reference to System.Windows.Forms and call it.
Another way of doing this which feels a little cleaner than these solutions is to run a batch file which includes a specific delay to wait for the current application to terminate. This has the added benefit of preventing the two application instances from being open at the same time.
Example windows batch file ("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"
In the application, add this code:
// Launch the restart batch file
Process.Start(#"C:\Dev\restart.bat");
// Close the current application (for WPF case)
Application.Current.MainWindow.Close();
// Close the current application (for WinForms case)
Application.Exit();
My solution:
private static bool _exiting;
private static readonly object SynchObj = new object();
public static void ApplicationRestart(params string[] commandLine)
{
lock (SynchObj)
{
if (Assembly.GetEntryAssembly() == null)
{
throw new NotSupportedException("RestartNotSupported");
}
if (_exiting)
{
return;
}
_exiting = true;
if (Environment.OSVersion.Version.Major < 6)
{
return;
}
bool cancelExit = true;
try
{
List<Form> openForms = Application.OpenForms.OfType<Form>().ToList();
for (int i = openForms.Count - 1; i >= 0; i--)
{
Form f = openForms[i];
if (f.InvokeRequired)
{
f.Invoke(new MethodInvoker(() =>
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}));
}
else
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}
if (cancelExit) break;
}
if (cancelExit) return;
Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Application.ExecutablePath,
Arguments = commandLine.Length > 0 ? string.Join(" ", commandLine) : string.Empty
});
Application.Exit();
}
finally
{
_exiting = false;
}
}
}
This worked for me:
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
Some of the other answers have neat things like waiting for a ping to give the initial application time to wind down, but if you just need something simple, this is nice.
For .Net application solution looks like this:
System.Web.HttpRuntime.UnloadAppDomain()
I used this to restart my web application after changing AppSettings in myconfig file.
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
configuration.AppSettings.Settings["SiteMode"].Value = model.SiteMode.ToString();
configuration.Save();

Categories