#  Expire.pl
#  Example 5.6:
#  ----------------------------------------
#  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;
use Win32::NetAdmin;
use Win32::AdminMisc;

Configure( \%Config );
if( $Config{help} )
{
    Syntax();
    exit();
}

if( "" ne $Config{domain} )
{
  $Config{machine} = "";
  Win32::NetAdmin::GetDomainController( '', 
                                        $Config{domain}, 
                                        $Config{machine} );
}
elsif( "" eq $Config{machine} )
{
    $Config{machine} = "\\\\" . Win32::NodeName();
}
else
{
  $Config{machine} = "\\\\$Config{machine}";
  $Config{machine} =~ s/^\\+/\\\\/;
}

# 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 $Account ( sort( keys( %AccountList ) ) )
{
  my %Attrib;
  my $Result = 0;
  my $Flag = 0;

  print ( ( $Config{expire} )? "Expiring" : "Unexpiring" );
  print " password for '$Account'...";
  if( Win32::AdminMisc::UserGetMiscAttributes( $Config{machine}, 
                                               $Account, 
                                               \%Attrib ) )
  {
    $Flag = $Attrib{USER_FLAGS};
    # If we are expiring the password AND the account does not allow
    # the password to change then modify it so that it DOES allow the
    # password to change.
    if( ! $Config{unexpire} )
    {
      $Flag &= ~UF_PASSWD_CANT_CHANGE;
   
      # If the account does not allow the account to expire then 
      # temporarily allow it...
      if( $Flag & UF_DONT_EXPIRE_PASSWD )
      {
          $Flag &= ~UF_DONT_EXPIRE_PASSWD;
      }
    }
  
    if( $Flag != $Attrib{USER_FLAGS} )
    {
      Win32::AdminMisc::UserSetMiscAttributes( $Config{machine}, 
                                               $Account, 
                                               USER_FLAGS => $Flag );
    }
  
    # Force the account to expire and reset the flags...
    $Result = Win32::AdminMisc::UserSetMiscAttributes( 
                    $Config{machine}, 
                    $Account, 
                    USER_PASSWORD_EXPIRED => !$Config{unexpire} );
  }

  if( $Result )
  {
    print "successful.\n";
  }
  else
  {
      my $Error =  Win32::FormatMessage( Win32::GetLastError() );
      $Error =~ s/\r|\n//g;
      print "failed to " . (($Config->{unexpire})? "unexpire" : "expire" );
      print ": ($Error)\n";
  }
}

sub Configure
{
  my( $Config ) = @_;

  Getopt::Long::Configure( "prefix_pattern=(-|\/)" );
  $Result = GetOptions( $Config, 
                          qw(
                              machine|m=s
                              domain|d=s
                              unexpire|u
                              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
Expires an account forcing the user to change passwords at next logon.

Syntax:
    perl $Script [-u] [-m machine | -d domain] Account [ Account2 ... ]
        -u..........Un-expire the account.
        -m Machine..Specify the machine the accounts lives 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
}