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.

4444
  • 3,523
  • 10
  • 27
  • 43
Patrick Desjardins
  • 125,683
  • 80
  • 286
  • 335
  • @nzpcmad: Where on earth did you get the idea to change the OP's tag? – GEOCHET Dec 11 '08 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. – Michael Stum Dec 11 '08 at 22:06
  • @Michael: I don't see how that warrants /changing/ the OP's tag. – GEOCHET Dec 11 '08 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. – Patrick Desjardins Dec 11 '08 at 22:22
  • @Daok: I figured, but the tags are yours to decide anyway. – GEOCHET Dec 11 '08 at 22:30
  • 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. – kemiller2002 Dec 12 '08 at 00:32
  • I wonder if is has something to do with running the process as an interactive user. There is a flag in the security setting somewhere in 2k00 and 2k03 (I don't know about 08) that has to be set from some processes. I'll see if I can find it. – kemiller2002 Dec 12 '08 at 15:49
  • @Daok, any sample code with final solution – Kiquenet Jan 10 '11 at 15:42

8 Answers8

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.

solidau
  • 3,824
  • 1
  • 22
  • 40
kemiller2002
  • 107,653
  • 27
  • 187
  • 244
  • 1
    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 – LarryF Dec 11 '08 at 22:01
  • Let me give a try! I'll be back after. – Patrick Desjardins Dec 11 '08 at 22:15
  • 4
    Why are there no milliseconds in a second? – Jay Bazuzi Dec 11 '08 at 22:27
  • 1
    I guess NO is a shortcut for number in this context. – alexandrul Dec 11 '08 at 22:31
  • 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. – kemiller2002 Dec 12 '08 at 00:11
  • Can someone one explain me the waitforexit code. Why not just put the number of miliseconds to wait straight up ? – guiomie Nov 28 '11 at 19:13
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());
                }
            }
        }
    }
klev
  • 392
  • 4
  • 9
samir
  • 111
  • 1
  • 2
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.

suresh
  • 283
  • 2
  • 4
  • 14
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

LarryF
  • 4,617
  • 4
  • 27
  • 40
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?

Stephen Martin
  • 9,110
  • 3
  • 23
  • 34
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

LarryF
  • 4,617
  • 4
  • 27
  • 40
  • 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. – Patrick Desjardins Dec 13 '08 at 18:00
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...

Patrick Desjardins
  • 125,683
  • 80
  • 286
  • 335
  • 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 – Ana Betts Dec 13 '08 at 20:30
  • 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... – LarryF Dec 15 '08 at 23:56
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. ;)

GEOCHET
  • 20,623
  • 15
  • 71
  • 98
LarryF
  • 4,617
  • 4
  • 27
  • 40