Solved

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

Posted on 2010-08-26
14
1,001 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 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
Learn by Doing. Anytime. Anywhere.

Do you like to learn by doing?
Our labs and exercises give you the chance to do just that: Learn by performing actions on real environments.

Hands-on, scenario-based labs give you experience on real environments provided by us so you don't have to worry about breaking anything.

 
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

Prepare for your VMware VCP6-DCV exam.

Josh Coen and Jason Langer have prepared the latest edition of VCP study guide. Both authors have been working in the IT field for more than a decade, and both hold VMware certifications. This 163-page guide covers all 10 of the exam blueprint sections.

Question has a verified solution.

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

Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
In this video, viewers are given an introduction to using the Windows 10 Snipping Tool, how to quickly locate it when it's needed and also how make it always available with a single click of a mouse button, by pinning it to the Desktop Task Bar. Int…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

627 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