Solved

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

Posted on 2010-08-26
14
994 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
  • 6
  • 4
  • 2
  • +2
14 Comments
 
LVL 16

Expert Comment

by:Vikram Singh Saini
Comment Utility
0
 
LVL 1

Expert Comment

by:funazonki
Comment Utility
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
Comment Utility
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
 
LVL 1

Expert Comment

by:funazonki
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 16

Expert Comment

by:ToddBeaulieu
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
I am closing this thread. Thanks everyone for the input.
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
How can I use this extension method? 8 35
Image(2) 3 21
Image(7) 1 33
Set form below another form 3 25
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

743 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now