#  SetupLogonScript.pl
#  Example 6.8:
#  ----------------------------------------
#  From "Win32 Perl Scripting: Administrators Handbook" by Dave Roth
#  Published by New Riders Publishing.
#  ISBN # 1-57870-215-1
#
#  This script is designed to run on a new machine. It is run as a logon
#  script for a special administrative "setup" user account.  When this special
#  user is logged on this logon script runs and performs necessary setup
#  functions on the new machine.

BEGIN
{
    print<<EOT;
    
    WARNING: This script demonstrates how a logon script can be used
             to setup a computer.  In this script files are copied,
             directories are secured and drives are converted from FAT to
             NTFS.
             For safty sake this script will end now.  To use this script
             you will have to remove the BEGIN{} block at the beginning.
             
EOT
    exit();
}

use Win32;
use Win32::Perms;
use Win32::NetAdmin;
use Win32::Registry;
use Win32::AdminMisc;

$Machine = Win32::NodeName();
$Domain = Win32::DomainName();

$PerlDrive = 'c:';
$PerlPath  = '\perl';

$REMOTE_PERL_PATH = '\\\\server\perlshare$\perl';
$NTFS_CONVERSION_APP = "convert.exe";
$NTFS_CONVERSION_PARAM = "/FS:NTFS /V";

ConfigGroup( $Domain );
if( ConfigDrive( $PerlDrive ) )
{
    SecureDir( "$PerlDrive$PerlPath" );
    CopyDir( $REMOTE_PERL_PATH, "$PerlDrive$PerlPath" );
    ConfigPath( "$Dir\\bin" );
}

ConfigLastUser( "" );
Log( $LogFile );
RebootMachine();
print "Finished.\n";

sub Log
{
  my( $LogFile ) = @_;

  if( open( LOG, ">> $LogFile" ) )
  {
    flock( LOG, 2 );
    seek( LOG, 0, 2 );
    print LOG Win32::NodeName(), "\t", scalar( localtime() ), "\n";
    flock( LOG, 8 );
    close( LOG );
  }
}

# Reboot the machine
sub RebootMachine
{
    Win32::AdminMisc::ExitWindows( EWX_REBOOT | EWX_FORCE );
}

# Remove the "Last Logged On User" so nobody knows
sub ConfigLastUser
{
    my( $User ) = @_;
    my $Key;
   
    if( $HKEY_LOCAL_MACHINE->Create( 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon', $Key ) )
    {
        $Key->SetValueEx( $Key, 0, REG_SZ, $User );
        $Key->Close();
    }
}

sub ConfigGroup
{
    my( $Domain ) = @_;
    
    $Domain .= "\\" if( '' ne $Domain );
    
    # Add the Domain Admins group to the Administrators group
    Win32::NetAdmin::LocalGroupAddUsers( '', 'Administrators', "$Domain" . "Domain Admins" );
}

sub ConfigPath
{
    my( $Dir ) = @_;
    my $RegexDir = "$Dir";
    my $Path;

    # First check to see if the $Dir is already in the path...
    $Path = Win32::AdminMisc::GetEnvVar( 'PATH' );
    
    # Prepare $Dir for a regex...
    $RegexDir =~ s/([.\\\$])/\\$1/g;
    if( $Path !~ /$Dir/i )
    {
        # Add $Dir to the system (not user) PATH
        Win32::AdminMisc::SetEnvVar( 'PATH', "$Path;$Dir" );
    }
    return( 1 );
}

sub CopyDir
{
    my( $RemoteDir, $DestDir ) = @_;

    print "Copying files from '$RemoteDir' to '$DestDir' ...\n";

    # XCOPY.EXE will autocreate the destination dir
    `xcopy "$RemoteDir\\*.*" "$DestDir\\*.*" /s`;
}

sub SecureDir
{
    my( $Dir ) = @_;
    my( $Perm, $Result );

    print "Securing the $Dir directory...\n";
    
    `md "$Dir"`;
    
    if( $Perm = new Win32::Perms( $Dir ) )
    {
        # Remove *all* entries...
        $Perm->Remove( -1 );
        
        $Perm->Allow( 'Administrators', FULL_CONTROL_FILE, FILE );
        $Perm->Allow( 'Administrators', FULL_CONTROL_DIR, DIR );
        
        $Perm->Allow( 'Everyone', READ_FILE, FILE );
        $Perm->Allow( 'Everyone', LIST_DIR, DIR );

        $Perm->Owner( 'Administrators' );

        $Result = $Perm->Set();
    }
    else
    {
        print "  Unable to create security descriptor. Directory is not secured.\n";
    }
    
    return( 0 != $Result );
}

sub ConfigDrive
{
    my( $Drive ) = @_;
    my %Info;
  
    print "Configuring the $Drive drive ...\n";
  
    # Make sure that the drive exists
    if( ! -e $Drive )
    {
        print "  The $Drive drive does not exist.\n";
        return( 0 );
    }
    
    # Do we have a fixed hard drive?
    if( DRIVE_FIXED != Win32::AdminMisc::GetDriveType( $Drive ) )
    {
        print "  The $Drive drive is not a local fixed hard drive. Skipping drive formatting.\n";
        return( 0 );
    }
    
    # If the drive is not NTFS then convert it into NTFS
    %Info = Win32::AdminMisc::GetVolumeInfo( $Drive );
    if( 'NTFS' ne $Info{FileSystemName} )
    {
        print "  The $Drive drive is not an NTFS drive.\n";
        print "  Converting from the $Info{FileSystemName} format...\n";
        @{$Log{ntfs_conversion}} = `$NTFS_CONVERSION_APP $Drive $NTFS_CONVERSION_PARAMS`;
    }
    
    return( 1 );
}
