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.
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 the following C# code:
private void executeBat(string batfile)
{
ProcessStartInfo psi = new ProcessStartInfo(batfile);
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.UseShellExecute = false;
psi.RedirectStandardError = false;
psi.RedirectStandardOutput = false;
Process p = Process.Start(psi);
p.WaitForExit();
if (p.ExitCode != 0)
{
throw new Exception("bat script failed with exit code " + p.ExitCode + ".");
}
p.Close();
}
string batFile = #"C:\Data\SomeFolder\AnotherFolder\SomeBat.bat";
executeBat(batFile);
That runs a .bat script that looks like this:
"c:\Program Files (x86)\SomeThirdParty\SomeExe" >C:\Data\SomeLog.txt 2>&1
set exitcode=%errorlevel%
echo "error return is %exitcode%" >>C:\Data\SomeLog.txt
exit /b %exitcode%
The SomeLog.txt file looks like this:
"error return is 0"
But it appears that the .bat does not really exit because the c# code never returns from p.WaitForExit().
Other people have experienced this problem but my report is different because I am not reading stdout or stderr.
This does not happen consistently. Perhaps 1 out of 1000 executions.
Here is a big clue...
It only happens when I run the c# code from Task Scheduler. When I run it from the commandline I have never gotten the issue.
I have integrated Sav32Cli.exe in my asp.net c# application & its working fine in my local machine but when we move it on the testing server I am getting the following error "Code 2 - If some error preventing further execution is discover "
The scenario is If only 1 person performs the activity it works fine but concurrent connection performs the same activity then I am getting this error for some connections.
Actual scenario : We have the page where users upload the pdf file & as soon as the file is uploaded on the server we perform the scanning via sop-hos and when multiple users perform the same activity I am getting the following error : Code 2 - If some error preventing further execution is discover. So I would like to know from you guys what should I do to bypass this error & implement the scanning successfully into my application.
Below is the code I have written to integrate the scanning into my application :
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
try
{
string filePath = sFileDetails.DirectoryName + "\\" + sFileName;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "C:\\Program Files (x86)\\Sophos\\Sophos Anti-Virus\\sav32cli.exe";
startInfo.Arguments = String.Format(#" -ss ""{0}""", filePath);
process.StartInfo = startInfo;
process.StartInfo.Verb = "runas";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
StringBuilder objStrBuilder = new StringBuilder();
objStrBuilder.AppendLine("Status " + output.ToString());
int i = process.ExitCode;
objStrBuilder.AppendLine("Code " + i.ToString());
File.WriteAllText(sFileDetails.DirectoryName + "\\" + Convert.ToString(System.Guid.NewGuid()) + ".txt", Convert.ToString(objStrBuilder));
if (i > 0)
{
return false;
}
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
process.Close();
process.Dispose();
}
Have you considered using SAVIDI for this - https://www.sophos.com/medialibrary/PDFs/partners/sophossavdidsna.ashx
SAV32CLI will take long time to load all the virus data into memory, I would expect around 5 seconds. This is fine when you're scanning your hard disk but per file it would be rather slow. If you're launching multiple instances then it would be quite a memory drain also.
If your throughput needs improving, I would suggest looking at SAVIDI. In this scenario there is service which loads the virus data once at startup and you can then ask it to scan a file/directory.
This post and attachment in the thread could help you:
https://community.sophos.com/products/endpoint-security-control/f/sophos-endpoint-software/9420/sophos-sav-di-icap-code-sample
Regards.
Sav32Cli.exe requires more permission to execute in web app. So impersonation technique helped me to solve this issue.
This link helped me to solve this issue : Click Here
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.
On the server, I'm attempting to open the command prompt and call an executable which converts a file to PDF. For this I am using the PDFCreator open source program.
In C# I am calling with this code:
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
process.StandardInput.WriteLine(#"cd c:\program files (x86)\pdfcreator");
process.StandardInput.WriteLine(#"PDFCreator.exe /PF""c:\dwf\dwf.dwf""");
It runs with no error, yet yields no result. What this PDFCreator.exe does is call another program, Autodesk Design Review which opens, uses the PDF driver to print to PDF, and saves the file. The command you see works fine being running standalone by me.
From scouring other threads it seems security could be my issue. So I have gone to the PDFCreator and Design Review folders/executables and granted full access to NETWORK, NETWORK SERVICE, IIS_WPG, IIS_IUSRS, and ASP.NET Machine account (realize this is probably a security thread but will disable once i figure out source of the issue). This has not helped.
It should be noted than i can change directory using the first command above, and then create a "test123" folder in both PDFCreator and Design Review folders. Seems I am getting close here, any ideas?
SteveCalPoly and Val Akkapeddi comments are very interesting.
Anyway, I use the following methods to run executable with command prompt
/// <summary>
/// Executes a shell command synchronously.
/// </summary>
/// <param name="command">string command</param>
/// <returns>string, as output of the command.</returns>
public void ExecuteCommandSync(object command)
{
try
{
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows,
// and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
}
}
/// <summary>
/// Execute the command Asynchronously.
/// </summary>
/// <param name="command">string command.</param>
public void ExecuteCommandAsync(string command)
{
try
{
//Asynchronously start the Thread to process the Execute command request.
Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
//Make the thread as background thread.
objThread.IsBackground = true;
//Set the Priority of the thread.
objThread.Priority = ThreadPriority.AboveNormal;
//Start the thread.
objThread.Start(command);
}
catch (ThreadStartException objException)
{
// Log the exception
}
catch (ThreadAbortException objException)
{
// Log the exception
}
catch (Exception objException)
{
// Log the exception
}
}
The System.Diagnostics.Process class has a method called WaitForExit() which will wait for its launched process to exit before continuing and then will return its return code.
Try creating a batch file with your commands and then running the batch file via the Process class. What happens if you use Process.WaitForExit(); after you call Process.Start(processInfo); ? Is there a return code from process.WaitForExit() at all?
Perhaps the errors are going to the StandardError stream and so you never see them?
Also, why not call PDFCreator.exe directly instead of via cmd.exe?
Try something like this
ProcessStartInfo processStartInfo = new ProcessStartInfo(#"c:\program files (x86)\pdfcreator");
processStartInfo.Arguments = #"/PF""c:\dwf\dwf.dwf"""
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
string errors = p.StandardError.ReadToEnd();
Found out the issue over at serverfault. The app I was calling needs to open another app on the desktop and then print to PDF. IIS cannot open programs on the desktop unless set in the services --> service name --> log on tab.
Unfortunately, the app I am calling isn't in the services panel so I'm currently stuck again, but at least I know it's not a C# problem.