Solved

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

Posted on 2010-08-26
14
1,000 Views
Last Modified: 2013-11-08
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
Comment
Question by:KimberleyY
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 2
  • +2
14 Comments
 
LVL 16

Expert Comment

by:Vikram Singh Saini
ID: 33538650
0
 
LVL 1

Expert Comment

by:funazonki
ID: 33543339
This worked for me -

        private bool RunCmd(
            string app,
            string workingDirectory,
            string cmd,
            DataReceivedEventHandler outData,
            DataReceivedEventHandler errorData,
            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.OutputDataReceived += outData;
                RunCmdProcess.ErrorDataReceived += errorData;
                RunCmdProcess.Exited += proc_Exited;
                RunCmdProcess.BeginOutputReadLine();
                RunCmdProcess.BeginErrorReadLine();
                InputStream = RunCmdProcess.StandardInput;
            }
            catch (Exception ex)
            {
                // do some logging
                return false;
            }
            return true;
        }
0
 

Author Comment

by:KimberleyY
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();
                process1.BeginOutputReadLine();
                process1.BeginErrorReadLine();

            }
            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
How Do You Stack Up Against Your Peers?

With today’s modern enterprise so dependent on digital infrastructures, the impact of major incidents has increased dramatically. Grab the report now to gain insight into how your organization ranks against your peers and learn best-in-class strategies to resolve incidents.

 
LVL 1

Expert Comment

by:funazonki
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

by:ToddBeaulieu
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...");
			Console.ReadKey();
		}
	}

	private static void WL(object text, params object[] args)
	{
		Console.WriteLine(text.ToString(), args);	
	}
	
	private static void RL()
	{
		Console.ReadLine();	
	}
	
	private static void Break() 
	{
		System.Diagnostics.Debugger.Break();
	}

	#endregion
}

Open in new window

0
 

Author Comment

by:KimberleyY
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

by:ToddBeaulieu
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

by:ToddBeaulieu
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

by:KimberleyY
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

by:avarmaavarma
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

by:KimberleyY
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

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

instead of
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

by:
ToddBeaulieu earned 500 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

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

Featured Post

Forrester Webinar: xMatters Delivers 261% ROI

Guest speaker Dean Davison, Forrester Principal Consultant, explains how a Fortune 500 communication company using xMatters found these results: Achieved a 261% ROI, Experienced $753,280 in net present value benefits over 3 years and Reduced MTTR by 91% for tier 1 incidents.

Question has a verified solution.

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

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question