Update: Thanks to uksza for the full set of state codes.
Originally I only knew about 1 and 4.
use Getopt::Long;
use Win32::Service;
use warnings;
my $hostname = ''; # this means local host.
my %services;
Win32::Service::GetServices($hostname,\%services);
my %svc = reverse %services; # so that it's keyed by service ID
my %state_code =
(
1 => 'not running',
2 => 'start pending',
3 => 'stop pending',
4 => 'running',
5 => 'resume pending',
6 => 'pause pending',
7 => 'paused'
);
sub status
{
my $func = shift; # 'status'
for my $svc ( map split(/,/), @_ )
{
my %info;
Win32::Service::GetStatus($hostname,$svc,\%info) or print("Err
+or - No service named '$svc'\n"), next;
print "Status of $svc:\n";
$svc{$svc} ne $svc and print "\tDescription: $svc{$svc}\n";
#printf "\tType: 0x%02X\n", $info{'ServiceType'};
print "\tState: ", $state_code{$info{'CurrentState'}} || $info
+{'CurrentState'} , "\n";
$info{'ProcessId'} and print "\tPID: $info{'ProcessId'}\n";
#$info{'ControlsAccepted'}
$info{'Win32ExitCode'} and print
"\tExited with code $info{'Win32ExitCode'}.\n";
$info{'ServiceSpecificExitCode'} and print
"\tExited with error; code $info{'ServiceSpecificExitCode'
+} was logged.\n";
$info{'WaitHint'} and print "\tApprox. $info{'WaitHint'} milli
+seconds until complete.\n";
$info{'CheckPoint'} and print "\tCheckpoint: $info{'CheckPoint
+'}\n";
print "\n";
}
}
sub list
{
for my $svc ( sort keys %svc )
{
my $descr = $svc{$svc};
{
my %info;
Win32::Service::GetStatus($hostname,$svc,\%info);
print "(@info{qw( CurrentState CheckPoint WaitHint )}) ";
}
print $svc;
$svc ne $descr and print qq( "$descr");
print "\n";
}
}
my %dispatch =
(
start => \&Win32::Service::StartService,
stop => \&Win32::Service::StopService,
pause => \&Win32::Service::PauseService,
resume => \&Win32::Service::ResumeService,
);
sub simple
{
my $func = shift;
for my $svc ( map split(/,/), @_ )
{
print "Attempting to $func $svc...\n\t";
print $dispatch{$func}->($hostname, $svc) ? "Success!\n" : "Fa
+ilure!\n";
}
}
sub prompt
{
my $func = shift;
my @prompts = map split(/\//), @_;
# Getopt::Long passes a single empty string if no argument is give
+n.
if ( @prompts < 1 or @prompts == 1 && $prompts[0] eq '' )
{
print "Press <Enter>: ";
}
else
{
print join("\n",@prompts), " press <Enter>: ";
}
scalar <>;
}
sub usage
{
die <<EOF;
Usage: $0 [options...]
Where options are one or more of the following:
--help : display this usage statement
--list : list all known services
--status LIST : display detailed status of the specified services
--start LIST : start the specified services
--stop LIST : stop the specified services
--pause LIST : pause (suspend) the specified services
--resume LIST : resume (unsuspend) the specified services
--prompt TEXT : present a prompt and wait for the <enter> key
You may give any option multiple times on the command line.
They are executed in the order given.
LIST is a comma-separated list of one or more service names.
You can use the --list option to get a list of known services.
Do NOT include whitespace; only commas!
The --prompt option is useful for scripting situations.
The prompt text is displayed and the program waits for the <Enter>
key to be pressed. The text "press <Enter>: " is appended to any
prompt string given as an argument. If no prompt string is given,
"Press <Enter>: " is used as default. You may create a multi-line
prompt by passing multiple slash-separated strings as an argument.
Example:
--stop SVC1 --prompt "SVC1 stopped."/"To start it," --start SVC1
This causes the following prompt to be displayed:
SVC1 stopped.
To start it, press <Enter>:
Any text entered by the user at the prompt is ignored.
EOF
}
sub extra
{
warn("\nWarning! Extra arguments passed and ignored!\n\t<@_>\nRun
+ with no options for a usage summary.\n");
}
@ARGV or usage();
GetOptions(
'list!' => \&list,
'status|get_status=s' => \&status,
'start=s' => \&simple,
'stop=s' => \&simple,
'pause=s' => \&simple,
'resume=s' => \&simple,
'prompt:s' => \&prompt,
'help!' => \&usage,
'<>' => \&extra,
) or usage();
We're building the house of the future together.