I am writing a program that is running a batch file, and will need the output further in the program. this is my C# code:
public void ExecuteBatFile()
{
Process proc = null;
try
{
string targetDir = string.Format("C:\\Users"); //this is where mybatch.bat lies
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = "batch.bat";
proc.StartInfo.Arguments = string.Format("10"); //this is argument
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //this is for hiding the cmd window...so execution will happen in back ground.
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
Console.WriteLine(output);
proc.WaitForExit();
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
}
}
}
Once I run I get this error though:
Exception thrown: 'System.InvalidOperationException' in System.dll
Exception Occurred :StandardOut has not been redirected or the process
hasn't started yet., at
System.Diagnostics.Process.get_StandardOutput() at
CefSharp.MinimalExample.Wpf.CallBatchFile.ExecuteBatFile() in
C:\Users\CefSharp.MinimalExamplemaster\CefSharp.MinimalExample.Wpf\CallBatchFile.cs:line
27
The batch file runs successfully, but then I'm not able to store the result into a variable. I can't get it to work in anyway. Has anyone got any suggestion?
This is my moch batch:
#echo off
cd C:\users\934874
echo.>silvio.txt
title This is your first batch script!
echo Welcome to batch scripting!
if "%errorlevel%"=="0" cls &Echo Success.
if "%errorlevel%"=="1" cls &Echo Fail
pause
The output that I'm expecting is either Success / Fail at console, and store that as a string into a variable.
Thanks in advance for your help
Need to redirect the output
proc.StartInfo.RedirectStandardOutput = true;
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.110).aspx
Quoting from
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute(v=vs.110).aspx
When UseShellExecute is false, the WorkingDirectory property is not used to find the executable. Instead, it is used only by the process that is started and has meaning only within the context of the new process. When UseShellExecute is false, the FileName property can be either a fully qualified path to the executable, or a simple executable name that the system will attempt to find within folders specified by the PATH environment variable.
One of the simplest way is to make your batch file write its output to a text file. Then your main program can read the text file after the batch has finished.
If you really want to read from the standard output stream, please take a look at this other SO post:
Capturing console output from a .NET application (C#)
All what I am trying to do is to be able to run VBS script from code behind but I am getting this error: “The system cannot find the file specified”. I know the path name and I only need to execute that .vbs script but it is giving me hard time and I am not able to figure out. Please help. Thanks
here is my code
System.Diagnostics.Process.Start(#"cscript //B //Nologo \\loc1\test\myfolder\test1.vbs");
i have updated the code as shown below but i am getting a security warning asking me if i want to open it. Is there a way to not get those kind of warning and just run script without any warnings?
here is the updated code:
Process proc = null;
try
{
string targetDir = string.Format(#"\\loc1\test\myfolder");//this is where mybatch.bat lies
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = "test1.vbs";
proc.StartInfo.Arguments = string.Format("10");//this is argument
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
}
catch (Exception ex)
{
// Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
}
Your code working fine for me, I think the error was in your File Path,
Better Confirm the File Path you given is valid or Not..
You can run that file like below also..
Process scriptProc = new Process();
scriptProc.StartInfo.FileName = #"cscript";
scriptProc.StartInfo.Arguments ="//B //Nologo \\loc1\test\myfolder\test1.vbs";
scriptProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
scriptProc.Start();
scriptProc.WaitForExit();
scriptProc.Close();
But check your File Path you given..
The parameters have to be included separately. There is an arguments field you use to pass arguments to the process.
You can use this as a guide for executing programs with command line from an application.
I can call Process.Start(filename.sln) and it launches VisualStudio with that solution.
But doing so using ProcessStartInfo with Verb="runas" and I get an exception. Even with UseShellExecute=true.
Is there a way to launch an app running as admin where I pass it the app's data file and don't have the application.exe filename?
Found the answer - when you run as admin you can only give it the executable file, not the app for the program to run. So you have to pass devenv.exe, not filename.sln
ProcessStartInfo processInfo = new ProcessStartInfo(); //new process class
processInfo.Verb = "runas"; //wanna admin rights
processInfo.FileName = sDevPath + "devenv.exe"; //exe file path
processInfo.Arguments = sPrjPath + "mConverter.sln"; //sln file as argument
try
{
Process.Start(processInfo); //try to start
}
catch (Win32Exception)
{
//oops
}
Due to the joys of UAC, I need to open an elevated command prompt programmatically and then redirect the standard input so I can use the time command.
I can open the link (a .lnk file) if I use
Process ecp = System.Diagnostics.Process.Start("c:/ecp.lnk");
however, if I use this method, I can't redirect the standardIn.
If I use the StartProcessInformation method (which works wonderfully if you are calling an exe)
ProcessStartInfo processStartInfo = new ProcessStartInfo("c:/ecp.lnk");
processStartInfo.UseShellExecute = false;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
Process process = new Process();
process.StartInfo = processStartInfo;
bool processStarted = process.Start();
StreamWriter inp = process.StandardInput;
StreamReader oup = process.StandardOutput;
StreamReader errorReader = process.StandardError;
process.WaitForExit();
I get the error message:
The specified executable is not a valid Win32 application.
Can anyone help me create an elevated command prompt which I can capture the standard input of? Or if anyone knows how to programatically escalate a command prompt?
In case no-one comes up with a better idea (pretty please), here is the work around one of the more devious in my office just came up with:
Copy cmd.exe (the link it pointing at this file)
Paste this file into a different directory
Rename the newly pasted file to something different
Set the permissions on this new file to Run As Administrator
You will still get the escalation dialog popping up, but at least you can capture the standardIn of this valid Win32 app!
I have a service that sometimes calls a batch file. The batch file takes 5-10 seconds to execute:
System.Diagnostics.Process proc = new System.Diagnostics.Process(); // Declare New Process
proc.StartInfo.FileName = fileName;
proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
The file does exist and the code works when I run the same code in-console. However when it runs inside the service, it hangs up at WaitForExit(). I have to kill the batch file from the Process in order to continue. (I am certain the file exists, as I can see it in the processes list.)
How can I fix this hang-up?
Update #1:
Kevin's code allows me to get output. One of my batch files is still hanging.
"C:\EnterpriseDB\Postgres\8.3\bin\pg_dump.exe" -i -h localhost -p 5432 -U postgres -F p -a -D -v -f "c:\backupcasecocher\backupdateevent2008.sql" -t "\"public\".\"dateevent\"" "DbTest"
The other batch file is:
"C:\EnterpriseDB\Postgres\8.3\bin\vacuumdb.exe" -U postgres -d DbTest
I have checked the path and the postgresql path is fine. The output directory does exist and still works outside the service. Any ideas?
Update #2:
Instead of the path of the batch file, I wrote the "C:\EnterpriseDB\Postgres\8.3\bin\pg_dump.exe" for the proc.StartInfo.FileName and added all parameters to proc.StartInfo.Arguments. The results are unchanged, but I see the pg_dump.exe in the process window. Again this only happens inside the service.
Update #3:
I have run the service with a user in the administrator group, to no avail. I restored null for the service's username and password
Update #4:
I created a simple service to write a trace in the event log and execute a batch file that contains "dir" in it. It will now hang at proc.Start(); - I tried changing the Account from LocalSystem to User and I set the admnistrator user and password, still nothing.
Here is what i use to execute batch files:
proc.StartInfo.FileName = target;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit
(
(timeout <= 0)
? int.MaxValue : timeout * NO_MILLISECONDS_IN_A_SECOND *
NO_SECONDS_IN_A_MINUTE
);
errorMessage = proc.StandardError.ReadToEnd();
proc.WaitForExit();
outputMessage = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
I don't know if that will do the trick for you, but I don't have the problem of it hanging.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace VG
{
class VGe
{
[STAThread]
static void Main(string[] args)
{
Process proc = null;
try
{
string targetDir = string.Format(#"D:\adapters\setup");//this is where mybatch.bat lies
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = "mybatch.bat";
proc.StartInfo.Arguments = string.Format("10");//this is argument
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred :{0},{1}", ex.Message,ex.StackTrace.ToString());
}
}
}
}
string targetDir = string.Format(#"D:\");//PATH
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = "GetFiles.bat";
proc.StartInfo.Arguments = string.Format("10");//argument
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
Tested,works clear.
What does the batch file do? Are you certain the process is getting launched with enough privs to execute the batch file? Services can be limited in what they are allowed to do.
Also make sure if you are doing something like usin the copy command to overwrite a file that you do something like:
echo Y | copy foo.log c:\backup\
Also, make sure you are using full paths for the batch commands, etc. If the batch file is launching a GUI app in some sort of "Console" mode, that may be an issue too. Remember, services don't have a "Desktop" (unless you enable the "interact with desktop") to draw any kind of windows or message boxes to. In your program, you might want to open the stdout and stderr pipes and read from them during execution in case you are getting any error messages or anything.
WebServices are probably executing as the IUSR account, or the anonymous account, which ever, so that might be an issue for you. If it works when you run it in console, that's just the first step. :)
I don't recall if System.Diagnostics. are available only in debug or not. Probably not, but some of them might be. I'll have to check up on that for ya.
Hope this gives you some ideas.
Larry
pg_dump.exe is probably prompting for user input. Does this database require authentication? Are you relying on any ENVIRONMENT variables that won't be present for the service? I don't know pg_dump but what are the other possible reasons it would prompt for input?
The next step I would take is to fire up the debugger, and see if you can tell what the program is waiting on. If you are expierenced at debugging in assembly, you may be able to get an IDEA of what's happening using tools like ProcExp, FileMon, etc.
Being a windows SERVICE, and not a web service, makes quite a bit of difference. Anyways, have you tried my suggestion of setting the "Allow Service to interact with desktop"?
If you are desperate, you might try launching cmd.exe instead of your batch file. Then, using the cmd.exe's cmd line parameters, you can have IT start the batch file. This would probably give you a cmd prompt window to view the actual output, if you turn on the interact with desktop.
For complete help on cmd.exe, just type cmd /? at any command prompt.
Larry
Here is the solution. The solution is not clear because I have changed so many time the code and now it's working!
I have tried to use a Account of User, and it's not what worked. Use LocalSystem. Here is the code that execute, mostly what Kevin gave me.
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = fileName;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
output1 = proc.StandardError.ReadToEnd();
proc.WaitForExit();
output2 = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
Thank you all, I'll up-vote everybody and accept Kevin since he helps me since the beginning. Very weird because it works now...
Daok, it looks as if the only thing you changed was the timeout period on the initial WaitForExit(). You need to be VERY careful of that. If something DOES hang your service, it will NEVER return (and well, pretty much work like it has been for you thus far.. heh), but it won't be good for the end users...
Now, perhaps that you know what's causing this to hang, you can debug it further and find the full solution...
That, or spin this off in some thread that you can monitor, and kill if it hangs too long.
Just my 2 cents worth, which usually isn't a whole lot. ;)