chris212 has asked for the wisdom of the Perl Monks concerning the following question:

When I run my script from a command-line, the output is redirected to a file like it should. When it runs as a Windows service, it does not. When "install" is passed as an argument, it will create a service as the same name as the script file. The output should be redirected to a log file in the same name as the script (.log instead of .pl) in the same directory.

use strict; use IPC::Run ('run'); use Win32::Daemon; use Cwd 'abs_path'; my $script = abs_path($0); my $logfile = $script; $logfile =~ s/\.[^\.\\\/]*$/.log/; my $svcname = $script; $svcname =~ s/^.*[\/\\]//g; $svcname =~ s/\.[^\.]*$//; if($ARGV[0] eq 'install') { my %service_info = ( machine => '', name => $svcname, display => $svcname, path => $^X, user => '', pwd => '', description => 'test case', parameters => $script ); if( Win32::Daemon::CreateService( \%service_info ) ) { print "Successfully added.\n"; } else { print "Failed to add service: " . Win32::FormatMessage( Win32: +:Daemon::GetLastError() ) . "\n"; } exit; } Win32::Daemon::StartService(); open(LOG,'>>',$logfile) or die("Failed to write to logfile\n$!\n"); Win32::Daemon::State( Win32::Daemon->SERVICE_RUNNING ); print "Run ping...\n"; print LOG localtime()."\n"; run(['ping','-n','5','127.0.0.1'],'>&',\*LOG); my $ec = $? >> 8; print LOG "Exit Code $ec\n\n"; close(LOG); print "Exit Code $ec\n"; Win32::Daemon::StopService();

Is this a IPC::Run bug, a Win32::Daemon bug, or am I doing something wrong? Thanks.

UPDATE:

I found that this bug only seems to affect the process start as a service. Child processes started by that process will work correctly. Also, if you close STDOUT, you will see the same behavior from the command line.

UPDATE 2:

Since child processes are not affected, I was going to ignore this bug. However, since Win32::Daemon can no longer handle shutdowns properly, that kind of defeats the purpose of converting it to a service, so all of this effort has been wasted.

Replies are listed 'Best First'.
Re: Win32::Daemon + IPC::Run redirect problem
by Marshall (Canon) on May 05, 2017 at 23:12 UTC
    I was able to run this "sort of". I am having a bit of trouble with getting right module for use IPC::Run ('run'); so I just commented that out as well as the ping further down in the code.

    Installation:

    C:\Projects_Perl\testing>perl serva.pl install service name: serva Log file: C:\Projects_Perl\testing\serva.log Successfully added.
    So far so good, I added printout to make sure service name and log file name were ok.

    Now starting service:

    C:\Projects_Perl\testing>net start serva The serva service is starting. The serva service could not be started. The service did not report an error. More help is available by typing NET HELPMSG 3534. C:\Projects_Perl\testing>type serva.log Fri May 5 15:57:50 2017 Exit Code 0 Run this service... Fri May 5 15:59:22 2017 Exit Code 0
    The error reported from net start is that "serva" didn't start, but I can see from the serva.log file that it actually did something!

    Of course, none of the print statements to the console, like print "Run ping...\n"; are going to do anything. You can only print LOG ... A Service (a daemon) does not any connection to a console. Not sure why it net says service didn't start, but then again, you stop yourself which is an odd thing for a service to do.

    Update: I did look with the Service GUI. Installation looks fine. automatic start, currently stopped, no actions on failure. Error message for GUI "Start" had more info than I would have thought: "The serva service on Local Computer started and then stopped. Some services stop automatically if they have no work to do, for example Performance Logs and Alerts service". Looks like the issue is with how you are running ping?

    Update I am no sure why I couldn't get run3 to work when running a service. I did try just using backticks and that appears to work, see readmore... for some small modifications.

      Yes, IPC::Run and IPC::Run3 will not redirect. I know I can use backticks, but in some cases I need the additional functionality offered by IPC::Run, and I don't want to sacrifice that functionality to make it run as a service.
Re: Win32::Daemon + IPC::Run redirect problem
by 1nickt (Canon) on May 05, 2017 at 19:41 UTC

    It's difficult to see how you will reach the part where you start a service after you

    exit;
    in the if block ...

    Hope this helps!


    The way forward always starts with a minimal test.
      It isn't supposed to START a service if you pass the "install" argument, it is supposed to INSTALL the service. You can start the service from the services.msc control panel. Or you can run the script from the command-line with no arguments to see it actually run like it is supposed to (redirect ping output).
      To maybe clarify a bit more about what the OP said...

      The OP combined the Windows "Service installation program" and the "Service itself" into one file. This is fine although often this would be 2 separate programs. The installation option makes entries into the Windows Registry about this new service and then exits - that is all it does.

      A Windows service is like a unix daemon. This is a process that runs "in the background" with no connection to a command line terminal. There are many examples of things like that. A database server would be an example.

      I have verified that the installation part "works". The service is "installed" and looks normal to the Windows O/S. I can start the service with the "net start" command or from the GUI.

      The issue here is how to run an external program and get its result from the Service environment? The service is not started from a command line shell and doesn't have connections to STDOUT,STDERR,STDIN. I found that I could use backticks to run the ping program and get the output of ping although I was not able to get ping to work with run() or run3().

      So I found a way to get ping into the Service's log, but this is only a partial solution. This is an question about the environment that the service is running in.

        Yes, I found the same (IPC::Run and IPC::Run3 cannot redirect, backticks and system can). The issue is I was looking at making a Perl script a service which would call other scripts (components). Many of which will use IPC::Run. I don't want to have to convert all the components which use IPC::Run losing the benefits of that module which are probably needed in some cases, and I don't want to impose a limitation on components due to running as a service. Unless there is an easy workaround or a bug fix on the horizon to avoid losing any component functionality, I don't think this is worth me pursuing.