Greetings fellow monks.

I recently had to throw together a script which would kick-start a Windows service (scheduler).

This was due to a particularly overzealous IT department's user group policy disabling user-initiated services at seemingly random intervals.

Of course I'm too lazy to write timing into my all of my scripts. And I'm yearning for cron-like functionality. So here's what I put together:

# /usr/bin/perl # child process to background # poll windows service (scheduler) and re-enable + start use Win32::Service; use Win32::OLE; use strict; # set logfile location my $logfile = 'log.txt'; my ($key, %service, %status); while (1) { Win32::Service::GetStatus('','Schedule', \%status); if (!($status{CurrentState} == 4)) { # service probably disabled, set to automatic again set_starttype('automatic','schedule'); Win32::Service::StartService('', 'Schedule') || die "could not + start service: $!\n"; open(LOG, '>>', $logfile); print LOG currtime() . "\tscheduler stop detected, restarted t +he service\n"; close LOG; } sleep(60); } # culled/tweaked from: http://unattended.sourceforge.net/ sub set_starttype { my ($type, $service_name) = @_; # Convert to lower-case $type = lc $type; $service_name = lc $service_name; my %types = map { (lc $_ => $_) } ('Boot', 'System', 'Automatic', 'Manual', 'Disabled'); (exists $types{$type}) or die '<type> must be one of ', join ' ', keys %types; # Bomb out completely if COM engine encounters any trouble. Win32::OLE->Option ('Warn' => 3); # Get a handle to the SWbemServices object of the local machine. my $computer = Win32::OLE->GetObject ('WinMgmts:'); # Get the SWbemObjectSet of all services. See: # http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_service +.asp my $services_set = $computer->InstancesOf ('Win32_Service'); # Convert set to a Perl array. my @services = Win32::OLE::Enum->All ($services_set); foreach my $service (@services) { my $name = $service->{'Name'}; my $display_name = $service->{'DisplayName'}; if (($service_name eq lc $name) || ($service_name eq lc $display_name)) { print "Setting mode for $name ($display_name) to $types{$t +ype}..."; my $ret = $service->ChangeStartMode ($types{$type}); $ret == 0 or die "Unable to ChangeStartMode to $types{$type}: $r +et"; print "done.\n"; } } } sub currtime { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localti +me(time); return sprintf("[%02u/%02u/%u %02u:%02u:%02u]", $mon + 1, $mday, $ +year + 1900, $hour, $min, $sec); }

Fork+exec it into the background and it's smooth sailing. Should note that polling frequency should be less than script frequency. I hope that someone will find it useful!

Replies are listed 'Best First'.
Re: Auto-Restarting Windows Services
by bulk88 (Priest) on Apr 04, 2012 at 09:06 UTC
    Why poll instead of using Win32::Process and WaitForSingleObject on a process handle or this is a service which runs inside svchost.exe?

      This particular machine is XP, which I believe runs task scheduler inside svchost.exe

      If it were Vista or 7 task scheduler does have a separate process which I could (and should!) do what you're suggesting.

      (someone more knowledgeable correct me if I'm wrong here)