Executing cmd commands with complex output in c# - c#

I often find myself using different commands on pc's to check stuff in the system and I wanted to basically create a small standalone exe that will execute all my common commands and give me the output of each of them without me entering them manually...
I want to note that I know this isn't the first question on google on the subject of executing a cmd command with c# but non fit my command requirements, for example many of them execute commands such as copy or move or make and non of them have a complex output, I want to execute for example the "sfc /scannow" command, which outputs a progress bar which measures the progress of course and a final output, the issue with that is I have tried many ways to attempt that but all failed, a shell execution works very well with opening another cmd windows and even requiring elevation but as soon as the progress bar ends and it displays the final output it crashes (and thus I can't see the final output), with shell execution off (executing via the main window) it either doesn't show the progress bar at all and just shows the final output, or shows nothing, or it does show the progress bar, but with each increment it's a new line which obviously doesn't look right...
this is my code:
public static void ExecuteCommand(string command) {
Process prc = new Process();
ProcessStartInfo info = new ProcessStartInfo
{
Verb = "runas",
FileName = "cmd.exe",
UseShellExecute = true,
Arguments = "/c" + command
};
prc.StartInfo = info;
prc.Start();
prc.WaitForExit();
prc.Close();
}
if anyone can think of a fix please do tell me, I have been stuck on this for about 3 days...

Turns out the culprit was "/c", if I change it to "/K" the windows stays open until I close it manually like I wanted.

Related

How to get the output of a running CMD process?

A Program I have to work with opens a CMD-window with a message after processing some data.
The message is something like "finished processing" and I don't have access to the code behind the other Programm.
The goals I want to achieve is:
Get the message from the CMD-window and write it to a text box (or similar) in my own programm.
Close the CMD-window
I managed to attach the process to my programm using Process[] localByName = Process.GetProcessesByName("cmd"); but I can't manage to get the output.
Thank you for your help.
Edit:
To elaborate a bit further about the circumstances of the problem:
I start the other programm with a command line command. I pass some parameters and after a bit, the other programm opens a cmd window with the message.
If i open the other programm normally, then the message is displayed within the application.
None of the parameters give me the option to manipulate the output and i am not able to pipeline the output to another file.
As for why i have to do this: I was given the task to add quality of life improvements to the other programm and using the command line is the easiest way to access the functionality of the other programm. The other solution available would be to reverse engeneer the processing of the data.
The Process class has a StandardOutput property of type StreamReader that you can use to read the output of the process. Using your example:
Process[] localByName = Process.GetProcessesByName("cmd");
if (localByName.Length > 0)
{
var cmdProcess = localByName[0];
var reader = cmdProcess.StandardOutput;
var output = reader.ReadToEnd();
Console.WriteLine($"The output from the cmd process is: {output}");
}
Once you are done with your message processing, you can use the CloseMainWindow() method of the Process class to close the cmd window:
cmdProcess.CloseMainWindow();
This answer is assuming that you want to capture the output of cmd after it has been attached to your process.

Git for windows seems to create sub-processes that never die

I use the following code to call git from C#:
var pInfo = new ProcessStartInfo
{
FileName = "git",
Arguments = "checkout master",
UseShellExecute = false
};
using var p = Process.Start(pInfo);
Console.WriteLine(p.Id);
p.WaitForExit();
The process ID printed is, lets say 3709. When my program ends, I look at the Task Manager and I see a git.exe process still running with a different ID, say 8865. This process remains running indefinitely.
It seems to me that the git process started by my program spawns a second git process that never exits. Is there any way for me to prevent this behavior? As it is, every time I run my program, there is yet another git.exe process left behind indefinitely, adding up to a lot over time, until I reboot.
(Alternatively, is there any other way to invoke git other than by running the executable?)

Listen for cmd output and log to file

I'm trying to make a C# program that can listen for and output to cmd.exe and log it to file. For example, if I run an exe and it runs a command in cmd like echo "hello", I want echo "hello" to be written in a file.
I know I need to use FileSystem, as well as Process maybe?
If this is even possible, and help would really be appreciated. Thanks.
Here's a quick little example that should work. There are a lot of examples out there, I'll try looking on stackoverflow and post one as well...
string cmd_to_run = "dir"; // whatever you'd like this to be...
// set up our initial parameters for out process
ProcessStartInfo p_info = new ProcessStartInfo();
p_info.FileName = "cmd";
p_info.Arguments = "/c " + cmd_to_run;
p_info.UseShellExecute = false;
// instantiate a new process
Process p_to_run = new Process();
p_to_run.StartInfo = p_info;
// wait for it to exit (I chose 120 seconds)
// waiting for output here is not asynchronous, depending on the task you may want it to be
p_to_run.Start();
p_to_run.WaitForExit(120 * 1000);
string output = p_to_run.StandardOutput.ReadToEnd(); // here is our output
Here's the Process class MSDN overview (there's a quick example on this page): https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx
And here's a SO example dealing with calling ReadToEnd() on Process: StandardOutput.ReadToEnd() hangs

Execute process/program silently

I am creating a wpf application that needs a prerequisite. If that prerequisites is not met then I ask the user if he will like to install the prerequisite that happens to be: Microsoft Visual C++ 2010 SP1 Redistributable Package.
So if the user chose to install the prerequisite I will execute vcredist_x86.exe (that is the file that get's downloaded from the first link that I provided).
Then on my application I will be able to tell when the installation is complete by doing something like:
ProcessStartInfo psi = new ProcessStartInfo(#"vcredist_x86.exe");
var p = new Process(); p.StartInfo = psi;
p.Start(); //start the process
p.WaitForExit(); // wait for the installation to finish
// installation should be done now
Ok everything works great so far. The problem is that I have a progress bar in my wpf application and I will like to show the progress in there.
I have been able to show the progress of the installation by doing the following:
There is a program called AutoIt that it is great for automating simple tasks. For example I can easily detect if a window exists with autoit by using something like:
I could then compile that script and create a very small executable. In that executable I will return 1 if the specified window exists or 0 otherwise.
When the user moves to the next window my script might return 2 because that is a different window. AutoIt can also see the progress of a progress bar of a window!!! so if that script returns 80 for example then I will update my progress to 80% for instance.
I do that by doing something like:
// start the autoitExecutable....
// wait for executable to exit usually takes 10 miliseconds it is fast
if (autoitProcess.ExitCode == 1)
{
// do somthing
}else if(autoitProcess.ExitCode == 2)
{
// do something else
} //etc....
As you can see I have to execute that script every 1 second to detect what changes have been done in order to update my progress bar in WPF. That works but every time I execute that executable with c# I get the:
cursor for about 500 milliseconds then on the next second it appears again. That becomes annoying even though no windows show up. It will be nice if I could get rid of that cursor and execute that executable silently somehow. when I execute the autoit executable there are no windows that show up nor nothing else.
P.S.
I know I could use c# to check for the existance of a window and maybe see the value of other window's handler's just like autoit is able to do it but it is so simple to create those programs with AutoIt and it will be nice if I could use AutoIt instead of C# for this kind of taks
I saw this behavior when the exe was set to "windows application" rather than "console application".
Changing the type to console no longer gives a busy cursor at launch.
You could add an event handler as well for example
System.Diagnostics.ProcessStartInfo p = new
System.Diagnostics.ProcessStartInfo(#"vcredist_x86.exe") ;
p.Arguments="-RunForever";
proc = new System.Diagnostics.Process();
proc.StartInfo = p;
proc.EnableRaisingEvents = true;
proc.Exited += new EventHandler(myProcess_Exited);
proc.Start();
inside the event if I wanted to do something like this
// Inside the form class:
private System.Diagnostics.Process proc;
private void myProcess_Exited(object sender, System.EventArgs e)
{
button3.BackColor=Color.LightGreen; //success indicator
}
if you wanted to do this in a While Loop you could also do something like this for example
but you would have to change the params to fit your case
example code you can utilize
while(!autoitProcess.WaitForExit(someTimeout))
{
if(ShouldCancel)
{
break;
}
}
does this make sense or help out...?

how to execute console application from windows form?

I want to run a console application (eg app.exe) from a windows form load event.
I'v tried System.Diagnostics.Process.Start(), But after it opens app.exe, it closes it immidiately.
Is there any way that I can run app.exe and leave it open?
If you are just wanting the console window to stay open, you could run it with something like this command:
System.Diagnostics.Process.Start( #"cmd.exe", #"/k c:\path\my.exe" );
Try doing this:
string cmdexePath = #"C:\Windows\System32\cmd.exe";
//notice the quotes around the below string...
string myApplication = "\"C:\\Windows\\System32\\ftp.exe\"";
//the /K keeps the CMD window open - even if your windows app closes
string cmdArguments = String.Format("/K {0}", myApplication);
ProcessStartInfo psi = new ProcessStartInfo(cmdexePath, cmdArguments);
Process p = new Process();
p.StartInfo = psi;
p.Start();
I think this will get you the behavior you are trying for. Assuming you weren't just trying to see the output in the command window. If you just want to see the output, you have several versions of that answer already. This is just how you can run your app and keep the console open.
Hope this helps. Good luck.
If app.exe does nothing, or finishes its work quickly (i.e. simply prints "Hello World" and returns), it will behave the way you just explained. If you want app.exe to stay open after its work is done, put some sort of completion message followed by Console.ReadKey(); in the console application.
If you can change the code of app.exe, just add Console.In.Read() to make it wait for a key press.
app.exe can end with Console.ReadLine() assuming it too is a C# application where you control the source code.
You have one of two problems, given your master/slave application setup:
Your master app is opening, displaying a form, that form runs the slave app and closes immediately, even though the slave app is still running.
Your master app is opening, displaying a form, that form runs the slave app which closes immediately.
For the first problem, you need to wait/block for the process to complete (i.e. Process.WaitForExit().
For the second problem, it sounds like the slave app has done what it needs to (or thrown an exception) and is closing immediately. Try running it with the same parameters from a command prompt and check the output.
If you have control over app.exe, you should be aware of how it functions so I will assume that you do not have control over it's inner workings. In that case, you can try passing a help flag which may or may not give you more info on how to call app.exe. Try something like this:
private startApp()
{
string command = " -h"; //common help flag for console apps
System.Diagnostics.Process pRun;
pRun = new System.Diagnostics.Process();
pRun.EnableRaisingEvents = true;
pRun.Exited += new EventHandler(pRun_Exited);
pRun.StartInfo.FileName = "app.exe";
pRun.StartInfo.Arguments = command;
pRun.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
pRun.Start();
pRun.WaitForExit();
}
private void pRun_Exited(object sender, EventArgs e)
{
//Do Something Here
}
Create a new text file, name it app.bat and put this in there:
app.exe
pause
Now have your form point to that bat file.
In your console application, type:
Console.ReadLine(); - Use this piece of code to wait until you press enter
Console.ReadKey(); - Use this code to wait until you press a key

Categories

Resources