davidj has asked for the wisdom of the Perl Monks concerning the following question:

My Fellow Monks,
(I know you will feel my pain)

Woe is me, for I have been tasked with using Perl to ensure another Perl program is running on a win2K machine. I offered to forego my internet privileges for a month if they would let the cup pass, but the Powers-That-Be declined :-)

Here is my situation:
I have a little script that launches on Windows startup. All it does is tail an application log every 5 minutes and then send an email to a particular user if certain messages appear in the log. Very plain, very simple. When I check the Windows machine, I discover that, for some reason, the script is no longer running. I have an error logging facility for it, but nothing in it indicates why it has died. The application whose log it is tailing is still running and everyone who has access to the machine swears they are not killing it. So I have been asked to write something that will check periodically to see if the script has died, and if so, kick it off again. (The Powers-That-Be were not interested in hearing about what would need to be done if the script that checks the script dies also).

So, finally, to my question:
Do any of you know of a way to get a list of all running programs on a Windows machine either my name or process Id? I figure this is the best way to determine if a program is running. I have examined the Win32 modules, but I cannot find anything. If it's in there, I certainly am missing it.
Or, if any of you have any other suggestions for how I might accomplish this task, I am most definately all ears.

as always, your input is greatly appreciated.
  • Comment on Check if a process is running on Windows

Replies are listed 'Best First'.
Re: Check if a process is running on Windows
by arden (Curate) on Jun 13, 2004 at 21:46 UTC
    From the description for Proc::Background, "This is a generic interface for placing processes in the background on both Unix and Win32 platforms. This module lets you start, kill, wait on, retrieve exit values, and see if background processes still exist."

    - - arden.

    update: While you're there, Win32::Process::Info has the  @info = $pi->GetProcInfo (); method which should return a host of information on every process running (except the idle and system processes) including the executable path and name.

      I guess looking hard doesn't mean much if you're looking in the wrong place, huh? :-)

      Thanks a bunch. I'll check it out.
Re: Check if a process is running on Windows
by Caron (Friar) on Jun 13, 2004 at 21:44 UTC

    One solution comes to mind.

    Write a script that launches the critical script, and does something when it is no longer running.

    #!/usr/bin/perl -w use strict; print "script started!\n"; my $result = system ""; # if it comes here, then the script has died. print " is no longer running. (Exit code $result)\n"; #perhaps add code to send a mail to your address
Re: Check if a process is running on Windows
by bibo (Pilgrim) on Jun 14, 2004 at 01:41 UTC
    Umm, this is pointed in a slightly different direction....

    How about having the original script write it's PID at start to a file, say your metascript could grab that PID and then query the OS if this particular PID is alive and kicking.... I have also written programs that update the run file every N minutes, as a keep-alive indicator. Then at least you have some idea when it died, and can start determining WHY it died. Good luck, I know how ugly and hurtful the Win32 world can be <grin>

Re: Check if a process is running on Windows
by BrowserUk (Patriarch) on Jun 13, 2004 at 22:59 UTC

    I would have thought that it would be much simpler to create a simple .bat/.cmd file

    :redo @notepad & goto redo

    Just substitute your program path/name for notepad.

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
      i would have thought that it would be worthwhile to investigate why the tail script dies. had a situation at work recently where my scripts only processed half the file and we didn't notice until later. it took a bit of head scratching to find that the file being processed had an eof character in it. this may not be the answer but, tail will exit if it sees eof in input stream.
Re: Check if a process is running on Windows
by mhi (Friar) on Jun 14, 2004 at 09:01 UTC
    Granted, this is not particularly a perl answer... :-)

    You may be happier installing cygwin on that box to have a Unix-like environment in which to run your scripts. With a simple ps -efW you'll see not only the cygwin processes, but also the Windows ones. You might also want to run your checker (and perhaps the original tail-and-mail script) from cygwin's cron utility.

    Also, a common way to check whether something is still running (actually running and not stuck somewhere) is to have it do something external (like touch a certain file or write into a log - a generalization of what bibo mentioned above) every once in a while and checking periodically whether this action has been executed recently enough. That may be better than simply checking for the existence of a process.

    Have fun!

Re: Check if a process is running on Windows
by AJRod (Scribe) on Jun 14, 2004 at 06:57 UTC

    Are you running the script/program as a service? I have recently stumbled upon this article and thought it might help.

    (I hope you will pardon this response if it appears naive.)

    Please forgive me for earlier sending you the above link to an article which I only later on discovered to be available only to subscribers of the website. Anyway, for whatever it was worth, the basic idea at least was there. Hope that helps.

Re: Check if a process is running on Windows
by paulbort (Hermit) on Jun 14, 2004 at 18:51 UTC
    While there are several valid methods above, they are all making this way too hard.

    This is one of the things that Windows gets right. Assuming you are on Windows 2000, Windows XP, or Windows 2003, you can solve this in less than a minute with zero code!

    First, disable whatever method is currently launching the main script.

    Next, set that same script up again to be launched by the built-in Windows Task Scheduler. Tell Task Scheduler that you want your script run every five minutes, UNLESS it is already running from last time. Voila!

    Hope you get this before spending too much time with another solution...

    Spring: Forces, Coiled Again!
Re: Check if a process is running on Windows
by mrpeabody (Friar) on Jun 14, 2004 at 18:36 UTC
    You can use Sysinternals PsList for this. See
    PsList 1.22 - Process Information Lister Copyright (C) 1999-2002 Mark Russinovich Sysinternals - Usage: pslist.exe [-d][-m][-x][-t][-s [n] [-r n] [\\computer [-u usern +ame][-p password][name|pid] -d Show thread detail. -m Show memory detail. -x Show processes, memory information and threads. -t Show process tree. -s [n] Run in task-manager mode, for optional seconds specifie +d. Press Escape to abort. -r n Task-manager mode refresh rate in seconds (default is 1 +). \\computer Specifies remote computer. -u Optional user name for remote login. -p Optional password for remote login. If you don't presen +t on the command line pslist will prompt you for it if ne +cessary. name Show information about specified process. pid Show information about specified process.
    (OT, would it kill CODE tags to wrap at 80 columns instead of 70?)
Re: Check if a process is running on Windows
by pgor (Beadle) on Jun 14, 2004 at 21:46 UTC
    use Win32::PerfLib; sub getProcessList { # this code is copied almost verbatim from the Win32::PerfLib docs # it's really convoluted and confusing, but it works for finding # the pid and name of running processes my @proc_objs = (); my %counter = (); Win32::PerfLib::GetCounterNames( '', \%counter ); my %r_counter = map { $counter{$_} => $_ } keys %counter; # retrieve the id for process object my $process_obj = $r_counter{ Process }; # retrieve the id for the process ID counter my $process_id = $r_counter{ 'ID Process' }; # create connection to $server my $perflib = new Win32::PerfLib( '' ); my $proc_ref = {}; # get the performance data for the process object $perflib->GetObjectList( $process_obj, $proc_ref ); $perflib->Close(); my $instance_ref = $proc_ref->{ Objects }->{ $process_obj }->{ Insta +nces }; foreach my $p ( sort keys %{$instance_ref} ) { my $counter_ref = $instance_ref->{ $p }->{ Counters }; foreach my $i ( sort { $a <=> $b } keys %{$counter_ref} ) { if ( $counter_ref->{ $i }->{ CounterNameTitleIndex } == $process +_id ) { push @proc_objs, { id => $counter_ref->{ $i }->{ Counter }, name => $instance_ref->{ $p }->{ Name }, }; } } } return @proc_objs; }