Windows scheduled tasks: no output logged when running an EXE

At work I have a number of scheduled tasks set up to run on Windows servers (2008 R2). The majority of these are set up to run .bat or .cmd files which execute Java code, and the scheduled tasks are set up with arguments to log the output to a log file with an argument like

>> batchoutput.log 2>&1

so that the output is appended to the log file each time the job runs.

I have a couple of jobs that are .NET console applications rather than Java. So for these I set the scheduled task to run the exe file directly, but with the same argument to log the output to a log file. When I run these jobs, it does not create a log file, and no output is logged.

However, I have discovered that if I create a cmd file to call the executable, and have the scheduled task run the command file, then I get my log file as expected.

So why doesn’t my output go to a log file when I have the scheduled task run the executable directly?

It’s a weird thing with Microsoft, where they recommend that programs that are not run from the console/command line do not have any output. Your redirects still work, but the .NET programs aren’t creating any output.

Putting them in a CMD or BAT file counts as running from console, so the programs now have output.

If you are annoyed by the console windows popping up, I would suggest using a WScript file, and launching the console in a hidden window. Google for more information.

It doesn’t bother me if a console window opens or not. These are jobs normally running unattended on a server, but sometimes we need to check the output in the log files. And I just thought having to run the exe indirectly through a bat or cmd file to get the output was kind of a clunky way to have to set it up.

And yes, if I run the exe manually in a command window, I definitely see the output. So I knew the application was generating output as expected, just couldn’t figure out why the log file was not getting created.

I guess a better way to do this would be to have the application write output to a text file rather than to a console (or do both). Then I don’t have to worry about having the scheduled task log the output.

STDIN, STDOUT and STDERR plus the >> or > redirect capability are features of cmd.exe. Not features of the OS itself.

.NET has nothing specific to do with your issue. You’d get the exact same behavior whether you run a .NET-based exe file or a conventional Win32/Win64 exe file.

As such, when you’re sitting at a CMD window and type


C:\>Myapp.exe >>J:\blah\blah\Logfile.txt

The >Logfile.txt redirection is performed by CMD.exe. Your myapp.exe receives no arguments at all. Cmd.exe passed myapp.exe file handles for STDIN, STDOUT, and STDERR, and myapp.exe blindly writes its output to the handles provided. With no knowledge of where that goes.

Absent CMD.exe, when you launch myapp.exe directly as a subprocess of another app, the task scheduler, the Windows Run dialog box, etc., the OS provides dummy file handles for STDIN, STDOUT and STDERR that go nowhere. Any effort by the app to read STDIN returns EOF immediately, and any attempt to write to STDOUT or STDERR returns a success result code immediately without sending the data anywhere.
So that’s why you see the results you do. Here’s what to do about it:
As you’ve seen one workaround is to launch cmd.exe to have it perform the redirection and in turn launch your exe.

Embedding the call to myapp.exe in a .bat or .cmd file amounts to the same thing. The OS knows .bat & .cmd files require cmd.exe to interpret them. So it starts CMD.exe and passes a ref to the .bat or .cmd file to CMD.exe. CMD.exe then reads the .bat or .cmd file and interprets each line. Including the line that specifies some redirection along with running myapp.exe.

The other alternative is to design your app(s) to parse and follow additional parameters to specify where to log to and whether to append or overwrite. e.g.


C:\>myapp.exe param1 param2 param3 /Logfile:J:\blah\blah\Logfile.txt /Appendmode:Y

But that means your app must have code to parse these arguments, create or open those files, etc. Ideally you’d design all your .exes to use the same parameter syntax so you’re not creating a maintenance nightmare for the people who create the scripts and tasks.

Ah. My bad. I thought the redirects still worked.

I’m still sure there is a standard about not logging any data to console, though. It came up with Firefox, and people were upset about it. Firefox had made it where even the /? command didn’t output anything unless fed through a pipe.

There’s a Windows design standard that separates exe’s into two broad types: ones that expect to run under cmd.exe (so-called “console apps”), and those that expect to run directly under OS control with access to the GUI (so-called “Windows apps” or “native apps”)*.

It’s considered very poor form to cross the beams. A console app should never try to launch a window, and a windows app should never try to write to the three STD* file handles. It’s technologically possible to commit either sin under both .Net & conventional Win32/64 APIs. But it’s a major design stink.

  • In the spirit of completeness, there’s a second sub-type of windows/native app called a “Windows service”. These run directly under OS control but *should *make no access to the GUI or the human input devices (mouse, keyboard, touch, etc). Again it’s technologically possible to violate this contract. Usually with very bad results. So don’t do that either.

OK, I think I understand now. So when I set the scheduled task to run “myprogram.exe” and have the arguments for the scheduled task set to “>>logfile.txt”, that argument is getting passed to “myprogram.exe” (but ignored, because the program isn’t looking for command line arguments.)

But creating a cmd file to execute “myprogram.exe”, and having the scheduled task run the cmd file, changes the situation so that the argument “>>logfile.txt” is now applied to the command session created when the cmd file is run, which redirects the output of the cmd file (including the output of myprogram.exe) to the log file.

Exactly.

If you only need the cmd file to run just the one app one time you can leave out one step.

Have task manager execute this string: cmd.exe /c “myapp.exe >> logfile.txt”

That has the effect of telling cmd.exe to run and perform just the quoted string after the /c.

There are other switches applicable to cmd.exe to control the starting drive/folder and other stuff. All this is documented at msft.

You may find this helpful since you don’t need a pile of one line cmd files to act as adapters. OTOH, this moves a lot of the operating logic into the task manager GUI where it’s harder to track and manage and version control and … versus keeping all stuff in a collection of cmd files in a single dedicated folder.