Why can't I start a batch file from a service using system() in Windows Server 2008?

1

I have a C++ program that runs as a service on a 64-bit Windows Server 2008 machine. This program attempts to start a batch file using the following command:

system(C:\pathtofile\file.bat)

In 32-bit Windows Server 2003 this worked fine (the batch file was executed), but on Windows Server 2008 the batch file is not executed and I get a return value of 0xC0000142 (I had the batch file write some text to a file as a test to see if it executed). I actually get that same return value even if I try to execute something that doesn't exist.

I read about Session 0 isolation in Windows Server 2008, so I used psexec to start a command prompt in Session 0 as the same domain user who is listed as the "Log On As" user for the service:

psexec -i 0 -u DOMAIN\serviceuser -p passwd cmd.exe

I was then able to successfully execute the batch file from the command prompt.

The domain user who is listed as the Log On As user for the service is in the Administrators group. Also if I start the C++ app manually (not as a service), it will start the batch file.

So is there something about Session 0 isolation that makes the system() call not work when the running as a service? Or some other explanation as to the change in behavior? I know that system() is not necessarily the best way to do this anyway, but I'm looking for the actual reason that this no longer works.

c++
windows
batch-file
service
session-0-isolation
asked on Stack Overflow Jan 23, 2014 by mattee

1 Answer

1

From what I now understand about the problem, the reason you can't run a batch file from a service using system() in Windows Server 2008 is because Windows considers any attempt to call cmd.exe (like it would do to run your batch file) as an attempt to launch an interactive service. Due to Session 0 isolation, this is not allowed and will just fail even though you might not think of your batch file as being interactive or having a GUI (which was throwing me off).

I figured out how to get the effect I was looking for using CreateProcess. The key here is that you must set the dwCreationFlags parameter to CREATE_NO_WINDOW. So my (simplified) call ended up looking something like this:

CreateProcess(NULL,   // No module name (use command line)
    L"C:\\Windows\\System32\\cmd.exe /C myfile.bat", // Call cmd.exe with /C flag
    NULL,           // Process handle not inheritable
    NULL,           // Thread handle not inheritable
    FALSE,          // Set handle inheritance to FALSE
    CREATE_NO_WINDOW,              // Use CREATE_NO_WINDOW!!!
    NULL,           // Use parent's environment block
    NULL,           // Use parent's starting directory 
    &si,            // Pointer to STARTUPINFO structure
    &pi )           // Pointer to PROCESS_INFORMATION structure
answered on Stack Overflow Jan 25, 2014 by mattee

User contributions licensed under CC BY-SA 3.0