http://qs321.pair.com?node_id=113082

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

Hi, i am hacking a script together to run on an NT box. It's a security script that checks whether someone is logged in using a forbidden userId ("admin") on a given unix box. The script works fine, logs in to the unix host and performs a "who", then runs "nbtstat" on NT to derive the NT logins. From these we can get their mail addresses and send them a nasty email. The %userData hash is already initialised as we know which users can log in to the box...

Anyhoo, here's my code, and the problem I'm having is weeding out duplicates from @mailArray so no more than one email is sent (Users could be logged in more than once with the same userId to the unix box). Hope you can help me, gawd I do.

#!perl -w use strict; use Net::Telnet; ##script to see how many people are still logging in ##as admin. get the ip/origination, and crucify them ##with a particularly condescending email #get rid of previous naughtyUsers.txt, so we don't have any duplic +ates unlink("naughtyUsers.txt") or warn "Unlink warning : $!\n"; my ($telnet,@naughtyList,$ip,$userName,$mailUserName,@whoArray, @n +btstatInfo,@mungeData,$ntID); #log in to machine $telnet = new Net::Telnet ( Timeout => 120); $telnet->open("hostname.company.com") or die "Died @ Open : $!\n"; $telnet->login( Name => "username", Password => "password", ) or die "Died @ Login : $!\n"; @whoArray = $telnet->cmd("who") or die "Died @ Who : $!\n"; $telnet->close; #get relevant data - i.e. glb1prd users foreach my $line(@whoArray) { if ($line =~ /^admin/) { push(@naughtyList, $line); } } #now resolve ip to get name - ouch #we are going to redirect stdout, so save it open (SAVEDOUT, ">&STDOUT"); open (SAVEDERR, ">&STDERR"); foreach my $foo (@naughtyList) { ($ip = $foo) =~ s/.*\((.*)\)/$1/g; open (STDOUT, ">>naughtyUsers.txt") or die "Died @ Open : $!\n"; open (STDERR, ">&STDOUT") or die "Died @ Open : $!\n"; system("nbtstat -A $ip") if ($ip =~ /^\d+/); close (STDOUT); close (STDERR); #set stdout back to default open (STDOUT, ">&SAVEDOUT"); open (STDERR, ">&SAVEDERR"); } #now munge data in file to get simple lines of who's logged in open (FH, "<naughtyUsers.txt") or die "Died @ Open : $!\n"; #initialise userData hash my %userData =( NTUSERONE => "ntuserone\@company.com", NTUSERTWO => "ntusertwo\@company.com", NTUSERTHREE => "ntuserthree\@company.com", NTUSERFOUR => "ntuserfour\@company.com", NTUSERFIVE => "ntuserfive\@company.com", ); #shove everything from naughtyUsers.txt into array @mungeData = <FH>; foreach my $entry(@mungeData) { foreach my $key (keys %userData) { ( ($key, my $value) = each %userData); if ($entry =~ /^$key/) { push (my @mailArray, $value); mailNaughtyUser(@mailArray); } } } sub mailNaughtyUser { my @addies = shift; foreach my $address(@addies) { #here's my problem - need to ensure duplicates #are pop()'d out of the array before we send a mail }

Azatoth a.k.a Captain Whiplash

Make Your Die Messages Full of Wisdom!
Get YOUR PerlMonks Stagename here!
Want to speak like a Londoner?

Replies are listed 'Best First'.
Re: Removing Duplicates from an Array
by davorg (Chancellor) on Sep 18, 2001 at 14:56 UTC
Re: Removing Duplicates from an Array
by ChOas (Curate) on Sep 18, 2001 at 14:51 UTC
    Something like this: ?

    sub mailNaughtyUser { my @addies = shift; #my @addies=@_; ? my %Seen; foreach my $address(@addies) { next if $Seen{$Address}++; # # Do that thing you do best once on every address # } }

    btw that my @addies=shift; looks like a really neat trick
    coz I don`t get it ;))

    GreetZ!,
      ChOas

    print "profeth still\n" if /bird|devil/;
Re: Removing Duplicates from an Array
by Zaxo (Archbishop) on Sep 18, 2001 at 15:00 UTC

    This is a pretty well-known problem:

    sub mailNaughtyUser { my %addies = map {($_ => 1)} @_; foreach my $address (keys %addies) { mail_nastygram $address; } }

    After Compline,
    Zaxo

Re: Removing Duplicates from an Array
by broquaint (Abbot) on Sep 18, 2001 at 15:59 UTC
    Maybe even -
    @arr = map { $_ if !$_{$_}++ } @arr;
    Which will get rid of all the duplicate elements in your array. Of course the above is quick, dirty and hackish, but if you're merely munging an array of strings, it should do the job.
    HTH

    broquaint

      I'm pretty sure you wanted grep there and not map, and you're altering %_ without warning. As others have said, look at the FAQ entry for proper code.

      -- Randal L. Schwartz, Perl hacker

Re: Removing Duplicates from an Array
by George_Sherston (Vicar) on Sep 18, 2001 at 14:59 UTC
    these threads have some discussion of the issues involved, and a number of slick ways to do it. Hope they're some use.

    § George Sherston