#  LastLogon.pl
#  Example 2.5:
#  ----------------------------------------
#  From "Win32 Perl Scripting: Administrators Handbook" by Dave Roth
#  Published by New Riders Publishing.
#  ISBN # 1-57870-215-1
#
#  This script expires or un-expires a user account. An account that is
#  expired will force the user to change it's password at next logon.
#
#
print "From the book 'Win32 Perl Scripting: The Administrator's Handbook' by Dave Roth\n\n";


use Getopt::Long;
use Win32::NetAdmin;
use Win32::AdminMisc;
    
Configure( \%Config );
if( $Config{help} )
{
  Syntax();
  exit();
}

if( "" ne $Config{domain} )
{
  # Must first assign some value to the machine key otherwise
  # GetDomainController() will fail.
  $Config{machine} = "";
  Win32::NetAdmin::GetDomainController( '', 
                                        $Config{domain}, 
                                        $Config{machine} );
  Win32::NetAdmin::GetServers( $Config{machine}, 
                               $Config{domain}, 
                               SV_TYPE_DOMAIN_CTRL|SV_TYPE_DOMAIN_BAKCTRL, 
                               \@MachineList );
}
else
{
  if( 0 == scalar @{$Config{machine_list}} )
  {
    # Must first assign some value to the machine key otherwise
    # GetDomainController() will fail.
    $Config{machine} = "";
    Win32::NetAdmin::GetDomainController( '', 
                                          $Config{domain}, 
                                          $Config{machine} );
    push( @{$Config{machine_list}}, $Config{machine} );
  }
  push( @MachineList, @{$Config{machine_list}} );
}

# Notice that we use a hash (%AccountList) to track the users we 
# are working on. This is a simple hack to prevent us from 
# processing the same user more than once (if the user passed
# in the same account name multiple times).
foreach my $Account ( @{$Config{accounts}} )
{
  if( $Account =~ /\*$/ )
  {
    my( $Prefix ) = ( $Account =~ /^(.*)\*$/ );
    my @Users;
    Win32::AdminMisc::GetUsers( $Config{machine}, $Prefix, \@Users );
    map
    {
      $AccountList{lc $_} = 1;
    } ( @Users );
  }
  else
  {
    $AccountList{lc $Account} = 1;
  }
}

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{$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 $Account ( sort( keys( %Result ) ) )
{
  print "$Account ($Result{$Account}->{fullname}):\n";
  print Report( "Last logon", $Result{$Account}->{lastlogon} ), "\n";
  print Report( "Last logoff", $Result{$Account}->{lastlogoff} ), "\n";
  print "\tTotal number of bad password attempts: ";
  print "$Result{$Account}->{badpwcount}\n";
  print "\tTotal number of logons: $Result{$Account}->{logons}\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" );
}

sub Configure
{
    my( $Config ) = @_;

    Getopt::Long::Configure( "prefix_pattern=(-|\/)" );
    $Result = GetOptions( $Config, 
                            qw(
                                machine_list|m=s@
                                domain|d=s
                                help|?
                            )
                        );

    $Config->{help} = 1 if( ! $Result );
    push( @{$Config->{accounts}}, @ARGV );
    $Config->{help} = 1 if( ! scalar @{$Config->{accounts}} );
}

sub Syntax
{
    my( $Script ) = ( $0 =~ /([^\\\/]*?)$/ );
    my( $Line ) = "-" x length( $Script );

    print <<EOT;

$Script
$Line
Displays the last logon and logoff time for a specified account.

Syntax:
    perl $Script [-m Machine | -d domain] Account [Account2 ...]
        -m Machine..Specify a machine the accounts live on.
        -d Domain...Specify the domain the accounts live in.
        Account.....The name of the account (the userid).
                    This account can end with a * char to indicate
                    all accounts that begin with the specified string.
EOT
}
