Go Premium for a chance to win a PS4. Enter to Win

x
Solved

# How can I have a .NET windows service execute a batch file?

Posted on 2010-08-26
Medium Priority
1,003 Views
I have a C# .NET Windows service in which I define a FileSystemWatcher component. This filewatcher watches a folder on my local machine and when a file gets created in this folder, on the create event, I start a process that will need to run a batch file (which picks up the file and posts it onto a tumbleweed ftp using the tumbleweed secure transport command line).
Here's the code in the created event of the FileSystemWatcher:
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo();
procStartInfo.FileName = "cmd.exe";
procStartInfo.Arguments = @"/c C:\temp\MyBat_TEMP.bat";
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = false;
// Now create a process, assign its ProcessStartInfo and start it
//Declare and instantiate a new process component.
System.Diagnostics.Process process1;
process1 = new System.Diagnostics.Process();
process1.StartInfo = procStartInfo;
try
{
process1.Start();
process1.WaitForExit(10000);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
process1.Close();
}

However, when I start the windows service and put a new file in the watched folder, it does not execute the batch file, it basically does nothing, does not throw any errors. I copied this same piece of code into a console app and run it and it works fine (i.e. batch file commands are executed).
Is there an issue that anyone knows about, with executing batch files from a windows service? Also, I setup the service to run as "Local System".
Any help is appreciated. Thanks.
0
Question by:KimberleyY
• 6
• 4
• 2
• +2

LVL 16

Expert Comment

ID: 33538650
0

LVL 1

Expert Comment

ID: 33543339
This worked for me -

private bool RunCmd(
string app,
string workingDirectory,
string cmd,
EventHandler proc_Exited,
LoggerDelegate Logger)
{
try
{
RunCmdProcess = new Process();
RunCmdProcess.StartInfo.Verb = "runas";
RunCmdProcess.StartInfo.Arguments = cmd;
RunCmdProcess.StartInfo.FileName = app;
RunCmdProcess.StartInfo.WorkingDirectory = workingDirectory;
RunCmdProcess.StartInfo.UseShellExecute = false;
RunCmdProcess.StartInfo.RedirectStandardInput = true;
RunCmdProcess.StartInfo.RedirectStandardOutput = true;
RunCmdProcess.StartInfo.RedirectStandardError = true;
//RunCmdProcess.StartInfo.CreateNoWindow = true;
RunCmdProcess.Start();
RunCmdProcess.Exited += proc_Exited;
InputStream = RunCmdProcess.StandardInput;
}
catch (Exception ex)
{
// do some logging
return false;
}
return true;
}
0

Author Comment

ID: 33544778
Thanks for the responses.
I tried the following:
1) change the service Log On to administrator from Local System (as described in the link posted by vs00saini) and that didn't do it
2) funazonki, I tried what you suggested and that doesn't seem to run the batch file either. Here's my code snippet:
string batchFile = @"C:\temp\MyBat_TEMP.bat";

System.Diagnostics.Process process1;
process1 = new System.Diagnostics.Process();
process1.StartInfo.Verb = "runas";
process1.StartInfo.Arguments = Environment.GetEnvironmentVariable("COMSPEC");
process1.StartInfo.FileName = batchFile;
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.RedirectStandardInput = true;
process1.StartInfo.RedirectStandardError = true;
try
{
process1.Start();

}
catch (Exception ex)
{
//System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
process1.Close();
}

In your code, were you passing the cmd.exe as the Argument and the location to the batch file as the FileName properties?
My batch file has the following in it:
cd C:\Program Files\Tumbleweed\STClient
<another line to execute a command line from this location>
I also tried changing my batchfile to do something simple, like
cd C:\Program Files
dir
and that didn't work either so I know it's not the command line.

Thanks for taking the time to respond. I appreciate your thoughts!
0

LVL 1

Expert Comment

ID: 33545199
I create the service with an sc command something like the following:

sc create {1} type= own start= delayed-auto binPath= \"{0}\" obj= {2} DisplayName= \"{1}\" password= {3}"

this is on windows 7 - earlier windows would only allow start= auto. I run under a local admin account. Note the odd sc convention in start= you must have a space after the '=' and no space before it
0

LVL 16

Expert Comment

ID: 33545498
COMSPEC is an environment variable that points to cmd.exe. You don't want to pass that as an argument. It's the actual executable. The batch file is the filename argument to StartInfo. Finally, any additionally required argument go in StartInfo.Arguments.

I suggest you start with the simplest example and even the simplest environment. I'd start by whipping up a tiny test in Code Snippet (free here: http://www.sliver.com/dotnet/SnippetCompiler/) and you'll quickly discover that the basic concept works.

I just copied the code from above and removed some of the fluff to keep it simple.
	public static void RunSnippet()
{
RunCmd( @"c:\test.bat", @"c:\", null);
}

private static bool RunCmd(
string app,
string workingDirectory,
string args
)
{
try
{
Process RunCmdProcess = new Process();
RunCmdProcess.StartInfo.Verb = "runas";
RunCmdProcess.StartInfo.Arguments = args;
RunCmdProcess.StartInfo.FileName = app;
RunCmdProcess.StartInfo.WorkingDirectory = workingDirectory;
RunCmdProcess.StartInfo.UseShellExecute = false;
//RunCmdProcess.StartInfo.CreateNoWindow = true;
RunCmdProcess.Start();
}
catch (Exception ex)
{
// do some logging
return false;
}
return true;
}

#region Helper methods

public static void Main()
{
try
{
RunSnippet();
}
catch (Exception e)
{
string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
Console.WriteLine(error);
}
finally
{
Console.Write("Press any key to continue...");
}
}

private static void WL(object text, params object[] args)
{
Console.WriteLine(text.ToString(), args);
}

private static void RL()
{
}

private static void Break()
{
System.Diagnostics.Debugger.Break();
}

#endregion
}

0

Author Comment

ID: 33545758
Todd,
Thanks!
My code does work from a console application. The issue is I cannot get the batch file to execute from my Windows service.
I basically want to execute a batch file from a FileSystemWatcher's "created" event handler in my service.
0

LVL 16

Expert Comment

ID: 33545951
Yikes... I missed that all too important bit about you having tested it in a console app! Sorry!

It doesn't seem right to me that you get no failure at all. Did you check the return code from the Process object?

Did you check to make sure that the user account it's running under has the needed comspec and it's right (if you're using that trick)?

How do you know it's not running? The "something simple like dir" test would never appear because a physical window won't open.

Can you have it do something like "dir > c:\test.txt", so you can then check for that file. I haven't messed with a service in a long time. If it's really not working, I assume it's permissions related, as you probably do, too.
0

LVL 16

Expert Comment

ID: 33546041
I'm searching for running a batch file from a windows service and I'm getting conflicting reports.

Some say it's not possible.

This guy claims he got it working as local service: http://stackoverflow.com/questions/361097/c-service-cannot-execute-batch-file

This solution talks about being local system working ok, but only with local files (no network resources are accessible from that account).

http://www.experts-exchange.com/Programming/Languages/Scripting/Q_22524877.html
0

Author Comment

ID: 33546253
Thanks for the input, Todd.
I did try the "dir > c:\text.txt" in my batch file and even that doesn't execute. I tried as both Local System and as the User. I'll double check if the User has all the required permissions or not, that's a good point. But right now I'm not even looking at the other command line things, all my batch file has is this:
"dir > C:\test.txt"
But maybe you do need special permissions to even execute a batch file from a windows service, whether or not it's accessing any network resources.
0

LVL 4

Expert Comment

ID: 33546902
To figure out what's going on, you're going to need to debug (step into) your service code. This is pretty easy to do. Start up your service as usual - locate the process that it is running as (in Task Manager). Now from within your Visual Studio solution (containing the service), 'ATTACH TO PROCESS' from the debug menu. You should be able to step into your code now.

Firstly - ensure that you are executing process1.Start() inside your try catch.

Let me know what you find out.

Thanks

0

Author Comment

ID: 33560548
Hi all,
Thanks for taking the time to respond. Here's what I found and if anyone has had similar issues before, i'd be interested, because this doesnt make sense!

When I define the ProcessStartInfo object like below, it seems to work and the batch file gets executed from the process:

string batchFile = @"C:\temp\MyBat_TEMP.bat";

System.Diagnostics.Process process1;
process1 = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psInfo = new ProcessStartInfo(batchFile);
psInfo.UseShellExecute = false;
psInfo.CreateNoWindow = false;
0

Author Comment

ID: 33560577
sorry, didnt mean to submit my previous comment incomplete, but basically if I do:
System.Diagnostics.ProcessStartInfo psinfo = new ProcessStartInfo(batchFile);

System.Diagnostics.ProcessStartInfo psinfo = new ProcessStartInfo();
psInfo.FileName = batchFile

it seems to work. My batch file gets executed from the Windows service.

Has anyone else seen this? Does it make sense why it would work in the first case and not the second?
Thanks!
0

LVL 16

Accepted Solution

ToddBeaulieu earned 2000 total points
ID: 33560898
Well, there are differences in the StartInfo properties between the original example and the bare StartInfo (the verb, for instance, is empty), but I don't see any differences between the StartInfo object properties in these examples:

Process p2 = new Process();
p2.StartInfo = new ProcessStartInfo(app);

Process p3 = new Process();
p3.StartInfo.FileName = app;

Process p4 = new Process();
p4.StartInfo = new ProcessStartInfo();
p4.StartInfo.FileName = app;

bool result = p4.Start();

0

Author Closing Comment

ID: 33592379
I am closing this thread. Thanks everyone for the input.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Integration Management Part 2