http://qs1969.pair.com?node_id=522586

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.

Replies are listed 'Best First'.
Re: Control and Query Win32 Services at the command line
by uksza (Canon) on Jan 12, 2006 at 08:38 UTC
    How nice!

    I was going to write something like this today.
    Thanks!

    Update:
    I've got something intresting:
    my %state_code = ( '1' => 'stopped.', '2' => 'start pending.', '3' => 'stop pending.', '4' => 'running.', '5' => 'continue pending.', '6' => 'pause pending.', '7' => 'paused.' );

    greetz, Uksza

    Yes, smart people know that fat arrow autoquotes the left argument. But why should you require your code to be maintained by smart people?
    Randal L. Schwartz, Perl hacker

      Thanks! That is great information.
      I tried to find it on the web, but every resource I found only referred to the values by their symbolic names. :-(

      We're building the house of the future together.
Re: Control and Query Win32 Services at the command line
by NetWallah (Canon) on Jan 12, 2006 at 22:05 UTC
    This looks like a rewrite of the NETSVC command from the Win2K resource kit, but it is missing the "remote host" option, that allows you to control services on other machines. Your code appears to prepared to easily include that option too.
    NETSVC.exe (Resource Kit) Command-line Service Controller. Start, Stop and Query services, but d +oes not cover creating or deleting them. Although part of the Windows 2000 resource kit - this command runs fin +e under NT 4. Syntax NETSVC \\server command servicename Key server The workstation or server where the service is runnin +g servicename The Name of the service, unlike the SC command this w +ill accept either the DisplayName or the service name commands: /list Lists installed services. Omit servicename with this + command. /query Query the status of a service. /start Start the specified service. /stop Stop the specified service. /pause Pause the specified service. /continue Restart a paused service. Arguments can be specified in any order: NETSVC /query \\Server299 "DHCP Client" NETSVC "DHCP Client" \\Server299 /query

         You're just jealous cause the voices are only talking to me.

         No trees were killed in the sending of this message.    However, a large number of electrons were terribly inconvenienced.

      Surely. Of course the same thing could be done using the standard M$ tools.

      But: a. this is Perl, which means it's better;-) and b. you can write a whole stop/wait/start or pause/wait/resume script on one line, even for a chain of dependent services. Heck, you could even use it as a "better pause" command. :-)

      We're building the house of the future together.