Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

534 lines
20 KiB

  1. #-----------------------------------------------------------------//
  2. # Script: access.pm
  3. #
  4. # (c) 2002 Microsoft Corporation. All rights reserved.
  5. #
  6. # decomposes the remote test boot installation run.
  7. #
  8. # Version: <2.31> 06/11/2002 : Serguei Kouzmine
  9. #
  10. #-----------------------------------------------------------------//
  11. use strict;
  12. package access;
  13. no strict 'refs';
  14. use vars (qw());
  15. use WMIFE qw($verbose);
  16. use Logmsg;
  17. use RemoteProc;
  18. use AutoBoottest;
  19. use vars (qw(
  20. $_ReleaseShare
  21. $_ToolShare
  22. $ToolShare
  23. $_BuildArch
  24. $_BldSku
  25. $ForceReboot
  26. $Lang
  27. $MasterMachine
  28. $MasterUserAccount
  29. $MasterUserPassword
  30. $SourcePath
  31. $TargetDrive
  32. $TargetMachine
  33. $TargetSystemDrive
  34. $TargetSystemRoot
  35. $TestUserAccount
  36. $TestUserPassword
  37. $Unattend
  38. $SourceIsDFS
  39. ));
  40. use Carp;
  41. my $USAGE =<<USAGE;
  42. Usage:
  43. &access::boottest(
  44. \$TargetMachine, # Target Machine name
  45. \$Lang, # language
  46. \$SourcePath, # Source Path in the form:
  47. \\\\<BUILDMACHINE>\\<RELEASE>\\<LANG>\\<BLDNAME>\\<SKU>\\<ARCH>
  48. or e.g.
  49. \\\\winbuilds\\release\\main\\usa\\latest.tst\\x86fre\\srv\\i386
  50. \$BuildArch # architecture
  51. \$BldSku # sku
  52. \$ToolShare # share to tools \\<BUILDMACHINE>\<TOOLS SHARE NAME>
  53. # leave this parameter undef in the case you use DFS
  54. \$TestUserAccount, # test user (leave empty for DFS install)
  55. \$TestUserPassword, # logon data (leave empty for DFS install)
  56. \$ForceReboot, # reboot switch (1: reboot, 0: don�t)
  57. \$SourceIsDFS # this argument must be FALSE unless
  58. # source bits accessible through DFS (see also above)
  59. );
  60. USAGE
  61. my $ToolPath = "NEWTOOLS";
  62. my $TIMEOUT = 5;
  63. my $UNATTEND = q(unattend.$_BuildArch.$_BldSku.txt);
  64. my $RELEASE = "RELEASE";
  65. my $TOOLSHARE = "BOOTTEST";
  66. my $PROCESS = "winnt32.exe";
  67. my $SERVICE = "SCHEDULE";
  68. my $TARGETDRIVE = "D:";
  69. my $TOOLDRIVE = "T:";
  70. my $RELEASEDRIVE = "Y:";
  71. my $VERSION = "2.2";
  72. my $DEBUG = 0;
  73. my $DELAY1 = 120;
  74. my $DELAY2 = 60;
  75. my $DELAY3 = 240;
  76. my $DELAY4 = 10;
  77. my $REPEAT = 30;
  78. my $SYSTEMROOT = $ENV{"SYSTEMROOT"};
  79. my $SYSTEMDRIVE = $ENV{"SYSTEMDRIVE"};
  80. $ENV{"SCRIPT_NAME"} = "access.pm";
  81. my $Results;
  82. my @answ = ();
  83. my @Credentials = ("*");
  84. # start ...
  85. $TargetMachine = undef;
  86. $SourcePath = undef;
  87. $TestUserAccount = undef;
  88. $TestUserPassword = undef;
  89. my $ToolsMachine = undef;
  90. # Usage:
  91. # &access::boottest(
  92. # $TargetMachine, # Target Machine name
  93. # $SourcePath, # path to winnt32.exe, including DFS part name, e.g.
  94. #
  95. # \\winbuilds\release\main\usa\latest.tst\x86fre\srv\i386
  96. # (everything winnt32.exe copies must be in this location or directories therein)
  97. #
  98. # $BuildArch # architecture
  99. # $BldSku # sku
  100. # $ToolShare # share to tools is ignored in DFS case
  101. # $TestUserAccount, # test user is ignored in DFS case
  102. # $TestUserPassword, # logon data is ignored in DFS case
  103. # $Reboot # reboot switch (1: reboot, 0: don�t)
  104. # $SourceIsDFS # this argument must be TRUE)
  105. #
  106. #
  107. #
  108. sub boottest{
  109. $TargetMachine = $_[0]; #$machinename
  110. $SourcePath = $_[1]; #path to winnt32
  111. $Lang = $_[2]; #lang
  112. $_BuildArch = $_[3]; #Architechture
  113. $_BldSku = $_[4]; #SKU
  114. $_ToolShare = $_[5]; #path to tools
  115. $Unattend = $_[6]; #unattend file name
  116. $TestUserAccount = $_[7]; #user for release/tools
  117. $TestUserPassword = $_[8]; #pass for user
  118. $ForceReboot = $_[9]; #Force a Reboot <=> DFS install
  119. ($MasterMachine, $_ReleaseShare) = $SourcePath =~ /\\\\([^\\]*)\\([^\\]*)\\.*/;
  120. ($ToolsMachine, $ToolShare) = $_ToolShare =~ /\\\\([^\\]*)\\(.*)/;
  121. $TargetDrive = $TARGETDRIVE;
  122. $WMIFE::DEBUG = $DEBUG;
  123. $WMIFE::TIMEOUT = $TIMEOUT;
  124. $MasterUserPassword = undef;
  125. $MasterUserAccount = $ENV{"USERDOMAIN"}."\\".$ENV{"USERNAME"};
  126. $Unattend = $UNATTEND;
  127. $Unattend =~ s/\$(\w+)\b/${$1}/eg;
  128. die &WMIFE::pPpPinfo($USAGE) unless defined($TargetMachine);
  129. @Credentials = ($MasterUserAccount, $MasterUserPassword)
  130. unless !$MasterUserPassword;
  131. my $Process = $PROCESS;
  132. my $Service = $SERVICE;
  133. my $ToolDrive = $TOOLDRIVE;
  134. my $ReleaseDrive = $RELEASEDRIVE;
  135. my $sRootKey = $WMIFE::sRootKey;
  136. my $sBootTestDataSubKey = $WMIFE::sBootTestDataSubKey;
  137. my $sLogonUserDataSubKey = $WMIFE::sLogonUserDataSubKey;
  138. my $answ;
  139. $TargetSystemRoot = $SYSTEMROOT;
  140. $TargetSystemDrive = $SYSTEMDRIVE;
  141. $Results = &WMIFE::ExecQuery($TargetMachine, # interactive session
  142. qq(SELECT * FROM Win32_operatingsystem),
  143. [qw(WindowsDirectory)],
  144. @Credentials);
  145. $TargetSystemRoot = $Results->[0]->{"WindowsDirectory"};
  146. $TargetSystemDrive = $TargetSystemRoot;
  147. $TargetSystemDrive =~ s/\\.*$//g;
  148. #=============================================================================
  149. if ($SourceIsDFS){
  150. $ForceReboot = 0;
  151. $DEBUG = 1;
  152. my $hereIsStep;
  153. $hereIsStep =<<PROMPT4PASS;
  154. %SYSTEMROOT%\\SYSTEM32\\CSCRIPT.EXE %RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\wsh.iexplore.dialog.input.wsf
  155. rem Prompt the user for the password
  156. PROMPT4PASS
  157. $DEBUG and
  158. print $hereIsStep, "\n";
  159. my $userData = &WMIFE::BackTick($hereIsStep);
  160. my ($TestUserAccount) = $userData =~ m/BT_U\s+=\s+(.+)/g;
  161. my ($TestUserPassword) = $userData =~ m/BT_P\s+=\s+(.+)/g;
  162. $DEBUG and
  163. print STDERR $TestUserAccount,
  164. "\n",
  165. $TestUserPassword,
  166. "\n";
  167. my $ToolsToCopy = join(" ", qw(
  168. %RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\rx.wsf
  169. %RAZZLETOOLPATH%\\POSTBUILDSCRIPTS\\NTCrypt.exe
  170. )) ;
  171. $hereIsStep= <<COPYTOOLS;
  172. REM Creating the directory for tools
  173. md \\\\%TARGETMACHINE%\\%TARGETSYSTREMDRIVE%\\%TOOLPATH%
  174. REM copy everything to the tagret machine
  175. for %. in (%TOOLSTOCOPY%) do @(echo %. & copy %. \\\\%TARGETMACHINE%\\%TARGETSYSTREMDRIVE%\\%TOOLPATH%)
  176. COPYTOOLS
  177. my $_TargetSystemDrive = $TargetSystemDrive;
  178. $_TargetSystemDrive =~ s/\:/\$/;
  179. $hereIsStep =~ s/\%TARGETMACHINE\%/$TargetMachine/g;
  180. $hereIsStep =~ s/\%TARGETSYSTREMDRIVE\%/$_TargetSystemDrive/g;
  181. $hereIsStep =~ s/\%TOOLPATH\%/$ToolPath/g;
  182. $hereIsStep =~ s/\%TOOLSTOCOPY\%/$ToolsToCopy/g;
  183. print STDERR $hereIsStep, "\n";
  184. print &WMIFE::BackTick($hereIsStep);
  185. } # $SourceIsDFS
  186. $answ = undef;
  187. if ($DEBUG){
  188. &logmsg( "Check pending jobs at \\\\$TargetMachine");
  189. my $TasksPath = $TargetSystemRoot ."\\\\TASKS\\\\";
  190. $TasksPath =~ s/^\w:/\\/g;
  191. $Results = &WMIFE::ExecQuery($TargetMachine,
  192. # task files
  193. "SELECT * FROM cim_DataFile WHERE Drive = \"$TargetSystemDrive\" AND Path = \"$TasksPath\" AND FileType Like \"Task Scheduler\%\"",
  194. [qw(FileName FileType Path)],
  195. @Credentials);
  196. foreach my $Result (@$Results){
  197. $DEBUG and
  198. map {&WMIFE::FormatDebugMsg($_, $Result->{$_})}
  199. keys (%$Result);
  200. }
  201. @answ = ();
  202. map {push @answ, $_->{"FileName"}} @$Results;
  203. @answ = grep {/\S/} @answ;
  204. $answ = \@answ;
  205. }
  206. if ($ForceReboot){
  207. &logmsg("Write $sLogonUserDataSubKey on \\\\$TargetMachine");
  208. &WMIFE::supplyRegData($TargetMachine,
  209. "SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION\\WINLOGON",
  210. {
  211. "DefaultUserName" => $TestUserAccount,
  212. "DefaultDomainName" => $TargetMachine,
  213. "DefaultPassword" => $TestUserPassword,
  214. "AutoAdminLogon" => "1",
  215. "ForceAutoLogon" => "1",
  216. "PasswordExpiryWarning" => "0",
  217. },
  218. {},
  219. 1);
  220. &logmsg("Reboot \\\\$TargetMachine to have $TestUserAccount logged");
  221. &WMIFE::ObjectExecMethod("Win32_Process",
  222. "Create",
  223. $TargetMachine,
  224. "CommandLine",
  225. "$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",
  226. @Credentials);
  227. #Wait for system to shutdown & come back up
  228. AutoBoottest::WaitOnProcess($TargetMachine, "csrss.exe", -1, "", "");
  229. if(!AutoBoottest::WaitForProcess($TargetMachine, "services.exe", $DELAY3, "", "")){
  230. errmsg("Fatal error: $TargetMachine may have not restarted correctly");
  231. exit(1);
  232. }
  233. sleep($DELAY4); #give it another 10 secs just in case
  234. }
  235. &logmsg("Write $sBootTestDataSubKey on \\\\$TargetMachine");
  236. &WMIFE::supplyRegData($TargetMachine,
  237. "SOFTWARE\\MICROSOFT\\BOOTTEST",
  238. {"LANG" => uc($Lang),
  239. "_BldSku" => uc($_BldSku),
  240. "_BldDrive" => $TargetDrive,
  241. "Unattend" => $Unattend,
  242. "SourcePath" => $SourcePath,
  243. "ToolsPath" => $_ToolShare,
  244. "_BuildArch" => $_BuildArch},
  245. {"COMPUTERNAME" => $ENV{"COMPUTERNAME"}},
  246. 1);
  247. &logmsg("Schedule task for $TargetMachine\\\\$TestUserAccount");
  248. my $stLabel = join("_", $Lang,
  249. $_BldSku ) ;
  250. my $res = &wrScheduTsk(
  251. $stLabel,
  252. $TargetMachine,
  253. $TargetSystemRoot,
  254. $ToolDrive,
  255. $ReleaseDrive,
  256. $ToolShare,
  257. $ToolsMachine,
  258. $_ReleaseShare,
  259. $MasterMachine,
  260. $TestUserAccount,
  261. $TestUserPassword,
  262. $SourceIsDFS);
  263. if("0" eq $res){
  264. errmsg("wrScheduTsk failed");
  265. exit(1);
  266. }
  267. #Wait on scheduled task for 1 min - if failed - kill it & try again
  268. if( ! AutoBoottest::WaitForTask($TargetMachine, $res, $DELAY2)){
  269. qx("schtasks /DELETE /S:$TargetMachine /U:$TestUserAccount /P:$TestUserPassword /TN:$res");
  270. &wrScheduTsk($stLabel,
  271. $TargetMachine,
  272. $TargetSystemRoot,
  273. $ToolDrive,
  274. $ReleaseDrive,
  275. $ToolShare,
  276. $ToolsMachine,
  277. $_ReleaseShare,
  278. $MasterMachine,
  279. $TestUserAccount,
  280. $TestUserPassword,
  281. $SourceIsDFS);
  282. if(0 == $res){
  283. errmsg("wrScheduTsk failed");
  284. exit(1);
  285. }
  286. }
  287. #We'll just die if it doesn't work this time
  288. if( ! AutoBoottest::WaitForTask($TargetMachine, $res, $DELAY2)){
  289. errmsg("Error starting task $res on $TargetMachine - exiting");
  290. exit(1);
  291. }
  292. &logmsg("Wait while $TargetMachine's drives are formatted");
  293. # beside checking for format.com it is possible to catch the moment drive is
  294. # being formatted
  295. #&wtDriveReady($TargetMachine, @Credentials);
  296. if((!AutoBoottest::WaitForProcess($TargetMachine, "format.com", 180, "", ""))
  297. ||
  298. (!AutoBoottest::WaitOnProcess($TargetMachine, "format.com", 300, "", "")))
  299. {
  300. errmsg("Fatal error: $TargetMachine may not have formatted drives correctly");
  301. exit(1);
  302. }
  303. &logmsg("Verify $Process in \%TARGET\% \(TASK LIST\)");
  304. &AutoBoottest::WaitForProcess($TargetMachine, $Process, $DELAY2, "", "");
  305. $answ = &WMIFE::IsRunning("Win32_Process",
  306. $Process,
  307. "CommandLine",
  308. ["ProcessId", "Name" , "CommandLine"],
  309. $TargetMachine);
  310. &logmsg("@$answ");
  311. 1;
  312. }
  313. sub wtDriveReady{
  314. my ($TargetMachine, $MasterUserAccount, $MasterUserPassword) = @_;
  315. my $repeat = 0;
  316. $DEBUG and
  317. print STDERR "BVT target drive on $TargetMachine:\n\n";
  318. my $Caption = "";
  319. while (1){
  320. $#$Results = -1;
  321. $Results =
  322. &WMIFE::ExecQuery($TargetMachine, # interactive session
  323. qq(SELECT * FROM win32_logicaldisk Where DriveType = 3 and FileSystem IS NULL),
  324. [qw(VolumeName Caption DriveType FileSystem Description)],
  325. $MasterUserAccount, $MasterUserPassword);
  326. last if scalar(@$Results);
  327. print ".";
  328. print "failed $REPEAT attempts\n" and last unless $repeat++< $REPEAT;
  329. sleep(1);
  330. }
  331. $repeat = 0;
  332. while (1){
  333. $#$Results = -1;
  334. $Results =
  335. &WMIFE::ExecQuery($TargetMachine, # interactive session
  336. qq(SELECT * FROM win32_logicaldisk Where DriveType = 3 and FileSystem IS NULL),
  337. [qw(VolumeName Caption DriveType FileSystem Description)],
  338. $MasterUserAccount, $MasterUserPassword);
  339. last unless scalar(@$Results);
  340. print ".";
  341. print "failed $REPEAT attempts\n" and last unless $repeat++< $REPEAT;
  342. foreach my $Result (@$Results){
  343. $DEBUG and
  344. map {&WMIFE::FormatDebugMsg($_, $Result->{$_})} keys (%$Result);
  345. $Caption = $Result->{"Caption"} if $Result->{"Caption"};
  346. }
  347. sleep(1);
  348. }
  349. }
  350. sub wrScheduTsk{
  351. my (
  352. $stLabel,
  353. $TargetMachine,
  354. $TargetSystemRoot,
  355. $ToolDrive,
  356. $ReleaseDrive,
  357. $ToolShare,
  358. $ToolsMachine,
  359. $_ReleaseShare,
  360. $MasterMachine,
  361. $TestUserAccount,
  362. $TestUserPassword,
  363. $LocalInstall
  364. ) = @_;
  365. # $TargetSystemRoot is lest in argument list for it could be needed
  366. my $Schtasks = "schtasks.exe";
  367. my $TaskName = join "_", $stLabel, time;
  368. my $STFilever = qx("ver");
  369. my $StartTime = ( $STFilever =~ /2600/ )? "\%HH\%:\%MM\%:\%SS\%": "\%HH\%:\%MM\%";
  370. # "secs" not needed for TS running in build 36XX.
  371. my $AtCommandTemplate = (!$LocalInstall)?
  372. 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")
  373. :
  374. 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%");
  375. # WARNING: Length of the command line argument should not exceed 255 characters
  376. $DEBUG and
  377. print STDERR "AT Command template:\n\"$AtCommandTemplate\"\n";
  378. my $ScheduleTime = &WMIFE::ScheduleTime($DELAY1);
  379. my $marker = ["HH" , "MM", "SS", "mm", "dd", "yyyy"];
  380. my $AtCommand = $AtCommandTemplate;
  381. $AtCommand =~ s/\%TASKNAME\%/$TaskName/g;
  382. $AtCommand =~ s/\%SCHTASKS\%/$Schtasks/g;
  383. $AtCommand =~ s/\%SYSTEMROOT\%/$TargetSystemRoot/g;
  384. $AtCommand =~ s/\%SYSTEMDRIVE\%/$TargetSystemDrive/g;
  385. $AtCommand =~ s/\%ToolPath\%/$ToolPath/g;
  386. $AtCommand =~ s/\%TARGET\%/$TargetMachine/g;
  387. $AtCommand =~ s/\%MASTER\%/$MasterMachine/g;
  388. $AtCommand =~ s/\%TOOLDISK\%/$ToolDrive/g;
  389. $AtCommand =~ s/\%TOOLSMACHINE\%/$ToolsMachine/g;
  390. # we hardcode here that TOOLSHARE is allocated on the TOOLSMACHINE
  391. $AtCommand =~ s/\%TOOLSHARE\%/\\\\$ToolsMachine\\$ToolShare/g;
  392. $AtCommand =~ s/\%RELEASEDISK\%/$ReleaseDrive/g;
  393. $AtCommand =~ s/\%RELEASESHARE\%/$_ReleaseShare/g;
  394. $AtCommand =~ s/\%USER\%/$TestUserAccount/g;
  395. $AtCommand =~ s/\%PASSWORD\%/$TestUserPassword/g;
  396. map {$AtCommand =~ s/\%$marker->[$_]\%/$ScheduleTime->[$_]/g;} (0..$#$marker);
  397. for my $i (qx("net use")){
  398. # win32_share ?
  399. ($i =~ /\w*\s*(\\\\$TargetMachine\\\w*\$+).*/) &&
  400. $DEBUG ? print `net use $1 /delete /y 2>&1` :
  401. `net use $1 /delete /y 2>&1`;
  402. }
  403. $DEBUG and
  404. print STDERR "$AtCommand\n";
  405. system($AtCommand);
  406. $TaskName;
  407. }
  408. 1;
  409. __END__
  410. =head1 Scheduled autoboottest control flow.
  411. =head2 RELEASE is accessed from MASTER SHARE
  412. MASTER: create TARGET->TESTUSER
  413. MASTER: create MASTER->TESTUSER
  414. MASTER: create MASTER->TOOLSHARE
  415. MASTER: share MASTER->RELEASESHARE for MASTER->TESTUSER
  416. MASTER: WRITE TARGET->REGISTRY (logon data)
  417. MASTER: reboot TARGET
  418. MASTER: WRITE TARGET->REGISTRY (encrypted password)
  419. MASTER: schedule TASK for TARGET->TESTUSER
  420. MASTER: wait for TASK steps to be passed
  421. TARGET: execute TASK SCRIPT from MASTER->TOOLSHARE
  422. TASK SCRIPT: FORMAT TARGET->TESTDRIVE
  423. TASK SCRIPT: HANDLE TARGET->BOOT OPTIONS
  424. TASK SCRIPT: start INSTALLATION from MASTER->RELEASESHARE
  425. =head2 RELEASE is accessed through DFS
  426. MASTER: create TARGET->SYSTEMDRIVE->TOOLDIR
  427. MASTER: copy scripts and binaries to the TARGET
  428. MASTER: WRITE TARGET->REGISTRY (build info)
  429. MASTER: prompt user for password and encrypt it
  430. MASTER: WRITE TARGET->REGISTRY (encrypted password)
  431. MASTER: schedule TASK for TARGET->NT AUTHORITY\SYSTEM
  432. MASTER: wait for TASK steps to be passed
  433. TARGET: execute TASK SCRIPT from TARGET->SYSTEMDRIVE->TOOLDIR
  434. TASK SCRIPT: DECRYPT MASTER password and get access to DFSSHARE
  435. TASK SCRIPT: FORMAT TARGET->TESTDRIVE
  436. TASK SCRIPT: HANDLE TARGET->BOOT OPTIONS
  437. TASK SCRIPT: start INSTALLATION from DFSSHARE
  438. =head2 Note. This is a bare bones implementation.
  439. Room for structural improvement is:
  440. * providing the Test Machine status reflection in
  441. REGISTRY and/or FILESYSTEM areas visible from Build Machine.
  442. * manipulate settings to record the winnt32.exe messages to ease
  443. break analysis