I have implemeneted a method into my c# program to run a batch file, which runs a virus scan on any files uploaded;
public static Int32 ExecuteCommand(String filePath, Int32 Timeout){
Int32 ExitCode;
ProcessStartInfo ProcessInfo = new ProcessStartInfo();
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = true;
ProcessInfo.FileName = filePath;
Process proc = Process.Start(ProcessInfo);
proc.WaitForExit(Timeout);
ExitCode = proc.ExitCode;
proc.Close();
return ExitCode;
}
Ok now my batch file;
#ECHO OFF
c:
cd "..\AVG\AVG9\"
avgscana.exe /SCAN="..\learninglounge.com.solar.quarantine\" /REPORT="..\learninglounge.com.solar.antivirus\virusReports\report.txt"
EDIT : I do have fully qualified link to avg exe and directories but have replaced here with .. for purposes of posting to stackoverflow. Sorry if this caused confusion.
So my problem is the reporting side of my batch file. I can double click the batch file and it scans and creates the report no problem. When i run it through my c# i get an exit code of 2; command not recognised. It's fine if i remove the report part of my batch file. Now obviously this points to write permissions but I have checked that and the impersonated user has write access on the directory. Is there anything Im missing?
Thanks all
The error states that avgscana.exe isn't located in directory which is set as "current" when you execute command. When you click on your bat file in Windows Explorer current directory is set to directory where bat file is located. Probably your avgscana.exe is located in the same folder so it works fine.
When you execute the command from .Net application current directory remains the same (if you haven't changed it then it will be a folder where .Net app is located). If your .Net app is located not in the same folder as bat file then you will get an error which you're actually getting. You should either specify a full path in your bat file or set Environment.CurrentDirectory in .Net app before launching bat.
HAve You checked that all enviromental variables are set exactly the same as You run the batch file from cmd line. I am pretty sure that there might be some differences. Also what kind of operating system is it. If this requires elevation (vista windows 7) You might actually need to impersonate appropriate user in code.
luke
Ok well ive done a work around, id rather have saved the report there and then but instead i just catch the standard output from the process and then save to a file + any processing.
Weird one this.
In your batch file, you have:
c:
cd "..\AVG\AVG9\"
avgscana.exe
/SCAN="..\learninglounge.com.solar.quarantine\"
/REPORT="..\learninglounge.com.solar.antivirus\virusReports\report.txt"
When the command is executed, the 'current' directory on drive C: is ambiguous. You just move up the directory tree. Same with the avgscana.exe command, you make relative references instead of absolute.
Are you certain that the CD command has brought you to the correct directory? Change the CD command to an absolute reference ( cd "c:\wherever\avg\avg9\" ), and that way you can be sure your avgscana command's relative references are found.
Your CD command may be failing silently but your avgscana.exe may be in your path, so it does get executed, but since the relative /scan and /report locations are not found, it fails with a code 2.
Good luck!
Related
I'm trying to run a .bat file in my application. This .bat calls a JTAG application to load a firmware in microcontroller. However, I don't know why this fail in to execute the software.
If I run the .bat outside of Visual Studio it works perfectly.
I have the GUI and a Button which I will click to execute the firmware loading
To generate the command files I used a software Uniflash. This software generates a folder with all necessary files to execute the JTAG access and load the firmware.
My code is below:
private void Button_Relay_Click(object sender, EventArgs e)
{
Process MSP = new Process();
MSP.StartInfo.WorkingDirectory = #"D:\\Projects\\Test_Fixture\\Test_Fixture_Visual_Studio\uniflash_windows_64";
MSP.StartInfo.FileName = "dslite.bat ";
MSP.Start();
Thread.Sleep(500);
MSP.WaitForExit();
}
However when I executed this code the compilation is ok, but when I run this code appear this error:
Questions:
I will always generate specific bat files for each application and include the .bat folder inside the folder of VS C#, how I set up the directory path to check automatically in my software folder?
Why the VS can't find the files if the path is right?
After my .bat run I would like to read the status of the programming ( Success or fail ) How I do it?
Success
Fail:
Ad 2)
About the error:
That's because you may have specified the path wrong:
Instead of
MSP.StartInfo.WorkingDirectory = #"D:\\Projects\\Test_Fixture\\Test_Fixture_Visual_Studio\uniflash_windows_64";
either use \\ everywhere (there is only one \ between Test_Fixture_Visual_Studio and uniflash_windows_64) and skip the # OR use the # and just use one \ instead of two. So replace your line with this one:
MSP.StartInfo.WorkingDirectory = #"D:\Projects\Test_Fixture\Test_Fixture_Visual_Studio\uniflash_windows_64";
Ad 3)
About the result of your prcess:
In my opinion it is easier to not call a batch file but to call the process itself directly. In this way you can retrieve the Process.ExitCode property to retrieve the exit code of the executable (if it returns it's state via the exit code).
You can check this by calling the executable in the command shell and check the error level of the last execution by calling
echo %ERRORLEVEL%
Usually 0 indicates success, everything else indicates a failure of some kind.
I'm running my console app from a plain old command prompt. I'm running it two ways:
using a relative path to the executable from what I think is the working directory. i.e.
C:\Working>.\path\to\my.exe -fileToRead file.txt
using a folder in my $PATH$. I.e.
C:\Working>my.exe -fileToRead file.txt
file.txt is in C:\Working and my.exe is C:\Working\path\to. my.exe will output an XML log file to the working directory. In my mind that, that should be C:\Working, but the file actually ends up in C:\Working\path\to. This doesn't jive with all other command line applications.
I'm not doing anything weird or non-standard (that I know about). I've tried just using the file name for the XML file, "TestResult.xml" and also Path.Combine(Environment.CurrentDirectory, "TestResult.xml"). Both end up in the executable directory, not the directory from which I'm running. The command-line parameter file argument is being read properly, so I know that's working.
Clarification: Basically, my problem is that Environment.CurrentDirectory and Assembly.GetExecutingAssembly().Location are the same directory, but shouldn't be.
What am I doing wrong here? And how do I get the directory from which I execute, not the path to the executable? (I realize I have the exact opposite problem of many questions on stackoverflow)
The results you have using Environment.CurrentDirectory are not the one I get with a very simple program like this
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Environment=" + Environment.CurrentDirectory);
Console.WriteLine("Assembly=" + Assembly.GetExecutingAssembly().Location);
}
}
}
Executing this little app from the command line gives always for the first line the directory where the command prompt is running and the second line always the directory where the assembly is located.
So, I suppose that your problem is caused by something different. Probably a change in the current directory.
I am creating MSI installer via VS 2008. I try to delete the temp folder at the end of the installation. That temp folder is created by my installer to hold some batch files for database creation. It always show other process is access it and doesn't allow my code to delete it. I have called the Close() of that access process. I have put sleep before the code to delete it. Nothing helpful.
Do you have any idea how I can delete it at the end of the installation?
thanks,
Did you try Filemon to see who is accessing the temp folder when delete is called on the folder?
Its better you use the system temp folder path
System.Environment.GetEnvironmentVariable("TEMP")
you need not worry about cleaning it up.
I can think of creating a batch file in the temp folder to run which runs as the last step. You put a pause in it by using ping (http://www.robvanderwoude.com/wait.php) and then after a few seconds (that installer has exited) delete the folder by using parameter passed:
PING 1.1.1.1 -n 1 -w 60000 >NUL
rd "%1"
This is really a hack. It is better to root out what locks your folder.
I'll address the conceptual problems in your setup first:
First off, as "Vinay B R" said, be sure your "temp" folder is beneath the Windows %TEMP% folder. That way, you can leave the files there if you fail to delete them.
Why exactly do you want to delete the batch files when you're done? There is no expectation that you clean up after yourself inside of the %TEMP% folder.
If you want to ensure the user doesn't run them again, then you could name them with a different file extension (e.g. ".tmp" instead of .bat), execute them using this method described here, then leave them behind:
cmd < "%TEMP%foo.tmp"
If you are trying to delete files because you don't want the user to have access to them, then by deleting them you will only protect yourself against casual users.
If you still want to delete the files, then:
In all likelihood your own process is locking your folder. Using Process Explorer will likely point to msiexec.exe or cmd.exe. No doubt you are able to manually delete the folder once MSI and SQL have exited, right? If so, then your own process isn't terminating right away. Find out why. Is SQL taking longer than you think, perhaps?
As an alternative to Aliostad's method, here is the "other flavor" listed in this article. As he wrote, however, it would be best for you to determine why it's locked.
Process.Start("cmd.exe", "/C choice /C Y /N /D Y /T 3 & Del " +
Application.ExecutablePath);
Application.Exit();
Here is a working sample in C#. If your users will have .NET installed, then you can invoke this as a custom action using the WiX DTF (install WiX, then in Visual Studio select New Project -> Windows Installer XML -> C# Custom Action Project).:
// Note: This can also be used to delete this .exe (i.e.
// System.Windows.Forms.Application.ExecutablePath).
//
public static void AsynchDeleteFolder(string myTempFolderPath)
{
ProcessStartInfo info = new ProcessStartInfo();
// Don't create a visible DOS box.
info.WindowStyle = ProcessWindowStyle.Hidden;
info.CreateNoWindow = true;
// Wait 3 seconds ("/T 3").
info.Arguments = #"/C choice /C Y /N /D Y /T 3 & rmdir /S /Q """ +
myTempFolderPath + #"""";
info.FileName = "cmd.exe";
Process.Start(info);
}
If you would rather execute just the applicable portion as a batch file, then you can avoid the DOS window by following this method.:
' Filename: Run_a_batch_file_with_no_popup_dos_box.vbs
'
' Invoke like this from the command line:
' wscript.exe Run_a_batch_file_with_no_popup_dos_box.vbs "c:\path with spaces to my file name.bat"
'
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & WScript.Arguments.Item(0) & Chr(34), 0
Set WshShell = Nothing
(See end for solution)
I didn't think this was going to be hard. I have a commmand file, d:\a.cmd which contains:
copy /b d:\7zS.sfx + d:\config.txt + d:\files.7z d:\setup.exe
But these lines of C# won't execute it:
Process.Start("d:\\a.cmd");
Process.Start("cmd", "/c d:\\a.cmd");
Throws Win32Exception: "%1 is not a valid Win32 application."
Process.Start opens .pdf files...why not execute command files?
This works if I type it in a cmd window:
cmd /c d:\a.cmd
Windows XP, MS Visual Studio 2008.
Thanks in advance,
Jim
SOLUTION
I'm only SLIGHTLY embarrassed :( There was a file named cmd.exe, size zero in my app's dir. I have no idea how it got there but it is now toast and both of the above C# statements now work. I'm off to find a Harry Potter book so I can get some self-punishment ideas from Dobby...
I've got four things for you that you can try out:
(1) Try providing the full path for cmd.exe (e.g. on my machine: C:\WINDOWS\SYSTEM32\CMD.EXE).
(2) Try adding call to the command to be executed:
Process.Start(#"C:\WINDOWS\SYSTEM32\CMD.EXE", #"/c call D:\a.cmd");
(3) Besides that, I can only guess where the %1 in the Win32Exception is coming from. Maybe your file associations are set-up incorrectly.
If you type the following on the command-line:
> assoc .cmd
You will likely get a mention of cmdfile. If you then look up this token with:
> ftype cmdfile
You might get an answer along the lines of:
cmdfile="%1" %*
Those settings are stored in the registry, and this is how the command-line interpreter knows how to execute files with custom extensions. (You can find out how a PDF document is started by executing the above two statements for the .pdf extension.)
(4) If you start to suspect that your machine might be mis-configured, start regedit (the registry editor) and locate the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor.
On my Windows XP machine (and your Process.Start example works on my machine, with different filenames though), I've got the following values stored in there:
// Name Type Value
// -----------------------------------------------
// (standard) REG_SZ (not set)
// AutoRun REG_SZ
// CompletionChar REG_DWORD 0x00000040 (64)
// DefaultColor REG_DWORD 0x00000000 (0)
// EnableExtensions REG_DWORD 0x00000001 (1)
// PathCompletionChar REG_DWORD 0x00000040 (64)
Of those, the AutoRun value might be of some interest. I think it corresponds to the /d command-line switch of cmd.exe, which controls whether cmd.exe attempts to start files with custom extensions. Usually, this is enabled. Maybe, on your machine, it isn't?
Or you can do a .bat file, then call this file through System.Diagnostics.Process.Start(). It won't redirect output to Console Application, but it would certainly execute the commands inside.
You need to specify the process full name (cmd.exe).
You should try
Environment.GetFolderPath(Environment.SpecialFolder.System) + "cmd.exe"
So you can be sure to execute the right file even if a cmd.exe is in your applications directory.
It looks like something wrong with your computer. Try running this on another machine. This should work. Process.Start(string) uses ShellExecuteEx to launch the file, so it's pretty much the same thing as double-clicking the file in Explorer, as you supposed.
A simple test worked for me.
B:\foo.cmd:
#echo Hello from foo.cmd!
#pause
Program.cs:
class Program{
static void Main(){
System.Diagnostics.Process.Start("B:\\foo.cmd");
}
}
This works as expected.
Your error message is suspicious, "%1 is not a valid Win32 application." The value in my registry at HKCR\cmdfile\shell\open\command is
"%1" %*
The %1 gets replaced by the file name, and the %* can be ignored here (it indicates that any further command-line arguments should be passed along, but we're not concerned with that right now).
The fact that the file itself is launched to handle this type of file indicates that Windows itself knows how to launch this type of file. On a normal installation of Windows, the following extensions should be set up similarly:
.exe Windows and DOS executable files
.com DOS "command" files
.bat Windows and DOS batch files
.cmd Windows NT batch files
.pif Windows shortcuts to DOS executable files
If you go to HKCR\.xxx (where xxx is any of the above), the "(Default)" value should be xxxfile. If you then go to HKCR\xxxfile\shell\open\command, the "(Default)" value should be "%1" %*. Also the "(Default)" value of HKCR\xxxfile\shell should be either not set or open.
If you have anything else in any of these values, then some program has attempted to insert itself into the execution process. Viruses sometimes do this (Sircam, for example).
Have you tried executing cmd.exe, and passing the .cmd file to it as an argument?
hmm try:
System.Diagnostics.Process myproc = new System.Diagnostics.Process();
myproc.EnableRaisingEvents=false;
myproc.StartInfo.FileName="d:\\a.cmd";
myproc.Start();
MessageBox.Show("did the command");
Have you tested your batch file in the directory, context it's going to run? The error message with %1 looks like the problem may be in there?
i've written a console application deploy.exe which runs a batch script.
Process p1 = new Process();
p1.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "installer.bat";
p1.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p1.Start();
p1.WaitForExit();
p1.Close();
the installer.bat conatins the following command.
\shared1\lists\list1.cmd
If i run the executable byitself it runs successfully.
However i needed it to run in a windows installer project. So i made a setup and deployment project and added the deploy.exe successfully as custom action upon install.
It runs fine but when it starts to execute the command i get this error
"The filename, directory name, or volume label syntax is incorrect".
any help?
Try printing out what the value of AppDomain.CurrentDomain.BaseDirectory is. It may not be where installer.bat is when you are installing it.
Also, you tried adding the bat file to a custom action (if that is even possible)?
And, would it possible to move what is in the bat to the exe?
Is it a problem in your batch file?
Check this:
\\shared1\\lists\\list1.cmd
should probably be
\\shared1\lists\list1.cmd
Note the extra \ chars in your original command. That would cause the batch file to give that error.
the error seems to be inside the script which was being executed. It contained environment variables %kind%, which were not acceptable by the installer for some reason. So it was working properly outside the installer and not properly when the installer was calling it.