http://qs321.pair.com?node_id=286730
Category: Win32 Stuff
Author/Contact Info /msg PodMaster
Description:
    perl tasklist.pl
    ...
    smss.exe  --  Smss.exe (Microsoft)
      Windows NT4/2000/XP only.į SMSS is the Session Manager SubSystem.į
      SMSSĘs purpose is to start, manage, and delete user sessions (or
      client sessions under Terminal Server).į Under Terminal Server the
      management part includes dealing with the different subsystems (OS/2,
      Win32, POSIX) which a client session may wish to run.
      Recommendationį:į An integral part of the operating system, leave
      alone.
    ...
See pod for more.

update: fixed minor bug. then i fixed another one ;)(if you already have a tasklist.storable, it's best to delete it)

#!/usr/bin/perl -  

=head1 NAME

tasklist.pl - dump win32 tasklist along with metadata

=head1 SYNOPSIS

    perl tasklist.pl
    ...
    smss.exe  --  Smss.exe (Microsoft)
      Windows NT4/2000/XP only.į SMSS is the Session Manager SubSystem
+.į
      SMSSĘs purpose is to start, manage, and delete user sessions (or
      client sessions under Terminal Server).į Under Terminal Server t
+he
      management part includes dealing with the different subsystems (
+OS/2,
      Win32, POSIX) which a client session may wish to run.
      Recommendationį:į An integral part of the operating system, leav
+e
      alone.

=head1 DESCRIPTION

The first time you use F<tasklist.pl>,
it will get tasklist metadata from 
L<http://www.answersthatwork.com/Tasklist_pages/tasklist.htm>.
and store it under C<$tasklistdir>
(whose value you might wanna change).

To refresh the metadata, just pass any argument to F<tasklist.pl>.

F<tasklist.pl> is intended for win32 machines (microsoft).

B<WARNING>: using this program may be against
the terms of use of L<http://www.answersthatwork.com>,
but as long as you don't distribute tasklist.storable,
along with this program you should be fine.

=head1 TODO

    - maybe contact GetOpt::Long and Pod::Usage MAN!!
    - maybe look into the charset issue
    - maybe add paging support
    - maybe add ability to simply list processes
    - maybe add the ability to dump metadata for named processes/pids 
+only
    - refactor refactor refactor

=head1 AUTHOR

    D. H. (PodMaster)

=head1 COPYRIGHT

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

If you don't know what that means, visit perl.com
or cpan.org or perl.org.

=cut

use HTML::TokeParser::Simple;
use LWP::Simple qw[ get mirror RC_NOT_MODIFIED ];
use Storable qw[ nstore retrieve ];
use Text::Wrap; #Text::Wrap  was first released with perl 5.00307
use Win32::Process::Info;

use strict;
use warnings;

my $tasklistdir = "$ENV{USERPROFILE}/tasklist";
my $file = 'tasklist.storable';

unless(-e $tasklistdir){
    mkdir $tasklistdir
        or die "can't create \$tasklistdir: $tasklistdir";
}

chdir $tasklistdir
    or  die "can't chdir to \$tasklistdir: $tasklistdir";

if( @ARGV or ! -e $file ){
    mirrorN() and parseNstore();
} else {
    getNdisplay();
}
exit;

sub getNdisplay {
    
    my $hash = retrieve $file or die "can't retrieve $file : $!";

    local $Text::Wrap::columns = 72;

    my %roy;
    $roy{ lc $_->{Name} }++
        for Win32::Process::Info->new()->GetProcInfo();

    for my $procNOX(sort keys %roy){
        print "\n$procNOX  -$roy{$procNOX}-  ";

        if( exists $hash->{$procNOX} ){
            print$hash->{$procNOX}->[0],"\n";
            print wrap('  ','  ', $hash->{$procNOX}->[1]);
        }

        print "\n";
    }

}

sub mirrorN {
    my $reparse = 0;
    for my $i ( 1, 'a'..'z' ) {
        $reparse++ unless
        mirror(
            "http://www.answersthatwork.com/Tasklist_pages/tasklist_$i
+.htm",
            "tasklist_$i.htm"
        ) == RC_NOT_MODIFIED;
    }

    return $reparse;
}

sub parseNstore {

    my %hash;
    for my $html( glob 'tasklist*.htm' ){
        my $p = HTML::TokeParser::Simple->new($html);
        
        while(defined(my $t = $p->get_tag('th') )){

            my $text = $p->get_trimmed_text('/th');

            last if $text =~ /AND WHAT YOU CAN DO/;
            #AND WHAT YOU CAN DO
        }

        while(defined(my $t = $p->get_tag )){
            if( $t->is_start_tag('tr') ){
                my @cols;
                for( 1 .. 3 ){
                    $t = $p->get_tag('td');
                    push @cols, $p->get_trimmed_text('/td');
                }
                my $exe;
                $exe = lc $1 if $cols[1] =~ /(\w+\.exe)/i;
                $exe = lc "$cols[0].exe" unless $exe;
                $hash{$exe} = [] unless exists  $hash{$exe};
                $hash{$exe}->[0] .= "$cols[1] ";
                $hash{$exe}->[1] .= "$cols[2]\n\n";
            }
            elsif( $t->is_end_tag('table') ){
                last;
            }
        }
    }
    nstore(\%hash, $file) or die "can't nstore into $file : $!";
}