# chksvc.pl checks if specified service is running on remote NT computers # and stops or restarts the service if so instructed. # # Written 21-dec-2000 by fgb. # Mod 18-jan-2001, fgb: added SetStartupType to change startup type. # # Usage: chksvc.pl service computerfile [/stop | /restart] [/type=auto|manual] # where computerfile contains list of remote computer names. require "ctime.pl"; use Net::Ping; use Win32::Registry; use Win32::Service; $bDebug = 0; MAIN: $sAppName = "chkSvc"; $sDate = &ctime(time); $bNotify = 0; $bRestart = 0; $nResult = 0; $sRptFile = "$sAppName.rpt"; my $ss; $sStartupType = "x"; $bStop = 0; $sTempFile = "t.t"; $sTmp = ""; $sToday = substr($sDate,4); $nTotalComputers = 0; $nTotalRestarted = 0; $nTotalStopped = 0; $bUseRptFile = 0; $bVerbose = 0; $sVersion = "1.1"; unless ($#ARGV + 1) { die "Missing data file on command line.\n"; # somebody give me an arg! } $sService = $ARGV[0]; $sMachineFile = $ARGV[1]; ParseCmdArgs(); # must FOLLOW any arg use! if ($bDebug) { $bVerbose = 1; } print "$sAppName $sVersion\n"; # Check each computer: open(FPCDATA,$sMachineFile) || die "Can't open file $sMachineFile: $!\n"; if ($bUseRptFile) { $sTmp = sprintf(">%s",$sRptFile); if ($bDebug) { print "sTmp = $sTmp\n"; } open(RPTFILE,$sTmp) || die "Can't open file $sRptFile: $!\n"; print RPTFILE "$sAppName $sVersion report generated at $sToday\n\n"; } while () { if (!/^\!/) { # skip comments chop $_; s/\s(.*)//; # remove whitespace s/^\\\\//; # remove leading '\\' $sComputer = $_; if (&IsVis()) { $ss = &IsServiceRunning(); if ($ss == -1) { if ($bVerbose) { print "$sService not installed on $sComputer\n"; } next; } if ($bVerbose) { print "$sService "; unless ($ss) { print "not "; } print "running on $sComputer\n"; } unless ($ss) { if ($bRestart) { Win32::Service::StartService($sComputer,$sService); ++$nTotalRestarted; if ($bVerbose) { print "$sService restarted on $sComputer\n"; } } } else { if ($bStop) { Win32::Service::StopService($sComputer,$sService); ++$nTotalStopped; if ($bVerbose) { print "$sService stopped on $sComputer\n"; } } } if ($sStartupType ne "x") { $nResult = SetStartupType($sStartupType); if ($bVerbose && $nResult) { print "Set $sService startup type to $sStartupType\n"; } } } ++$nTotalComputers; unless ($bVerbose) { print "."; } } } close(FPCDATA); print "\n$sAppName: checked $nTotalComputers computers.\n"; if ($nTotalStopped > 0) { $sTmp = "Stopped service on $nTotalStopped machines!\n"; } if ($nTotalRestarted > 0) { $sTmp = "Restarted service on $nTotalRestarted machines!\n"; } print $sTmp; if ($bUseRptFile) { print RPTFILE $sTmp; close(RPTFILE); } if ($bNotify) { Notify(); } if ($nTotalStopped == 0 && $nTotalRestarted == 0) { print "All is well.\n"; if ($bUseRptFile) { # no problems found, so unlink $sRptFile; # delete empty rpt file } } ########### subroutines eh? ############ sub IsServiceRunning { my %status; Win32::Service::GetStatus($sComputer,$sService,\%status); if ($bDebug) { print "status of $sService = $status{'CurrentState'}\n"; } if ($status{'CurrentState'} == 2 || $status{'CurrentState'} == 4 || $status{'CurrentState'} == 5) { return 1; } else { if ($status{'CurrentState'} == "") { return -1; } # service not installed else { return 0; } } ######## # 1= "Stopped" # 2= "Start_Pending" # 3= "Stop_Pending" # 4= "Running" # 5= "Continue_Pending" # 6= "Pause_Pending" # 7= "Paused" ######## } sub Help { printf("%s version %s\n",$sAppName,$sVersion); printf("\nUsage: %s service computerlist [options]\n",$sAppName); print "\nOptions: /output=filename <-- save output to a file\n"; print " /restart\n"; print " /stop\n"; print " /type= <-- auto or manual\n"; print " /notify <-- email output (if bad)\n"; } sub IsVis { $p = Net::Ping->new("icmp"); return ($p->ping($sComputer,1)); } sub Notify { @Recipients = ('frank.brown','john.doe','jane.addams'); $sMailDomain = "my.com"; print "Sending email...\n"; foreach $sName (@Recipients) { $sToList .= sprintf("%s\@%s,",$sName,$sMailDomain); } chop($sToList); # chop last comma from recipient list $sCmd = sprintf("blat %s -t %s -s \"service %s\"",$sRptFile,$sToList,$sService); if ($bDebug) { print "dbg: $sCmd\n"; } else { system($sCmd); } } sub ParseCmdArgs { while (@ARGV) { $_ = shift @ARGV; if ($bDebug) { print "dbg: parsing $_\n"; } if (/^[\/\-]/) { # is arg a switch? $arg = substr($_,1,3); # parse 1st 3 chars: if ($arg eq "deb") { $bDebug = 1; } if ($arg eq "res") { $bRestart = 1; } if ($arg eq "sto") { $bStop = 1; } if ($arg eq "typ") { $i = index($_,"="); $i++; $sStartupType = sprintf("%s",substr($_,$i)); } if ($arg eq "not") { $bNotify = 1; $bUseRptFile = 1; # need file to email to recipients } if (($arg eq "hel") || (substr($arg,0,1) eq "?")) { &Help(); exit; } if ($arg eq "out") { $i = index($_,"="); $i++; $sRptFile = sprintf("%s",substr($_,$i)); if ($sRptFile eq $sTempFile) { $sRptFile .= "2"; # prevent dup filename } $bUseRptFile = 1; } } } if ($bDebug) { print "dbg: sStartupType = $sStartupType\n"; print "dbg: bNotify = $bNotify\n"; print "dbg: sRptFile = $sRptFile\n"; print "dbg: bUseRptFile = $bUseRptFile\n"; } } sub SetStartupType { local $sType = substr(@_[0],0,1); if ($bDebug) { print "dbg: sType = $sType\n"; } local $hk; local $hkr; local $sKey = "SYSTEM\\CurrentControlSet\\Services\\"; $sKey .= $sService; if ($bDebug) { print "dbg: sKey = $sKey\n"; } local $sValName = "Start"; local $nVal = 0; local $status = 0; $sServer = "\\\\" . $sComputer; # used by ->Connect() if ($sType eq "a") { $nVal = 2; } else { if ($sType eq "m") { $nVal = 3; } else { print "unknown startup type: $sType\n"; return $status; } } if ($bDebug) { print "dbg: nVal = $nVal\n"; } if (!$HKEY_LOCAL_MACHINE->Connect($sServer,$hkr)) { print "Can't connect to $sServer\n"; return $status; } if (!$hkr->Open($sKey,$hk)) { print "error opening key $sKey\n"; return $status; } if (!$hk->SetValueEx($sValName,0,REG_DWORD,$nVal)) { print "error setting $sValName = $nVal\n"; } else { $status = 1; } $hk->Close(); $hkr->Close(); return $status; }