#  UnifiedLogon.pl
#  Example 6.9:
#  ----------------------------------------
#  From "Win32 Perl Scripting: Administrators Handbook" by Dave Roth
#  Published by New Riders Publishing.
#  ISBN # 1-57870-215-1
#
#  This script is an example of a unified logon script.

use Win32;
use Win32::Lanman;
use Win32::NetAdmin;
use Win32::AdminMisc;
use Win32::ODBC;

my $TempFileGracePeriod = 2 * $WEEK;
my $DSN = "LogonDatabase";
my %Logon = (
    account => Win32::LoginName(),
    machine => Win32::NodeName(),
    domain  => Win32::DomainName(),
    dc      => undef,
);
my %LogonPath = (
    share    => 'NetLogon',
    rootdir  => 'Scripts',
    userdir  => 'Users',
);
my $SERVER_TYPE = SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL;
my $ScriptsUnc = "";
my @GroupList = ();

Win32::NetAdmin::GetAnyDomainController( '', $Logon{domain}, $Logon{dc} );

# Discover the local Perl server...
if( Win32::NetAdmin::GetServers( '', '', $SERVER_TYPE, \@List ) )
{
    my $Time = 0xFFFF;
    foreach my $Machine ( @List )
    {
        my $Unc = "\\\\$Machine\\$LogonPath{share}\\$LogonPath{rootdir}";
        if( -d $Unc )
        {
            my @Output = `ping -n 1 $Machine`;
            my( $NewTime ) = ( join( " ", @Output ) =~ /Reply from.*?\s+time[=<>](\d+)ms/is );
            if( ( "" ne $NewTime ) && ( $NewTime < $Time ) )
            {
                $Time = $NewTime;
                $ScriptsUnc = $Unc;
            }    
        }        
    }
}    
Win32::AdminMisc::SetEnvVar( 'ScriptServer', $ScriptsUnc, ENV_USER, 10 );

# Before we call any other scripts first open the database
# so that each script can use it.
$db = new Win32::ODBC( $DSN );

# Discover what local groups the user is a member of...
Win32::Lanman::NetUserGetLocalGroups( $Logon{dc},
                                      $Logon{account},
                                      LG_INCLUDE_INDIRECT,
                                      \@LGroups );

# Discover what global groups the user is a member of…
Win32::Lanman::NetUserGetGroups( $Logon{dc},
                                 $Logon{account}, 
                                 \@GGroups );
print "Starting the unified logon process...\n";

foreach my $Group ( @LGroups, @GGroups )
{
  my $GroupName = $Group->{name};
  my $Script = "$ScriptsUnc\\$GroupName.pl";
  print " Calling $Script\n";
  require $Script if( -f $Script );
}

# If the user has his own logon script run it...
if( -f "$ScriptsUnc\\$LogonPath{userdir}\\$Logon{account}.pl" )
{
    require "$ScriptsUnc\\$LogonPath{userdir}\\$Logon{account}.pl";
}

# Fix any user overriding of system variables
if( ( Win32::AdminMisc::GetEnvVar( \%System, ENV_SYSTEM ) )
    && ( Win32::AdminMisc::GetEnvVar( \%User, ENV_USER ) ) )
{
    my @NewUserVar = ();
    foreach $VarName ( keys( %System ) )
    {
        if( defined $User{$VarName} )
        {
            if( $System{$VarName} =~ /_$VarName/ )
            {
                push( @NewUserVar, $VarName );
            }
        }
    }
    
    # Modify the user env var space
    foreach $VarName ( @NewUserVar )
    {
        print "Setting new user var: _$VarName\n";
        if( Win32::AdminMisc::SetEnvVar( "_$VarName", $User{$VarName}, ENV_USER ) )
        {
            $ENV{"_$VarName"} = $User{$VarName};
    
            # Remove conflicting user env vars
            print "Deleting user var: $VarName\n";
            if( Win32::AdminMisc::DelEnvVar( $VarName, ENV_USER ) )
            {
                delete $ENV{$VarName};
            }
        }
    }
}

# Clean up the temp directory...
# First start with the system temp directory...
push( @TempDirs, Win32::AdminMisc::GetEnvVar( 'Temp', ENV_SYSTEM ) );
push( @TempDirs, Win32::AdminMisc::GetEnvVar( 'Temp', ENV_USER ) );
foreach my $TempDir ( @TempDirs )
{
    foreach my $Path ( glob( "$TempDir\\*.*" ) )
    {
        next if( ! -f $Path );                
        unlink( $Path) if( $TempFileGracePeriod < time() - (stat( $Path ))[10] );
    }
}

# Update the logon database...
if( $db )
{
    my $Query = "INSERT INTO UserLogon (Domain, Account, Machine, Date) " .
             "VALUES ('$Logon{domain}', '$Logon{account}', '$Logon{machine}', {fn Now()})";
    $db->Sql( $Query );
    $db->Close() if( $db ); 
}

BEGIN
{
    $SECOND = 1;
    $MINUTE = 60 * $SECOND;
    $HOUR = 60 * $MINUTE;
    $DAY = 24 * $HOUR;
    $WEEK = 7 * $DAY;
}
