Windows-Server-2003/tools/access.pm

535 lines
20 KiB
Perl
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#-----------------------------------------------------------------//
# Script: access.pm
#
# (c) 2002 Microsoft Corporation. All rights reserved.
#
# decomposes the remote test boot installation run.
#
# Version: <2.31> 06/11/2002 : Serguei Kouzmine
#
#-----------------------------------------------------------------//
use strict;
package access;
no strict 'refs';
use vars (qw());
use WMIFE qw($verbose);
use Logmsg;
use RemoteProc;
use AutoBoottest;
use vars (qw(
$_ReleaseShare
$_ToolShare
$ToolShare
$_BuildArch
$_BldSku
$ForceReboot
$Lang
$MasterMachine
$MasterUserAccount
$MasterUserPassword
$SourcePath
$TargetDrive
$TargetMachine
$TargetSystemDrive
$TargetSystemRoot
$TestUserAccount
$TestUserPassword
$Unattend
$SourceIsDFS
));
use Carp;
my $USAGE =<<USAGE;
Usage:
&access::boottest(
\$TargetMachine, # Target Machine name
\$Lang, # language
\$SourcePath, # Source Path in the form:
\\\\<BUILDMACHINE>\\<RELEASE>\\<LANG>\\<BLDNAME>\\<SKU>\\<ARCH>
or e.g.
\\\\winbuilds\\release\\main\\usa\\latest.tst\\x86fre\\srv\\i386
\$BuildArch # architecture
\$BldSku # sku
\$ToolShare # share to tools \\<BUILDMACHINE>\<TOOLS SHARE NAME>
# leave this parameter undef in the case you use DFS
\$TestUserAccount, # test user (leave empty for DFS install)
\$TestUserPassword, # logon data (leave empty for DFS install)
\$ForceReboot, # reboot switch (1: reboot, 0: dont)
\$SourceIsDFS # this argument must be FALSE unless
# source bits accessible through DFS (see also above)
);
USAGE
my $ToolPath = "NEWTOOLS";
my $TIMEOUT = 5;
my $UNATTEND = q(unattend.$_BuildArch.$_BldSku.txt);
my $RELEASE = "RELEASE";
my $TOOLSHARE = "BOOTTEST";
my $PROCESS = "winnt32.exe";
my $SERVICE = "SCHEDULE";
my $TARGETDRIVE = "D:";
my $TOOLDRIVE = "T:";
my $RELEASEDRIVE = "Y:";
my $VERSION = "2.2";
my $DEBUG = 0;
my $DELAY1 = 120;
my $DELAY2 = 60;
my $DELAY3 = 240;
my $DELAY4 = 10;
my $REPEAT = 30;
my $SYSTEMROOT = $ENV{"SYSTEMROOT"};
my $SYSTEMDRIVE = $ENV{"SYSTEMDRIVE"};
$ENV{"SCRIPT_NAME"} = "access.pm";
my $Results;
my @answ = ();
my @Credentials = ("*");
# start ...
$TargetMachine = undef;
$SourcePath = undef;
$TestUserAccount = undef;
$TestUserPassword = undef;
my $ToolsMachine = undef;
# Usage:
# &access::boottest(
# $TargetMachine, # Target Machine name
# $SourcePath, # path to winnt32.exe, including DFS part name, e.g.
#
# \\winbuilds\release\main\usa\latest.tst\x86fre\srv\i386
# (everything winnt32.exe copies must be in this location or directories therein)
#
# $BuildArch # architecture
# $BldSku # sku
# $ToolShare # share to tools is ignored in DFS case
# $TestUserAccount, # test user is ignored in DFS case
# $TestUserPassword, # logon data is ignored in DFS case
# $Reboot # reboot switch (1: reboot, 0: dont)
# $SourceIsDFS # this argument must be TRUE)
#
#
#
sub boottest{
$TargetMachine = $_[0]; #$machinename
$SourcePath = $_[1]; #path to winnt32
$Lang = $_[2]; #lang
$_BuildArch = $_[3]; #Architechture
$_BldSku = $_[4]; #SKU
$_ToolShare = $_[5]; #path to tools
$Unattend = $_[6]; #unattend file name
$TestUserAccount = $_[7]; #user for release/tools
$TestUserPassword = $_[8]; #pass for user
$ForceReboot = $_[9]; #Force a Reboot <=> DFS install
($MasterMachine, $_ReleaseShare) = $SourcePath =~ /\\\\([^\\]*)\\([^\\]*)\\.*/;
($ToolsMachine, $ToolShare) = $_ToolShare =~ /\\\\([^\\]*)\\(.*)/;
$TargetDrive = $TARGETDRIVE;
$WMIFE::DEBUG = $DEBUG;
$WMIFE::TIMEOUT = $TIMEOUT;
$MasterUserPassword = undef;
$MasterUserAccount = $ENV{"USERDOMAIN"}."\\".$ENV{"USERNAME"};
$Unattend = $UNATTEND;
$Unattend =~ s/\$(\w+)\b/${$1}/eg;
die &WMIFE::pPpPinfo($USAGE) unless defined($TargetMachine);
@Credentials = ($MasterUserAccount, $MasterUserPassword)
unless !$MasterUserPassword;
my $Process = $PROCESS;
my $Service = $SERVICE;
my $ToolDrive = $TOOLDRIVE;
my $ReleaseDrive = $RELEASEDRIVE;
my $sRootKey = $WMIFE::sRootKey;
my $sBootTestDataSubKey = $WMIFE::sBootTestDataSubKey;
my $sLogonUserDataSubKey = $WMIFE::sLogonUserDataSubKey;
my $answ;
$TargetSystemRoot = $SYSTEMROOT;
$TargetSystemDrive = $SYSTEMDRIVE;
$Results = &WMIFE::ExecQuery($TargetMachine, # interactive session
qq(SELECT * FROM Win32_operatingsystem),
[qw(WindowsDirectory)],
@Credentials);
$TargetSystemRoot = $Results->[0]->{"WindowsDirectory"};
$TargetSystemDrive = $TargetSystemRoot;
$TargetSystemDrive =~ s/\\.*$//g;
#=============================================================================
if ($SourceIsDFS){
$ForceReboot = 0;
$DEBUG = 1;
my $hereIsStep;
$hereIsStep =<<PROMPT4PASS;
%SYSTEMROOT%\\SYSTEM32\\CSCRIPT.EXE %RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\wsh.iexplore.dialog.input.wsf
rem Prompt the user for the password
PROMPT4PASS
$DEBUG and
print $hereIsStep, "\n";
my $userData = &WMIFE::BackTick($hereIsStep);
my ($TestUserAccount) = $userData =~ m/BT_U\s+=\s+(.+)/g;
my ($TestUserPassword) = $userData =~ m/BT_P\s+=\s+(.+)/g;
$DEBUG and
print STDERR $TestUserAccount,
"\n",
$TestUserPassword,
"\n";
my $ToolsToCopy = join(" ", qw(
%RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\rx.wsf
%RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\NTCrypt.exe
)) ;
$hereIsStep= <<COPYTOOLS;
REM Creating the directory for tools
md \\\\%TARGETMACHINE%\\%TARGETSYSTREMDRIVE%\\%TOOLPATH%
REM copy everything to the tagret machine
for %. in (%TOOLSTOCOPY%) do @(echo %. & copy %. \\\\%TARGETMACHINE%\\%TARGETSYSTREMDRIVE%\\%TOOLPATH%)
COPYTOOLS
my $_TargetSystemDrive = $TargetSystemDrive;
$_TargetSystemDrive =~ s/\:/\$/;
$hereIsStep =~ s/\%TARGETMACHINE\%/$TargetMachine/g;
$hereIsStep =~ s/\%TARGETSYSTREMDRIVE\%/$_TargetSystemDrive/g;
$hereIsStep =~ s/\%TOOLPATH\%/$ToolPath/g;
$hereIsStep =~ s/\%TOOLSTOCOPY\%/$ToolsToCopy/g;
print STDERR $hereIsStep, "\n";
print &WMIFE::BackTick($hereIsStep);
} # $SourceIsDFS
$answ = undef;
if ($DEBUG){
&logmsg( "Check pending jobs at \\\\$TargetMachine");
my $TasksPath = $TargetSystemRoot ."\\\\TASKS\\\\";
$TasksPath =~ s/^\w:/\\/g;
$Results = &WMIFE::ExecQuery($TargetMachine,
# task files
"SELECT * FROM cim_DataFile WHERE Drive = \"$TargetSystemDrive\" AND Path = \"$TasksPath\" AND FileType Like \"Task Scheduler\%\"",
[qw(FileName FileType Path)],
@Credentials);
foreach my $Result (@$Results){
$DEBUG and
map {&WMIFE::FormatDebugMsg($_, $Result->{$_})}
keys (%$Result);
}
@answ = ();
map {push @answ, $_->{"FileName"}} @$Results;
@answ = grep {/\S/} @answ;
$answ = \@answ;
}
if ($ForceReboot){
&logmsg("Write $sLogonUserDataSubKey on \\\\$TargetMachine");
&WMIFE::supplyRegData($TargetMachine,
"SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION\\WINLOGON",
{
"DefaultUserName" => $TestUserAccount,
"DefaultDomainName" => $TargetMachine,
"DefaultPassword" => $TestUserPassword,
"AutoAdminLogon" => "1",
"ForceAutoLogon" => "1",
"PasswordExpiryWarning" => "0",
},
{},
1);
&logmsg("Reboot \\\\$TargetMachine to have $TestUserAccount logged");
&WMIFE::ObjectExecMethod("Win32_Process",
"Create",
$TargetMachine,
"CommandLine",
"$TargetSystemRoot\\SYSTEM32\\cmd.exe /c USE $RELEASEDRIVE /D&net USE $TOOLDRIVE /D&net USE $TOOLDRIVE $_ToolShare $TestUserPassword /u:$MasterMachine\\$TestUserAccount&$TOOLDRIVE\\autologon.exe /MIGRATE&shutdown.exe /r /m \\\\$TargetMachine /f /t 0",
@Credentials);
#Wait for system to shutdown & come back up
AutoBoottest::WaitOnProcess($TargetMachine, "csrss.exe", -1, "", "");
if(!AutoBoottest::WaitForProcess($TargetMachine, "services.exe", $DELAY3, "", "")){
errmsg("Fatal error: $TargetMachine may have not restarted correctly");
exit(1);
}
sleep($DELAY4); #give it another 10 secs just in case
}
&logmsg("Write $sBootTestDataSubKey on \\\\$TargetMachine");
&WMIFE::supplyRegData($TargetMachine,
"SOFTWARE\\MICROSOFT\\BOOTTEST",
{"LANG" => uc($Lang),
"_BldSku" => uc($_BldSku),
"_BldDrive" => $TargetDrive,
"Unattend" => $Unattend,
"SourcePath" => $SourcePath,
"ToolsPath" => $_ToolShare,
"_BuildArch" => $_BuildArch},
{"COMPUTERNAME" => $ENV{"COMPUTERNAME"}},
1);
&logmsg("Schedule task for $TargetMachine\\\\$TestUserAccount");
my $stLabel = join("_", $Lang,
$_BldSku ) ;
my $res = &wrScheduTsk(
$stLabel,
$TargetMachine,
$TargetSystemRoot,
$ToolDrive,
$ReleaseDrive,
$ToolShare,
$ToolsMachine,
$_ReleaseShare,
$MasterMachine,
$TestUserAccount,
$TestUserPassword,
$SourceIsDFS);
if("0" eq $res){
errmsg("wrScheduTsk failed");
exit(1);
}
#Wait on scheduled task for 1 min - if failed - kill it & try again
if( ! AutoBoottest::WaitForTask($TargetMachine, $res, $DELAY2)){
qx("schtasks /DELETE /S:$TargetMachine /U:$TestUserAccount /P:$TestUserPassword /TN:$res");
&wrScheduTsk($stLabel,
$TargetMachine,
$TargetSystemRoot,
$ToolDrive,
$ReleaseDrive,
$ToolShare,
$ToolsMachine,
$_ReleaseShare,
$MasterMachine,
$TestUserAccount,
$TestUserPassword,
$SourceIsDFS);
if(0 == $res){
errmsg("wrScheduTsk failed");
exit(1);
}
}
#We'll just die if it doesn't work this time
if( ! AutoBoottest::WaitForTask($TargetMachine, $res, $DELAY2)){
errmsg("Error starting task $res on $TargetMachine - exiting");
exit(1);
}
&logmsg("Wait while $TargetMachine's drives are formatted");
# beside checking for format.com it is possible to catch the moment drive is
# being formatted
#&wtDriveReady($TargetMachine, @Credentials);
if((!AutoBoottest::WaitForProcess($TargetMachine, "format.com", 180, "", ""))
||
(!AutoBoottest::WaitOnProcess($TargetMachine, "format.com", 300, "", "")))
{
errmsg("Fatal error: $TargetMachine may not have formatted drives correctly");
exit(1);
}
&logmsg("Verify $Process in \%TARGET\% \(TASK LIST\)");
&AutoBoottest::WaitForProcess($TargetMachine, $Process, $DELAY2, "", "");
$answ = &WMIFE::IsRunning("Win32_Process",
$Process,
"CommandLine",
["ProcessId", "Name" , "CommandLine"],
$TargetMachine);
&logmsg("@$answ");
1;
}
sub wtDriveReady{
my ($TargetMachine, $MasterUserAccount, $MasterUserPassword) = @_;
my $repeat = 0;
$DEBUG and
print STDERR "BVT target drive on $TargetMachine:\n\n";
my $Caption = "";
while (1){
$#$Results = -1;
$Results =
&WMIFE::ExecQuery($TargetMachine, # interactive session
qq(SELECT * FROM win32_logicaldisk Where DriveType = 3 and FileSystem IS NULL),
[qw(VolumeName Caption DriveType FileSystem Description)],
$MasterUserAccount, $MasterUserPassword);
last if scalar(@$Results);
print ".";
print "failed $REPEAT attempts\n" and last unless $repeat++< $REPEAT;
sleep(1);
}
$repeat = 0;
while (1){
$#$Results = -1;
$Results =
&WMIFE::ExecQuery($TargetMachine, # interactive session
qq(SELECT * FROM win32_logicaldisk Where DriveType = 3 and FileSystem IS NULL),
[qw(VolumeName Caption DriveType FileSystem Description)],
$MasterUserAccount, $MasterUserPassword);
last unless scalar(@$Results);
print ".";
print "failed $REPEAT attempts\n" and last unless $repeat++< $REPEAT;
foreach my $Result (@$Results){
$DEBUG and
map {&WMIFE::FormatDebugMsg($_, $Result->{$_})} keys (%$Result);
$Caption = $Result->{"Caption"} if $Result->{"Caption"};
}
sleep(1);
}
}
sub wrScheduTsk{
my (
$stLabel,
$TargetMachine,
$TargetSystemRoot,
$ToolDrive,
$ReleaseDrive,
$ToolShare,
$ToolsMachine,
$_ReleaseShare,
$MasterMachine,
$TestUserAccount,
$TestUserPassword,
$LocalInstall
) = @_;
# $TargetSystemRoot is lest in argument list for it could be needed
my $Schtasks = "schtasks.exe";
my $TaskName = join "_", $stLabel, time;
my $STFilever = qx("ver");
my $StartTime = ( $STFilever =~ /2600/ )? "\%HH\%:\%MM\%:\%SS\%": "\%HH\%:\%MM\%";
# "secs" not needed for TS running in build 36XX.
my $AtCommandTemplate = (!$LocalInstall)?
qq(%SCHTASKS% /create /s %TARGET% /tn %TASKNAME% /u %TARGET%\\%USER% /p %PASSWORD% /sc once /st $StartTime /sd %mm%/%dd%/%yyyy% /tr cmd.exe /C NET USE %TOOLDISK% /D&NET USE %TOOLDISK% %TOOLSHARE% %PASSWORD% /U:%TOOLSMACHINE%\\%USER%&CSCRIPT.EXE %TOOLDISK%\\rx.wsf /from:\\\\%BLDMACHINE%\\%RELEASESHARE% /usedfs")
:
qq(%SCHTASKS% /create /s %TARGET% /tn %TASKNAME% /u %TARGET%\\%USER% /p %PASSWORD% /sc once /st $StartTime /sd %mm%/%dd%/%yyyy% /tr "%SYSTEMROOT%\\SYSTEM32\\cmd.exe /C NET USE %TOOLDISK% /D&NET USE %RELEASEDISK% /D&NET USE %TOOLDISK% %TOOLSHARE% %PASSWORD% /U:%MASTER%\\%USER%&NET USE %RELEASEDISK% \\\\%BLDMACHINE%\\%RELEASESHARE% %PASSWORD% /U:%MASTER%\\%USER%&CSCRIPT.EXE %TOOLDISK%\\rx.wsf /from:\\\\%MASTER%\\%RELEASESHARE%");
# WARNING: Length of the command line argument should not exceed 255 characters
$DEBUG and
print STDERR "AT Command template:\n\"$AtCommandTemplate\"\n";
my $ScheduleTime = &WMIFE::ScheduleTime($DELAY1);
my $marker = ["HH" , "MM", "SS", "mm", "dd", "yyyy"];
my $AtCommand = $AtCommandTemplate;
$AtCommand =~ s/\%TASKNAME\%/$TaskName/g;
$AtCommand =~ s/\%SCHTASKS\%/$Schtasks/g;
$AtCommand =~ s/\%SYSTEMROOT\%/$TargetSystemRoot/g;
$AtCommand =~ s/\%SYSTEMDRIVE\%/$TargetSystemDrive/g;
$AtCommand =~ s/\%ToolPath\%/$ToolPath/g;
$AtCommand =~ s/\%TARGET\%/$TargetMachine/g;
$AtCommand =~ s/\%MASTER\%/$MasterMachine/g;
$AtCommand =~ s/\%TOOLDISK\%/$ToolDrive/g;
$AtCommand =~ s/\%TOOLSMACHINE\%/$ToolsMachine/g;
# we hardcode here that TOOLSHARE is allocated on the TOOLSMACHINE
$AtCommand =~ s/\%TOOLSHARE\%/\\\\$ToolsMachine\\$ToolShare/g;
$AtCommand =~ s/\%RELEASEDISK\%/$ReleaseDrive/g;
$AtCommand =~ s/\%RELEASESHARE\%/$_ReleaseShare/g;
$AtCommand =~ s/\%USER\%/$TestUserAccount/g;
$AtCommand =~ s/\%PASSWORD\%/$TestUserPassword/g;
map {$AtCommand =~ s/\%$marker->[$_]\%/$ScheduleTime->[$_]/g;} (0..$#$marker);
for my $i (qx("net use")){
# win32_share ?
($i =~ /\w*\s*(\\\\$TargetMachine\\\w*\$+).*/) &&
$DEBUG ? print `net use $1 /delete /y 2>&1` :
`net use $1 /delete /y 2>&1`;
}
$DEBUG and
print STDERR "$AtCommand\n";
system($AtCommand);
$TaskName;
}
1;
__END__
=head1 Scheduled autoboottest control flow.
=head2 RELEASE is accessed from MASTER SHARE
MASTER: create TARGET->TESTUSER
MASTER: create MASTER->TESTUSER
MASTER: create MASTER->TOOLSHARE
MASTER: share MASTER->RELEASESHARE for MASTER->TESTUSER
MASTER: WRITE TARGET->REGISTRY (logon data)
MASTER: reboot TARGET
MASTER: WRITE TARGET->REGISTRY (encrypted password)
MASTER: schedule TASK for TARGET->TESTUSER
MASTER: wait for TASK steps to be passed
TARGET: execute TASK SCRIPT from MASTER->TOOLSHARE
TASK SCRIPT: FORMAT TARGET->TESTDRIVE
TASK SCRIPT: HANDLE TARGET->BOOT OPTIONS
TASK SCRIPT: start INSTALLATION from MASTER->RELEASESHARE
=head2 RELEASE is accessed through DFS
MASTER: create TARGET->SYSTEMDRIVE->TOOLDIR
MASTER: copy scripts and binaries to the TARGET
MASTER: WRITE TARGET->REGISTRY (build info)
MASTER: prompt user for password and encrypt it
MASTER: WRITE TARGET->REGISTRY (encrypted password)
MASTER: schedule TASK for TARGET->NT AUTHORITY\SYSTEM
MASTER: wait for TASK steps to be passed
TARGET: execute TASK SCRIPT from TARGET->SYSTEMDRIVE->TOOLDIR
TASK SCRIPT: DECRYPT MASTER password and get access to DFSSHARE
TASK SCRIPT: FORMAT TARGET->TESTDRIVE
TASK SCRIPT: HANDLE TARGET->BOOT OPTIONS
TASK SCRIPT: start INSTALLATION from DFSSHARE
=head2 Note. This is a bare bones implementation.
Room for structural improvement is:
* providing the Test Machine status reflection in
REGISTRY and/or FILESYSTEM areas visible from Build Machine.
* manipulate settings to record the winnt32.exe messages to ease
break analysis