#!/usr/bin/env perl use strict; use warnings; use File::Basename; use Cwd qw(abs_path getcwd); use Win32; use Win32::Daemon; use Cwd qw(abs_path getcwd); use File::Spec::Functions; # Get command line argument - if none passed, use empty string my $opt = $ARGV[0] || ""; my $path = $ARGV[1]; open(my $fh, ">>", "C:\\Users\\john\\test\\test.log"); select($fh); $|=1; print $fh "Running Test Service.\n"; print $fh "opt: $opt\n"; print $fh "path: $path\n"; # Check command line argument if ($opt =~ /^(-i|--install)$/i) { install_service(); } elsif ($opt =~ /^(-r|--remove)$/i) { remove_service(); } else { if (!$path) { print $fh "This program is intended to be run as a service.\n"; exit 1; } chdir $path; Win32::Daemon::RegisterCallbacks( { start => \&Callback_Start, running => \&Callback_Running, stop => \&Callback_Stop, pause => \&Callback_Pause, continue => \&Callback_Continue, } ); print $fh "Debug 1\n"; my %Context = ( last_state => SERVICE_STOPPED, start_time => time(), ); print $fh "Debug 2\n"; Win32::Daemon::AcceptedControls(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PARAMCHANGE | SERVICE_ACCEPT_NETBINDCHANGE); print $fh "Debug 3\n"; Win32::Daemon::StartService( \%Context, 1 * 1000); print $fh "Debug 4\n"; close STDERR; close STDOUT; } sub Callback_Running { my($Event, $Context) = @_; print $fh "SERVICE_RUNNING: " . SERVICE_RUNNING . "\n"; print $fh "SERVICE_CONTROL_TIMER: " . SERVICE_CONTROL_TIMER . "\n"; print $fh "State: " . Win32::Daemon::State() . "\n"; if(SERVICE_RUNNING == Win32::Daemon::State()) { # if(SERVICE_CONTROL_TIMER == Win32::Daemon::State()) { print $fh "Checking in.\n"; $Context->{last_state} = SERVICE_RUNNING; Win32::Daemon::State( SERVICE_RUNNING ); } } sub Callback_Start { my($Event, $Context) = @_; print $fh "Starting\n"; $Context->{last_state} = SERVICE_RUNNING; print $fh "DEBUG Set Context\n"; Win32::Daemon::State( SERVICE_RUNNING ); print $fh "DEBUG Set State\n"; } sub Callback_Pause { my($Event, $Context) = @_; print $fh "Paused.\n"; $Context->{last_state} = SERVICE_PAUSED; Win32::Daemon::State( SERVICE_PAUSED ); } sub Callback_Continue { my( $Event, $Context ) = @_; print $fh "Resumed running."; $Context->{last_state} = SERVICE_RUNNING; Win32::Daemon::State( SERVICE_RUNNING ); } sub Callback_Stop { my($Event, $Context) = @_; print $fh "Stopped.\n"; $Context->{last_state} = SERVICE_STOPPED; Win32::Daemon::State( SERVICE_STOPPED ); # We need to notify the Daemon that we want to stop callbacks and the service. Win32::Daemon::StopService(); } sub install_service { my ($path, $parameters); my $dir = getcwd; # Get the program's full filename, break it down into constituent parts my $fn = Win32::GetFullPathName($0); my ($cwd,$bn,$ext) = ( $fn =~ /^(.*\\)(.*)\.(.*)$/ ) [0..2] ; # Determine service's path to executable based on file extension if ($ext eq "pl") { # Source perl script - invoke perl interpreter $path = "\"$^X\""; # Parameters include extra @INC directories and perl script # @INC directories must not end in \ otherwise perl hangs my $inc = ($cwd =~ /^(.*?)[\\]?$/) [0]; $parameters = "-I " . "\"$inc\"" . " \"$fn\" \"myflag\" \"$dir\""; } else { # Invalid file type? die "Can not install service for $fn, file extension $ext not supported."; } my $sServiceName = "TestService"; # Populate the service configuration hash # The hash is required by Win32::Daemon::CreateService my %srv_config = ( name => $sServiceName, display => "Test Service ($sServiceName)", path => $path, description => "For debugging.", parameters => $parameters, service_type => SERVICE_WIN32_OWN_PROCESS, start_type => SERVICE_AUTO_START, ); # Install the service if (Win32::Daemon::CreateService(\%srv_config)) { print $fh "Test Service has been installed.\n"; } else { print $fh "Failed to install Test Service.\n"; } print $fh "Setting agent service to delayed start.\n"; print $fh "sc config $sServiceName start= delayed-auto\n"; print $fh `sc config $sServiceName start= delayed-auto` . "\n"; } sub remove_service { print $fh "Test Service is being removed.\n"; my $sServiceName = "TestService"; my $hostname = Win32::NodeName(); if (Win32::Daemon::DeleteService($sServiceName)) { print $fh "Test Service uninstalled successfully.\n"; } else { print $fh "Failed to uninstall Test Service.\n"; } }