I have a wrote a C# code that would read several .xml files(Containing executable, path, parameters. The .xml files contains a series of executable that need to be run) and several batch file will be created associate with the .xml file.
After each batch file is created, the program would execute each batch file in the C# code (using cmd of course). The problem is some of the batch file would run for days and it is a waste of memory/instants to keep the C# program running.
Is it possible to keep the .bat file running and close the C# code? Assuming that we do not need any error reporting from the C# code.
Below is the code for executing a batch file.
//Execute BatchFile
public static void ExecuteCommand(string command, string dummyPath)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.WorkingDirectory = dummyPath;
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
process.Close();
}
If I understand you correctly, I think it is possible if you don't need any feedback from the .bat file.
I have tested this line of code on my own machine and it worked fine.
static void Main(string[] args)
{
System.Diagnostics.Process.Start(#"d:\simple.bat");
}
and for testing purpose I simply put PING www.google.com inside my .bat file.
The cmd batch process is belong to your program process, main process stop and sub processes will be killed.
I think you can try to create windows task schedule in your program, run batch in the taski, program stop and task schedule will still runnning.
Related
I have this code
public static void ExecuteCommand(string command, string workingFolder, int TimeoutMin)
{
int ExitCode;
ProcessStartInfo ProcessInfo;
Process process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
ProcessInfo.WorkingDirectory = workingFolder;
// *** Redirect the output ***
ProcessInfo.RedirectStandardError = true;
ProcessInfo.RedirectStandardOutput = true;
process = Process.Start(ProcessInfo);
process.WaitForExit(TimeoutMin * 1000 * 60);
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
ExitCode = process.ExitCode;
MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
process.Close();
}
It runs batch file in C#
it is the batch file runs long process which takes few minutes
when I call ExecuteCommand then close the application, the batch file still runs even though app is closed
Is there any way I can control running batch files from within my c# code?
According to C# process hanging due to StandardOutput.ReadToEnd() and StandardError.ReadToEnd()
and Hanging process when run with .NET Process.Start -- what's wrong?
If output is kept filling with info, your thread might be blocked.
Following lines are blocking in your operation
process.WaitForExit(TimeoutMin * 1000 * 60);
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
That is, process.Close is never called before batch is done.
If abortion is required, you need to close process somewhere else while application is exiting.
I reproduce your problem by
Pasting code snippet to a button clicked event on a small winform application.
Press the button.
UI hung <--- That means code snippet is blocking a (UI) thread.
I have a batch file I want to run from a C# windows form. the Batch file is very basic and accepts one parameter
cd C:\Program Files (x86)\Advent\ApxClient
AdvScriptRunner REPRUN -mrgainloss -p%1 -vf -t\\myserver\apx$\pdf\myReport
If i call it in a command prompt, this works fine
C:\Program Files (x86)\Locations\blah>realizedgainloss 123456
that will run just fine, and i get the expected result (it outputs a report run on a third party peice of software). However I cannot for the life of me figure this out with c#. I have the following.
private void button1_Click(object sender, EventArgs e)
{
ExecuteCommand(getCommand());
}
public string getCommand()
{
return "realizedgainloss.bat";
}
static void ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo(command);
//processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.Arguments = String.Format("{0} {1}", command, "123456");
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
// Warning: This approach can lead to deadlocks, see Edit #2
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
process.Close();
}
Its worth noting that if i do not provide a parameter, and change the bat file to be static, with 12345 in place of it's %1, then it runs from C#, so there is something incorrect about how i'm getting the parameters into the bat file...
any thoughts?
You have your batch file name as the command to run and the first parameter of your script. I find it easier and more reliable to use cmd.exe as the command to run and invoke it with the /C argument. Doing it this way you should make sure your working directory is set correctly as well.
processInfo = new ProcessStartInfo("cmd.exe");
processInfo.Arguments = String.Format("/C {0} {1}", command, "123456");
processInfo.WorkingDirectory = yourWorkingDirectory;
I am trying to execute a batch file which runs on its own. I am now trying to automate this by deploying it as a windows service which listens for a folder and invokes the batch file using file watcher event. Here is the code -
void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
ServiceEventLog.WriteEntry(TheServiceName + " Inside fileSystemWatcher_Created() - ");
if (e.Name.Trim().ToUpper().Contains("FU4DGF_TRADES"))
{
try
{
Utilities.SendEmail("IAMLDNSMTP", 25, "desmond.quilty#investecmail.com", "IAMITDevelopmentServices#investecmail.com", "Ben.Howard#investecmail.com", "prasad.matkar#investecmail.com", "StatPro BatchFile Execution Started ", "");
int exitCode;
// ProcessStartInfo processInfo;
ServiceEventLog.WriteEntry(TheServiceName + " Before creation of instance of Batch process - ");
Process process = new Process();
process.StartInfo.FileName = #"C:\Program Files (x86)\StatPro Suite\MonthlyUpload.bat";
process.StartInfo.RedirectStandardOutput = false;
process.StartInfo.RedirectStandardError = false;
process.StartInfo.CreateNoWindow = false;
process.StartInfo.WorkingDirectory = #"C:\Program Files (x86)\StatPro Suite";
process.StartInfo.UseShellExecute = false;
ServiceEventLog.WriteEntry(TheServiceName + " Before start of Batch process - ");
process.Start();
ServiceEventLog.WriteEntry(TheServiceName + " After start of Batch process - ");
process.WaitForExit();
//while (!process.HasExited)
//{
// System.Threading.Thread.Sleep(100);
//}
ServiceEventLog.WriteEntry(TheServiceName + " After process.close - ");
System.Environment.ExitCode = process.ExitCode;
}
I can see from my event log that it goes as far as logging - Before start of Batch process. Presumably after that the process starts by invoking process.Start() but then nothing happens. Nothing in the event log, the service is still running i.e. not crashed. No errors. I can see from task manager that it does invoke the exe that it is supposed to invoke via the batch file but the exe simply remains in memory with constant memory and 0 CPU usage suggesting the exe is not doing anything. If I run the batch file manually it works fine. Any idea what could be going wrong?
You disabled UseShellExecute. This means that you can't use the shell to execute the file. bat files are not executables, they are shell scripts.
Since you're not redirecting standard I/O anyway, just enable UseShellExecute and you should be fine.
I want to execute a batch command and save the output in a string, but I can only execute the file and am not able to save the content in a string.
Batch file:
#echo off
"C:\lmxendutil.exe" -licstatxml -host serv005 -port
6200>C:\Temp\HW_Lic_XML.xml notepad C:\Temp\HW_Lic_XML.xml
C# code:
private void btnShowLicstate_Click(object sender, EventArgs e)
{
string command = "'C:\\lmxendutil.exe' -licstatxml -host lwserv005 -port 6200";
txtOutput.Text = ExecuteCommand(command);
}
static string ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
process.Close();
return output;
}
I want the output in a string and do this directly in C# without a batch file, is this possible?
Don't need to use "CMD.exe" for execute a commandline application or retreive the output, you can use "lmxendutil.exe" directly.
Try this:
processInfo = new ProcessStartInfo();
processInfo.FileName = "C:\\lmxendutil.exe";
processInfo.Arguments = "-licstatxml -host serv005 -port 6200";
//etc...
Do your modifications to use "command" there.
I hope this helps.
It doesn't look to me like your batch file will produce any output. If you run it in the command line, do you see an output? You have the redirection > operator in your bat file line, so it seems like you're sending output to the xml file.
If you have saved the output to an xml file, maybe you should just load that using C# once your process exits.
When i try to run BCDEDIT from my C# application i get the following error:
'bcdedit' is not recognized as an internal or external
command,
operable program or batch file.
when i run it via elevated command line i get as expected.
i have used the following code:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.FileName = #"CMD.EXE";
p.StartInfo.Arguments = #"/C bcdedit";
p.Start();
string output = p.StandardOutput.ReadToEnd();
String error = p.StandardError.ReadToEnd();
p.WaitForExit();
return output;
i have also tried using
p.StartInfo.FileName = #"BCDEDIT.EXE";
p.StartInfo.Arguments = #"";
i have tried the following:
Checking path variables - they are fine.
running visual studio from elevated command prompt.
placing full path.
i am running out of ideas,
any idea as to why i am getting this error ?
all i need is the output of the command if there is another way that would work as well.
thanks
There is one explanation that makes sense:
You are executing the program on a 64 bit machine.
Your C# program is built as x86.
The bcdedit.exe file exists in C:\Windows\System32.
Although C:\Windows\System32 is on your system path, in an x86 process you are subject to the File System Redirector. Which means that C:\Windows\System32 actually resolves to C:\Windows\SysWOW64.
There is no 32 bit version of bcdedit.exe in C:\Windows\SysWOW64.
The solution is to change your C# program to target AnyCPU or x64.
If you are stuck with x86 application on both 32it/64bit Windows and You need to call bcdedit command, here is a way how to do that:
private static int ExecuteBcdEdit(string arguments, out IList<string> output)
{
var cmdFullFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess
? #"Sysnative\cmd.exe"
: #"System32\cmd.exe");
ProcessStartInfo psi = new ProcessStartInfo(cmdFullFileName, "/c bcdedit " + arguments) { UseShellExecute = false, RedirectStandardOutput = true };
var process = new Process { StartInfo = psi };
process.Start();
StreamReader outputReader = process.StandardOutput;
process.WaitForExit();
output = outputReader.ReadToEnd().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
return process.ExitCode;
}
usage:
var returnCode = ExecuteBcdEdit("/set IgnoreAllFailures", out outputForInvestigation);
Inspiration was from this thread and from How to start a 64-bit process from a 32-bit process and from http://www.samlogic.net/articles/sysnative-folder-64-bit-windows.htm