in reply to Problem with ascertaining last NT logon - Roth script

Looks to me that your script actually polled the results for all the servers, but because you are not populating your hash %Results "correctly", the previous results are overwritten by most recent results. What you need to do is to introduce another hash level, so that your %Results looks like this:
$Results{$Machine}{$Account}{$attributes}

And then you iterate through your machines first, then for each machine, you iterate through your accounts, and so on...

If you want to order by the accounts, you build your %Results like this:
$Results{$Account}{$Machine}{$attributes}

ie, swap the account and machine, and you iterate through account, then machine, and so on...

Replies are listed 'Best First'.
Re: Re: Problem with ascertaining last NT logon - Roth script
by billie_t (Sexton) on Feb 17, 2004 at 06:26 UTC

    Thanks for the explanation, Roger. I'm afraid that being a complete noob when it comes to Perl, I can find it quite difficult to visualise what is going on within a hash, particularly if elements are being referenced by other variables.

    I can see that my %Result is fairly much only storing {$account} and {%attrib}. And I understand the idea that you need another level (for {%machine}?) in the %Result to store what went on before. But to be frank, thinking in more than 2 hash levels is beyond me at present (some things I can visualise by RFTM, others need to be explained - I'm not a programmer).

    Would it be possible for you (or someone else) to give me a snippet of code to show what you mean? Apologies for the "obviousness" of the question... :-(

    Also, any links to simple discussions of hashes etc would be helpful - my books are good, but coming at it from a different perspective sometimes helps.

      Ok, here comes the code... Give this a try. See if this gives you what you expect:
      foreach my $Machine ( @MachineList ) { ( $Machine = "\\\\$Machine" ) =~ s/^\\+/\\\\/; print "Querying $Machine\n"; foreach my $Account ( sort keys %AccountList ) { my %Attrib; if( Win32::AdminMisc::UserGetMiscAttributes( $Machine, $Account, \%Attrib ) ) { my $Data = $Result{$Machine}{$Account} = {}; $Data->{fullname} = $Attrib{USER_FULL_NAME}; if( $Data->{lastlogon}->{value} < $Attrib{USER_LAST_LOGON} ) { $Data->{lastlogon}->{value} = $Attrib{USER_LAST_LOGON}; $Data->{lastlogon}->{machine} = $Machine; } if( $Data->{lastlogoff}->{value} < $Attrib{USER_LAST_LOGOFF} ) { $Data->{lastlogoff}->{value} = $Attrib{USER_LAST_LOGOFF}; $Data->{lastlogoff}->{machine} = $Machine; } $Data->{badpwcount} += $Attrib{USER_BAD_PW_COUNT}; $Data->{logons} += $Attrib{USER_NUM_LOGONS}; } } } foreach my $Machine ( sort keys %Result ) { my $MachineInfo = $Results{$Machine}; foreach my $Account ( sort keys %{$MachineInfo} ) { print "$Account ($MachineInfo->{$Account}{fullname}):\n"; print Report( "Last logon", $MachineInfo->{$Account}{lastlogon +} ), "\n"; print Report( "Last logoff", $MachineInfo->{$Account}{lastlogo +ff} ), "\n"; print "\tTotal number of bad password attempts: "; print "$MachineInfo->{$Account}{badpwcount}\n"; print "\tTotal number of logons: $MachineInfo->{$Account}{logo +ns}\n"; print "\n"; } } sub Report { my( $Field, $Data ) = @_; my $Date = scalar localtime($Data->{value} ); my $Location = "( $Data->{machine} )"; $Date = "Not available" if( 0 == $Data->{value} ); $Location = "" if( 0 == $Data->{value} ); return( "\t$Field: $Date $Location" ); }
        That's great! -other than what I presume was a typo,
        foreach my $Machine ( sort keys %Result ) { my $MachineInfo = $Results{$Machine}; foreach my $Account ( sort keys %{$MachineInfo} )
        should be my $MachineInfo = $Result{Machine}??

        The output now produces an entry for each machine in the list. All I have to do now is compare the two entries and get it to spit out the last value in each field from all servers, but I can do that with what you've given me.

        Thanks!