This question already has answers here:
Calling a batch file from a windows service
(3 answers)
Closed 9 years ago.
I am having batch file : sample.bat with following code:
#ECHO OFF
SET /a INT1=%1
SET /a INT2=%2
SET /a ANSWER=INT1*INT2
ECHO %ANSWER%
PAUSE
Also created another batch file : cmdSample.bat with following code:
sample 2 4
So if i run cmdSample.bat file, it gives me correct result.
After that i have created 1 windows service application in which i tried to call that batch file and pass the command, as follows:
private void DoWork()
{
try
{
string fname = #"C:\Users\of4\Desktop\sample.bat";
string cmd = "sample 2 4";
RunSampleBatch(fname, cmd);
}
}
private void RunSampleBatch(string fname, string cmd)
{
Process p = new Process();
p.StartInfo.FileName = fname;
p.StartInfo.Arguments = cmd;
p.Start();
}
Can anyone help me, why i am not able to execute batch file through windows service application??
Thanks in advance..
Your parameters are off, you are giving "sample" as your first parameter to the sample.bat.
Your service is probably not running under your user account. Maybe it cannot even access your file.
You need to start your batchfile using cmd.exe. You can find a very good explanation here.
What are you trying to do? Running a batch file from a windows service doesn't make much sense, you won't be able to see the results. Maybe you should try a console application first to debug your problems.
You might also want to post an actual error next time, because all of the above is just guesswork, we need more info than just "doesn't work".
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a simple service with .net using c#. When I deploy the serivce, I know that it's running because I can see files being deleted. However, the only task that doesn't run is the send the file to printer task. I'm using admin account on the service and it still not doing anything. If I run this same code in visual studio under debug mode, the service runs just fine. please advise on what I'm doing wrong. Thank you so much everyone.
const string flagNoSplashScreen = "/s";
const string flagOpenMinimized = "/h";
var flagPrintFileToPrinter = string.Format("/t \"{0}\" \"{1}\"", pdfFileName, printerName);
var args = string.Format("{0} {1} {2}", flagNoSplashScreen, flagOpenMinimized, flagPrintFileToPrinter);
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = processFilename;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.Arguments = args;
p.Start();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
//if (!p.WaitForExit(10000))
//{
// if (!p.HasExited)
// {
// p.Kill();
// }
//}
p.EnableRaisingEvents = true;
p.CloseMainWindow();
p.Close();
Unfortunately without you giving us an exception or stack trace we havent got much to go on here.
So, first of all, you need to find out which line of code fails when running as a "windows service" and not when you run the code "interactively".
One thing you could do is wrap your function with a try/catch clause and catch the exception and log it to a file.
In addition to that, another option would be for you to debug the code whilst it is running as a windows service and then put a breakpoint on the function in question and step through the code.
To do that, temporarily add the following code to the service:
static void Main(string[] args)
{
if (Debugger.IsAttached == false)
Debugger.Launch();
...
Then, make sure you have visual studio open with your solution loaded. Then, when you start your service, it will pop up a dialog and ask for you to either attach to an "existing instance" of visual studio or to "open a new instance". Select the option to attach to an "existing instance" with your code open, and then you will be able to step through the code as normal, set breakpoints, etc, only this time the code is running under the credentials of the service.
From here, you should be able to track down the code that fails while running as a service.
Due to me having knowledge of launching apps I am aware that you have multiple ways of launching an application in C# .NET, but I'm running into a issue that occurs when attempting to launch a SDL2 application.
I have attempted the following using the Process class to:
Start the .exe file of the build.
Start the application using "cmd.exe /K" or "cmd.exe /c" followed by "exec" or "call" or "start" followed by "{path to file}" or "{path to batch file to launch the application}". Launching the application via a batch file and CMD works fine. But, whenever I attempt to even launch the application (even in a new instance of Command-Prompt launched from cmd.exe /? start cmd.exe ?params) it will yield no result.
What I can observe is that the application tries to open. It takes forever to launch into the Window mode (starting the 3D environment). After a timeout it will either, render a couple of frames of a blank window before closing or close immediately after opening the window.
So my question is, does anyone have succesfully made a launcher application for a SDL app written in C# .NET? Or knows a way to debug this behaviour? Because unfortunately, the app does not send out a error message and since SDL safely closes the application I can't observe a crash either.
Edit #1
I'm not doing anything fancy with parameters as there shouldn't be any. I already have another one functioning that launches a normal C# application as my launcher requires to open 2 programs. 1 SLD application, 1 COM:VBA controlling application.
Given:
string audioSpectrumProgram = "AudioSpectrum.exe";
string audioSpectrumBatchProgram = "AudioSpectrum.bat";
private void BtnLaunchPPTApp_OnClick()
{
//Powerpoint controlling application
pVBAApp = Process.Start(presenterProgram, $"\"{this.path}\" {this.audioFormatParams[0]} {((this.ckboxGenerate.Checked) ? "--create" : "")} lang={this.languageCodesParams[this.cboxLanguage.SelectedIndex]}");
}
Method 1:
private void BtnLaunchSDLApp_OnClick()
{
pVizualizer = Process.Start(audioSpectrumProgram); //file launched from local path (is correct)
}
Method 2:
pVizualizer = Process.Start(audioSpectrumBatchProgram); //file launched from local path (is correct)
Method 3:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
if (spectrumFileInfo.Exists)
info.Arguments = $"/c \"{spectrumFileInfo.FullName}\"";
pVizualizer = Process.Start(info);
Method 4:
based on senario of method 3. You don't have to parse arguments using ProcessStartInfo.
pVizualizer = Process.Start($"cmd.exe /K call \"{spectrumFileInfo.FullName}\"") //to observe what happens to the application
Edit #2
Not affected by changing the UseShellExecute to true or false
private void btnOpenVisualizer_Click(object sender, EventArgs e)
{
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.UseShellExecute = true;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n"
);
}
A general way of analyzing startup issues is to use SysInternals Process Monitor.
Record the application that is not starting up properly. Use a filter for your application. Then go through all items which don't have SUCCESS in the result column. Typically you want to do that bottom-up, since the last error is the one stopping your application from loading.
Like this you'll find common startup issues like:
missing DLLs or other dependencies
old DLLs or DLLs loaded from wrong location (e.g. registered COM components)
wrong working directory, e.g. access to non-existent config files
Ok For Future reference:
Pathing to the files can be correct and everything might be in order but if you are using DLLs for imports. Change the process's working directory.
The project will run, libs can "sometimes" be found but can cause a weird unknown bug like this one. So the most optimal way of running another C# instance with SDL or any other kind of library:
private void RunSDLProgram()
{
FileInfo spectrumFileInfo = new FileInfo("pathToFile.exe");
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.UseShellExecute = false;
info.WorkingDirectory = spectrumFileInfo.DirectoryName;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n" +
$"output : {pVizualizer.StandardOutput}\n" +
$"err : {pVizualizer.StandardError}\n"
);
}
Running a batch file will look at it's own directory and makes all references local, but it won't alter the working directory. (already had my suspicions about changing the work directory but I didn't see a way to call 2 opperations in process.start("cmd.exe");)
I have 4 independent servers (not in domain):
IIS, SQL1, SQL2, SQL3
I want to copy a database backup from SQL1 to SQL2 or SQL3 (depending on parameters) by button click on webpage hosted on IIS
I wrote a button click method for that, which is calling batch file located in inetpub folder on IIS
Batch is using pstools to run robocopy on SQL1 which should copy required file to destination server (SQL2 or SQL3)
This solution works if I execute batch directly on IIS (cmd as Administrator) or when I debug it on my local machine, but it doesn't if it is called from the running site.
It even doesn't spend any time between the following lines:
batchProcess.Start();
batchProcess.WaitForExit();
Here is my copy method:
private bool ProcessCopy(string file, string destinationIp)
{
SecureString password = ConvertToSecureString("myPassword");
try
{
string batchPath = Server.MapPath(".") + "\\CopyFile.bat";
string cmd = #"c:\Windows\System32\cmd.exe";
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = cmd,
UseShellExecute = false
};
Process batchProcess = new Process {StartInfo = processInfo};
batchProcess.StartInfo.Arguments = $"/C {batchPath} {file} {destinationIp}";
batchProcess.StartInfo.Domain = "";
batchProcess.StartInfo.UserName = "Administrator";
batchProcess.StartInfo.Password = password;
batchProcess.StartInfo.RedirectStandardOutput = true;
batchProcess.StartInfo.RedirectStandardError = true;
batchProcess.StartInfo.CreateNoWindow = true;
batchProcess.Start();
batchProcess.WaitForExit();
string response = batchProcess.StandardOutput.ReadToEnd();
response += batchProcess.StandardError.ReadToEnd();
statusStringAppend($"response: {response}");
return true;
}
catch (Exception ex)
{
statusStringAppend($"Failed: {ex.Message}. {ex.StackTrace}");
}
return false;
}
Batch body is:
#echo off
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
My questions are:
1. Why the file was not copied?
2. Is there any better way to get it copied?
CODE UPDATED ACCORDING TO SUGGESTIONS BELOW
My guess is that you never executed pstools as the user that your IIS service is running as before, so the EULA dialog is blocking your execution.
If you remember, you always got a window and needed to press the accept button when running any sysinternals tool like pstools the first time.
I guess this should work for you:
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
[EDIT]
You would most likely have hit this problem later on, anyway it did not work for you, so i have to list what else could be wrong with your code:
starting a .bat file needs cmd.exe as mother process, you cannot just start a .bat file as process directly. Instead you can for example use another method than ProcessStartInfo that spawns the system default script interpreter automatically: Executing Batch File in C#
the process for executing batch files is "cmd.exe", first parameter "/C", second parameter the batch file you are executing
when executing typical commandline tools, you might consider reading the SDTOUT (standard output) of the process you are executing, like this: Capturing console output from a .NET application (C#)
This question already has answers here:
How To: Execute command line in C#, get STD OUT results
(18 answers)
Closed 7 years ago.
I am trying to run an exe file as window service. I have done it before manually by doing like this:
sc create TestService binPath= "C:\MyExePathWhichIsToBeRunAsWindowService"
and it could worked properly, when i see the services i am able to find it, Now have to do the same using c# code.
The code should ask the user for the path of exe file and this file has to be run as window service and also the name which he has to provide to this window service.So these two things user will enter at runtime, which is an easy task for me but once if i got that, then how i will run the command below from c# code ?
sc create TestServiceNameUsrEntered binPath= "path user entered for exe at run time"
Could some one please help me ?
EDIT: Please note that user will always enter serviceApplication exe file Not arbitrary files
You should look into Process.Start. You might want to try something like this:
Process.Start("sc", String.Format("create \"{0}\" binPath=\"{1}\"", serviceName, binPath));
You can take a look at Topshelf.
If you like to do it from scratch yourself, you can take a look into the HostInstaller.cs, where it simply adds the needed registry key:
using (RegistryKey system = Registry.LocalMachine.OpenSubKey("System"))
using (RegistryKey currentControlSet = system.OpenSubKey("CurrentControlSet"))
using (RegistryKey services = currentControlSet.OpenSubKey("Services"))
using (RegistryKey service = services.OpenSubKey(_settings.ServiceName, true))
{
service.SetValue("Description", _settings.Description);
var imagePath = (string)service.GetValue("ImagePath");
_log.DebugFormat("Service path: {0}", imagePath);
imagePath += _arguments;
_log.DebugFormat("Image path: {0}", imagePath);
service.SetValue("ImagePath", imagePath);
}
I wan to add some DNS records in c# program via a bat file so I have written these lines in bat file:
set servername=%1
set siteaddress=%2
"C:\Windows\System32\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
and I have written these lines in C#:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.WorkingDirectory = Application.StartupPath;
p.StartInfo.FileName = General.DnsBatPath;
p.StartInfo.Arguments = string.Format("{0} {1}", General.DnsServerName, txtSiteAddress.Text);
p.Start();
p.WaitForExit();
I get this error "dnscmd.exe is not recognized as internal or external command..." but when I run bat file manually (outside of C#) all things are OK.
I changed my C# code to check what happened
Process.Start(#"C:\Windows\System32\dnscmd.exe");
I still get "not recognized ..." error.but I can see dnscmd.exe in "C:\Windows\System32".
I changed my C# code again to check another thing:
Process.Start(#"C:\Windows\System32\cmd.exe");
and after that CMD windows will be opened???
any idea?
In answer to your second question, you can always check the environmental variable PROCESSOR_ARCHITECTURE to see if it contains the number 64.
set servername=%1
set siteaddress=%2
if "%PROCESSOR_ARCHITECTURE%" equ "%PROCESSOR_ARCHITECTURE:64=%" (
REM 32bit
"C:\Windows\System32\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
) else (
REM 64bit
"%windir%\Sysnative\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
)
Possibly a more reliable method is to get it from the registry:
set servername=%1
set siteaddress=%2
for /f "tokens=3" %%x in ('reg Query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier') do (
set arch=%%x
)
if %!arch:~-2!%==64 (
set dnsPath=%windir%\Sysnative
) else (
SET dnsPath=C:\Windows\System32
)
"%dnsPath%\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
In my case I created a console application to run a batch file with some java command but was getting 'java' not recognized as an internal command error.
Took me few hours but the solution is straight forward. My server had JVM running on 64 bit so I changed the platform target to 64 bit.
x86 is 32 bit and x64 is 64 bit. Project properties are below:
Try this code:
ProcessInfo psi= new ProcessStartInfo("cmd.exe", string.Format("/c {0} {1} {2}", General.DnsBatPath, General.DnsServerName, txtSiteAddress.Text);
psi.UseShellExecute = false;
process = Process.Start(psi);
process.WaitForExit();
The /c parameter says that the given command should run and then cmd.exe should exit. For details, run cmd /? in windows console.
You can also try what happens when you set ShellExecute to true. Then the process should start the same way like a file is double-clicked in explorer. The disadvantage of shell execution is that if the user changed the .BAT file default application to (for example ) notepad, the file will not be executed but opened in notepad.
If you also want to redirect the console output, look here: Executing Batch File in C#