in reply to Monitoring a process

Here is some code that can help get you started with WIn32 services:
#///////////////////////////////////////////////////////////////////// +///////// #// #// ServiceMaker.pl #// Win32 Service Creator #// #// Copyright (c) 2004 Vijay Anand #// #// 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 <ServiceName> #// To CREATE, Run: perl ServiceMaker.pl <Full path to MRTG cfg fi +le> #// (The service name will be the same as the file name, without #// the extension - Eg: d:\apps\mrtg\bin\Rtr1.cfg Service is Rtr +1) #// To LIST services, Run: perl ServiceMaker.pl -l <Optional Filter> #// 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::Fo +rmatMessage( 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$ServiceNa +me\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"; } } }
Of course, it needs to be run with appropriate priviledges.

    ..."I don't know what the facts are but somebody's certainly going to sit down with him and find out what he knows that they may not know, and make sure he knows what they know that he may not know, and that's a good thing. I think it's a very constructive exchange," --Donald Rumsfeld