18

I have a service that sometimes calls a batch file. The batch file takes 5-10 seconds to execute:

System.Diagnostics.Process proc = new System.Diagnostics.Process(); // Declare New Process
    proc.StartInfo.FileName = fileName;
    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    proc.StartInfo.CreateNoWindow = true;
    proc.Start();
    proc.WaitForExit();

The file does exist and the code works when I run the same code in-console. However when it runs inside the service, it hangs up at WaitForExit(). I have to kill the batch file from the Process in order to continue. (I am certain the file exists, as I can see it in the processes list.)

How can I fix this hang-up?

Update #1:

Kevin's code allows me to get output. One of my batch files is still hanging.

"C:\EnterpriseDB\Postgres\8.3\bin\pg_dump.exe" -i -h localhost -p 5432 -U postgres -F p -a -D -v -f "c:\backupcasecocher\backupdateevent2008.sql" -t "\"public\".\"dateevent\"" "DbTest"

The other batch file is:

"C:\EnterpriseDB\Postgres\8.3\bin\vacuumdb.exe" -U postgres -d DbTest

I have checked the path and the postgresql path is fine. The output directory does exist and still works outside the service. Any ideas?

Update #2:

Instead of the path of the batch file, I wrote the "C:\EnterpriseDB\Postgres\8.3\bin\pg_dump.exe" for the proc.StartInfo.FileName and added all parameters to proc.StartInfo.Arguments. The results are unchanged, but I see the pg_dump.exe in the process window. Again this only happens inside the service.

Update #3:

I have run the service with a user in the administrator group, to no avail. I restored null for the service's username and password

Update #4:

I created a simple service to write a trace in the event log and execute a batch file that contains "dir" in it. It will now hang at proc.Start(); - I tried changing the Account from LocalSystem to User and I set the admnistrator user and password, still nothing.

8
  • @nzpcmad: Where on earth did you get the idea to change the OP's tag? Commented Dec 11, 2008 at 21:57
  • I'm not nzpcmad, but my guess is: Since he says "I have a webservice", I assume that he has a Web Service (.asmx) and not a Windows Service. Commented Dec 11, 2008 at 22:06
  • @Michael: I don't see how that warrants /changing/ the OP's tag. Commented Dec 11, 2008 at 22:08
  • It's not webservice, I did write it at the first line humm might be very tired. The good one is "service". Sorry. Commented Dec 11, 2008 at 22:22
  • @Daok: I figured, but the tags are yours to decide anyway. Commented Dec 11, 2008 at 22:30

8 Answers 8

28

Here is what i use to execute batch files:

proc.StartInfo.FileName                 = target;
proc.StartInfo.RedirectStandardError    = true;
proc.StartInfo.RedirectStandardOutput   = true;
proc.StartInfo.UseShellExecute          = false;

proc.Start();

proc.WaitForExit
    (
        (timeout <= 0)
            ? int.MaxValue : timeout * NO_MILLISECONDS_IN_A_SECOND *
                NO_SECONDS_IN_A_MINUTE
    );

errorMessage = proc.StandardError.ReadToEnd();
proc.WaitForExit();

outputMessage = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();

I don't know if that will do the trick for you, but I don't have the problem of it hanging.

Sign up to request clarification or add additional context in comments.

6 Comments

Yea.. Do what Kevin says. He's redirecting the stderr and stdout like I mention, but one of the big differences is that he's setting "UseShellExecute" to false, which is something you have to consider when it comes to Vista... Good answer Kevin... Larry
Let me give a try! I'll be back after.
Why are there no milliseconds in a second?
I guess NO is a shortcut for number in this context.
I think it has something to do with the parameters on the batch file. I ran into that problem with mine and had to take them out. I ran out of time and had to come with a quick solution without them. I'll poke around tomorrow morning at work if no one has posted a solution.
|
11
using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    namespace VG
    {
        class VGe
        {
            [STAThread]
            static void Main(string[] args)
            {
                Process proc = null;
                try
                {                
                    string targetDir = string.Format(@"D:\adapters\setup");//this is where mybatch.bat lies
                    proc = new Process();
                    proc.StartInfo.WorkingDirectory = targetDir;
                    proc.StartInfo.FileName = "mybatch.bat";
                    proc.StartInfo.Arguments = string.Format("10");//this is argument
                    proc.StartInfo.CreateNoWindow = false;
                    proc.Start();
                    proc.WaitForExit();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception Occurred :{0},{1}", ex.Message,ex.StackTrace.ToString());
                }
            }
        }
    }

1 Comment

Pretty much what I had in the beginning, isn't it?
4
            string targetDir = string.Format(@"D:\");//PATH
            proc = new Process();
            proc.StartInfo.WorkingDirectory = targetDir;
            proc.StartInfo.FileName = "GetFiles.bat";
            proc.StartInfo.Arguments = string.Format("10");//argument
            proc.StartInfo.CreateNoWindow = false;
            proc.Start();
            proc.WaitForExit();

Tested,works clear.

Comments

3

What does the batch file do? Are you certain the process is getting launched with enough privs to execute the batch file? Services can be limited in what they are allowed to do.

Also make sure if you are doing something like usin the copy command to overwrite a file that you do something like:

echo Y | copy foo.log c:\backup\

Also, make sure you are using full paths for the batch commands, etc. If the batch file is launching a GUI app in some sort of "Console" mode, that may be an issue too. Remember, services don't have a "Desktop" (unless you enable the "interact with desktop") to draw any kind of windows or message boxes to. In your program, you might want to open the stdout and stderr pipes and read from them during execution in case you are getting any error messages or anything.

WebServices are probably executing as the IUSR account, or the anonymous account, which ever, so that might be an issue for you. If it works when you run it in console, that's just the first step. :)

I don't recall if System.Diagnostics. are available only in debug or not. Probably not, but some of them might be. I'll have to check up on that for ya.

Hope this gives you some ideas.

Larry

Comments

3

pg_dump.exe is probably prompting for user input. Does this database require authentication? Are you relying on any ENVIRONMENT variables that won't be present for the service? I don't know pg_dump but what are the other possible reasons it would prompt for input?

1 Comment

I can do this command from the command line of cmd.exe and it does work without prompting.
3

The next step I would take is to fire up the debugger, and see if you can tell what the program is waiting on. If you are expierenced at debugging in assembly, you may be able to get an IDEA of what's happening using tools like ProcExp, FileMon, etc.

Being a windows SERVICE, and not a web service, makes quite a bit of difference. Anyways, have you tried my suggestion of setting the "Allow Service to interact with desktop"?

If you are desperate, you might try launching cmd.exe instead of your batch file. Then, using the cmd.exe's cmd line parameters, you can have IT start the batch file. This would probably give you a cmd prompt window to view the actual output, if you turn on the interact with desktop.

For complete help on cmd.exe, just type cmd /? at any command prompt.

Larry

1 Comment

Now the batch file contain only "dir". I have create a solution outside the real project and I am trying to execute. It still hang. The last log I have is just before the proc.Start() method.
1

Here is the solution. The solution is not clear because I have changed so many time the code and now it's working!

I have tried to use a Account of User, and it's not what worked. Use LocalSystem. Here is the code that execute, mostly what Kevin gave me.

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = fileName;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;


            proc.Start();
            proc.WaitForExit();
            output1 = proc.StandardError.ReadToEnd();
            proc.WaitForExit();
            output2 = proc.StandardOutput.ReadToEnd();
            proc.WaitForExit();

Thank you all, I'll up-vote everybody and accept Kevin since he helps me since the beginning. Very weird because it works now...

2 Comments

This is well and good if you're just doing a one-off thing, but please don't ship software that runs scripts as Local System, it is very hard to secure
Yea. Instead, make them execute ActiveScript, so the attacker can at least use vbScript to get the ball rolling... :) (Of course, you guys all have to know I'm just kiddding. I'm glad he found his solution, just mad that Kevin got it right first. hehe..) :) J/K AGAIN. No one get mad at me now...
1

Daok, it looks as if the only thing you changed was the timeout period on the initial WaitForExit(). You need to be VERY careful of that. If something DOES hang your service, it will NEVER return (and well, pretty much work like it has been for you thus far.. heh), but it won't be good for the end users...

Now, perhaps that you know what's causing this to hang, you can debug it further and find the full solution...

That, or spin this off in some thread that you can monitor, and kill if it hangs too long.

Just my 2 cents worth, which usually isn't a whole lot. ;)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.