Reputation: 368
Here is the script for checking status of windows services and if they are in stop state, it will start the service. I can able to get the status of service, but can't able to start services. please help and let me know what I need to do.
#!/usr/local/bin/perl
use Win32::Service;
use strict;
sub checkService();
sub getDate();
sub getTime();
sub logEvent();
my @timeInfo = localtime(time);
my $serviceName = "TapiSrv";
my $currentDate = getDate();
my $currentTime = getTime();
my %status;
my %status_code = (1 => 'not running',
2 => 'start pending',
3 => 'stop pending',
4 => 'running',
5 => 'resume pending',
6 => 'pause pending',
7 => 'paused');
checkService();
########
# SUBS
########
sub checkService() {
my $startCounter = 0;
Win32::Service::GetStatus('', $serviceName, \%status);
if($status{"CurrentState"} eq '4') {
# Log the event
&logEvent("$currentTime: $serviceName is running\n");
} elsif($status{"CurrentState"} eq '1') {
Win32::Service::StartService('', $serviceName);
}
while($startCounter < 3) {
sleep(5);
Win32::Service::GetStatus('', $serviceName, \%status);
if($status{"CurrentState"} eq '2') {
$startCounter++;
} else {
$startCounter = 3;
}
}
if($startCounter == 3) {
&logEvent("$currentTime: Unable to start $serviceName in $startCounter attempts\n");
} else {
&logEvent("$currentTime: Started $serviceName in $startCounter attempts\n");
}
}
sub getDate() {
my $year = $timeInfo[5] + 1900;
my $month = $timeInfo[4] + 1;
my $day = $timeInfo[3];
return sprintf("%04d-%02d-%02d", $year, $month, $day);
}
sub getTime() {
my $hour = $timeInfo[2];
my $min = $timeInfo[1];
my $sec = $timeInfo[0];
return sprintf("%02d:%02d:%02d", $hour, $min, $sec);
}
sub logEvent() {
# Log the event
open(OUT, ">> C:/servicestatus/$currentDate.txt");
print OUT "$_[0]";
close(OUT);
}
Upvotes: 0
Views: 5119
Reputation: 1068
One major problem I have with this Win32::Service module is that it returns undef on failure BUT doesn't set $! so finding out why it failed is more work. I have not done any testing in retrieving that error, but it's probably a call to one of the functions in the Win32 module.
#!/usr/local/bin/perl
use 5.010;
use strict;
use warnings;
use POSIX qw(strftime);
use Win32::Service qw(StartService GetStatus GetServices);
my $service = shift || 'Apple Mobile Device';
check_service($service);
exit;
###############################################################################
sub check_service {
my $service = shift;
my %status_code = (
Stopped => 1,
StartPending => 2,
StopPending => 3,
Running => 4,
ResumePending => 5,
PausePending => 6,
Paused => 7
);
my (%status, %services);
GetServices('', \%services) or do {
log_event('Failed to retieve list of services');
exit;
};
%services = reverse %services;
if (! exists $services{$service}) {
log_event("'$service' is not a configured Windows service");
exit;
}
if (GetStatus('', $service, \%status)) {
if ($status{"CurrentState"} eq $status_code{Running} ) {
log_event("$service is running");
}
elsif ( $status{"CurrentState"} eq $status_code{'Stopped'} ) {
ATTEMPT: for (1..3) {
log_event("Attempting to start '$service'");
if (StartService('', $service)) {
sleep 5;
GetStatus('', $service, \%status);
if ($status{"CurrentState"} eq $status_code{Running}) {
log_event("Started '$service'");
last ATTEMPT;
}
}
else {
die "StartService() function failed";
}
}
}
}
else {
log_event("failed to retrieve the status of service '$service'");
exit;
}
return;
}
sub log_event {
# Using one of the better loging modules such as Log::Log4perl
# would be a much better and more robust logging mechanism
my $msg = shift;
my $timestamp = strftime("%H:%M:%S", localtime);
my $filename = strftime("C:/servicestatus/%Y-%m-%d.txt", localtime);
open(my $fh, '>>', $filename) or die "failed to open '$filename' <$!>";
say $fh "$timestamp: $msg";
close $fh;
return;
}
Upvotes: 1
Reputation: 2393
Based upon some comments below (including some nice points by @Ron Bergin), I'm revising this post to show code that works for me (Windows 8.1, ActivePerl 5.16).
#!/usr/local/bin/perl
use strict;
use warnings;
use POSIX;
use Win32::Service;
my $currentDate = getDate();
my %status;
my %status_code = (
Stopped => 1,
StartPending => 2,
StopPending => 3,
Running => 4,
ResumePending => 5,
PausePending => 6,
Paused => 7
);
checkService("Apple Mobile Device");
########
# SUBS
########
sub checkService {
my $serviceName = shift || die "No arg passed";
my $startCounter = 1;
Win32::Service::GetStatus('', $serviceName, \%status);
if ($status{"CurrentState"} eq $status_code{Running}) {
logEvent("$serviceName is running\n");
}
elsif ($status{"CurrentState"} eq $status_code{'Stopped'}) {
my $maxAttempts = 3;
while ($startCounter <= $maxAttempts) {
logEvent("Attempting to start $serviceName");
Win32::Service::StartService('', $serviceName);
sleep(5);
Win32::Service::GetStatus('', $serviceName, \%status);
if ($status{"CurrentState"} eq $status_code{Running}) {
logEvent("Started $serviceName in $startCounter attempts\n");
last;
}
$startCounter++;
}
if ($startCounter eq $maxAttempts) {
logEvent("Unable to start $serviceName in $startCounter attempts\n");
}
}
}
sub getDate {
my @timeInfo = localtime(time);
my $year = $timeInfo[5] + 1900;
my $month = $timeInfo[4] + 1;
my $day = $timeInfo[3];
return sprintf("%04d-%02d-%02d", $year, $month, $day);
}
sub logEvent {
my $msg = strftime("%H:%M:%S", localtime) . ": $_[0]\n";
print "$msg";
open(OUT, ">> C:/servicestatus/$currentDate.txt");
print OUT "$msg";
close(OUT);
}
Running this NOT as an admin, gives output like this:
14:11:30: Attempting to start Apple Mobile Device
14:11:35: Attempting to start Apple Mobile Device
14:11:40: Attempting to start Apple Mobile Device
Running as an admin looks like this:
14:14:29: Attempting to start Apple Mobile Device
14:14:34: Started Apple Mobile Device in 1 attempts
Upvotes: 2