#////////////////////////////////////////////////////////////////////////////// #// #// ServiceMaker.pl #// Win32 Service Creator #// #// 2004 Netwallah #// #// Use this program to CREATE or DELETE a Win32 service. #// This is specifically designed to run MRTG config files #// (Although it can be easily modified for other purposes). #// Bonus Functions: get a LIST of services, and/or #// Replace FireDaemon service(s) with SRVANY. #// #// It requires that the SRVANY program from the Windows Resource #// kit be installed in the %Systemroot%\System32 directory. #// It requires that the Win32::Daemon perl module be installed by: #// PPM install http://www.roth.net/perl/packages/win32-daemon.ppd #// #// Run instructions/Parameters: #// To DELETE, run: perl ServiceMaker.pl -d #// To CREATE, Run: perl ServiceMaker.pl #// (The service name will be the same as the file name, without #// the extension - Eg: d:\apps\mrtg\bin\Rtr1.cfg Service is Rtr1) #// To LIST services, Run: perl ServiceMaker.pl -l #// To REPLACE a bunch of FireDaemon services with SRVANY, Run: #// perl ServiceMaker.pl -f ServiceName1 ServiceName2 ... #// #// 20031209 : Code Complete -- Patch History --- -VA #// 20031210 : First Fix Info here .. -VA #////////////////////////////////////////////////////////////////////////////// use strict; use Win32::Service; my $Registry; use Win32::TieRegistry ( TiedRef=>\$Registry, Delimiter=>"/" ); use Win32::Daemon; use English; my %ServiceStartType = ( '0x00000002' => 'automatic', '0x00000003' => 'manual', '0x00000004' => 'disabled', ); my %ServiceStatusCode = ( '1' => 'stopped.', '2' => 'start pending.', '3' => 'stop pending.', '4' => 'running.', '5' => 'continue pending.', '6' => 'pause pending.', '7' => 'paused.' ); my $SERVICES_KEY='HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/'; if ($ARGV[0] eq "-l"){ ListServices($ARGV[1]); exit 0; } if ($ARGV[0] eq "-d"){ DeleteThisService($ARGV[1]); exit 0; }; if ($ARGV[0] eq "-f"){ foreach( @ARGV[1..$#ARGV] ){ ReplaceFireDaemon($_); } exit 0; }; # We better have an MRTG cfg file name (With PATH) in ARGV[0] my $MRTG_File = $ARGV[0] or die "MRTG Cfg file name not specified\n"; -e $MRTG_File or die "No file:$MRTG_File\n"; -e qq($ENV{systemroot}\\system32\\srvany.exe) or die "SRVANY.exe not found in $ENV{systemroot}\\system32\\ \n"; #Separate the file-name into the Dir, and file.ext $MRTG_File =~m/^(.+)\\(.+)$/; my $PathName = $1; my $filename = $2; my $ServiceName = (split /\./, $filename)[0]; #(split /\./,(split /\\/,$MRTG_File)[-1])[0]; MakeService($ServiceName, $PathName, "$EXECUTABLE_NAME mrtg $filename"); #Note: $EXECUTABLE_NAME ($^X) is The name used to execute the current copy of Perl, from C's argv[0]. # I.E. it is the full path to "Perl.exe" ################################# sub MakeService{ my $ServiceName = shift or die "Service Name Not Specified\n"; my $ServiceDir = shift; my $ServiceCommandLine = shift; my %ServiceStatus; # See if registered in SERVICES if (Win32::Service::GetStatus("", $ServiceName, \%ServiceStatus)){ # Service Already Exists .. complain warn "**Service $ServiceName is Already defined as a SERVICE and ". $ServiceStatusCode{$ServiceStatus{CurrentState}} . "; Please Remove this service before adding**\n"; return 1; } #It may be in REGISTRY, but not registered as a service - check if (exists $Registry->{"LMachine/System/CurrentControlSet/Services/$ServiceName/"}) { warn "**Service $ServiceName is Already defined in Registry ". "; Please Remove this service before adding**\n"; return 1; } my %ServiceInfo = ( machine => '', name => "MRTG$ServiceName", display => "MRTG $ServiceName", path => '', user => '', pwd => '', description => "$ServiceName MRTG Service", parameters =>"%SystemRoot%\\system32\\srvany.exe", ); if( Win32::Daemon::CreateService( \%ServiceInfo ) ) { print "Successfully added Service $ServiceInfo{name}.\n"; } else { print "Failed to add service $ServiceInfo{name}: " . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n"; return 1; } $Registry->{"LMachine/System/CurrentControlSet/Services/$ServiceName/Parameters"}= { "/Application" => [$ServiceCommandLine ,"REG_SZ"], "/AppDirectory" => [$ServiceDir ,"REG_SZ"], } or die "Can not create services Parameter entry\n"; ## Need to actually START the new service ... print "Service $ServiceName Created. (Will AutoStart on reboot)\n"; print "To start it NOW, use the command:\n NET START MRTG$ServiceName\n"; } ################################# sub DeleteThisService{ my $ServiceName = shift or die "No service specified to DELETE\n"; my $rslt = Win32::Daemon::DeleteService('', $ServiceName ); print "Service $ServiceName DELETED = $rslt ***\n"; } ################################# sub ListServices{ my $filter=shift || ''; # Pattern match for service list my $ServiceKey = $Registry->{$SERVICES_KEY}; foreach (keys %{$ServiceKey}){ length($_) > 1 or next; # Must have one char + "/". Skip emptys my $Svcname=$ServiceKey->{$_}->{DisplayName} || ''; ##print " Key:$_-$Svcname; Filter=$filter \n"; if ( length($filter)==0){ #Show this }elsif($Svcname =~m/$filter/i or $_ =~m/$filter/i){ # Show this one }else{ next; # Don't show }; print " $_\t= $Svcname\n"; } } ################################# sub ReplaceFireDaemon{ my $servicename = shift; print "ReplaceFireDaemon processing [$servicename]..."; my $service = $Registry->{$SERVICES_KEY}->{$servicename}; exists $service->{Parameters}->{FireStarter} or return; $service->{DisplayName}=~s/FireDaemon Service://i; $service->{ImagePath} = ['%SystemRoot%\system32\srvany.exe', "REG_EXPAND_SZ"]; $service->{Parameters}->{Application} = $service->{Parameters}->{FireStarter}; $service->{Parameters}->{AppDirectory} = $service->{Parameters}->{WorkingDir}; delete $service->{Parameters}->{FireStarter}; delete $service->{Parameters}->{WorkingDir}; print "DONE\n"; } ######################################################## sub ShowServiceStatus{ #set up a hash of known service states my %serviceHash; #go get 'em... Win32::Service::GetServices("", \%serviceHash); # Key=Long name, Value = Short name, in ServiceHash foreach my $key(sort keys %serviceHash){ my $service = $Registry->{$SERVICES_KEY}->{$serviceHash{$key}}; my $servstart = $ServiceStartType{$service->GetValue('Start')}; my %statusHash; Win32::Service::GetStatus("", $serviceHash{$key}, \%statusHash); if ($statusHash{"CurrentState"} =~ /[1-7]/){ print $ServiceStatusCode{$statusHash{CurrentState}} . "\t $key=" . $serviceHash{$key} . " \tStartType=$servstart\n"; }else{ print "*Unknown state=" . $statusHash{"CurrentState"} ." for service $key=" . $serviceHash{$key} . "\n"; } } }