#--------------------------------------------------------------------- package AutoBoottest; # Copyright (c) Microsoft Corporation. All rights reserved. # # Version: 1.00 (01/01/2002) : TSanders # # Purpose: Collection of tools used in autoboottest.pl #--------------------------------------------------------------------- use vars qw($VERSION); $VERSION = '1.00'; use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts"; use lib $ENV{RAZZLETOOLPATH}; use Logmsg; use Win32::OLE; use Win32::OLE::Enum; use strict; my $ABTShare = "ABTRelease"; my $ABTWorkDir = "AutoBoottest"; #--------------------------------------------------------------------- # Copy - copy file to dest # # In: $file, $dest # #--------------------------------------------------------------------- sub Copy($$) { my($file, $dest) = @_; if( `copy $file $dest` =~ /0 file/ ) { errmsg("Couldn't copy $file to $dest"); return 0; } return 1; } #--------------------------------------------------------------------- # RebootAndWait - Shutdown $target & wait for it to reboot # # In: Machine, user, pass # #--------------------------------------------------------------------- sub RebootAndWait($$$$) { my($target, $user, $pass) = @_; } #--------------------------------------------------------------------- # WaitForTask - wait for scheduled task $name to start # # In: Machine, task name, timeout, user pass # #--------------------------------------------------------------------- sub WaitForTask($$$) { my($target, $name, $timeout) = @_; my ($res, $time); $res = `schtasks /query /s $target`; if($res !~ /$name/){ errmsg "Task: $name doesn't exist on $target"; return 0; } if($res =~ /Could not start/){ errmsg "Task: $name failed to start"; return 0; } print("\nWaiting on task $name to start."); $time = $timeout; while($time--) { $res = `schtasks /query /s $target`; my($tm, $stat) = ( $res =~ /$name\s{1,40}(.{0,25})\s{2,25}(.*)/i ); last if ($stat =~ /running/i); if($tm =~ /never/i){ errmsg "Task: $name didn't schedule correctly"; return 0; } if( $tm =~ /(.+):(.+):.+,.+/ ){ my($s, $m, $h, $d) = localtime; if( $h >= $1 && $m >= $2 && ( $stat !~ /running/i )) { errmsg "Task: $name didn't start"; return 0; } } print "."; sleep 1; } if(0 >= $time && $timeout > 0){ print("timeout hit.\n"); return 0; } #print("\nWating on task to complete."); #while($timeout--) #{ # $res = `schtasks /query /s $target`; # last if ($res =~ /$name\s*never\s*running.*/i || # $res =~ /$name\s*never\s*/i || # (!($res =~ /$name/))); # #last if ($res =~ /$name/); # print "."; # sleep 1; #} print "\n"; return 1; } #--------------------------------------------------------------------- # WaitForProcess - wait for $processname to begin # # In: Machine, process name to wait on, timeout, user, pass # Note: timeout < 0 == infinity #--------------------------------------------------------------------- sub WaitForProcess($$$$$) { my ($target, $procname, $timeout, $user, $pass) = @_; my (@res, $oADSIDom, $wbemLocator, $remote_services, $oServ, $res, $proc, $resultArray, $resultRef); my $Time = $timeout; defined($procname) or return 0; $wbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); (OLE_errmsg("Could not instatiate WbemScripting.SWbemLocator") && return 0 ) if ( !defined $wbemLocator ); print("\nWaiting for process to begin: $procname."); while($Time--){ eval{ defined($user) ? $remote_services = $wbemLocator->ConnectServer( "$target", "root\\cimv2", $user, $pass ): $remote_services = $wbemLocator->ConnectServer("$target"); $resultArray = $remote_services->ExecQuery("Select * From Win32_Process Where Name ='$procname'"); $resultRef = [ (in $resultArray) ]; last if( shift(@$resultRef)); print "."; sleep 1; undef $remote_services; }; if($@){ print("x"); sleep 1; undef $remote_services; } } undef $remote_services; undef $wbemLocator; if(0 >= $Time && $timeout > 0) { print("timeout hit.\n"); return 0; } print("done\n"); return 1; } #--------------------------------------------------------------------- # WaitOnProcess - wait on $processname till it ends # # In: Machine, process name to wait on, user, pass # #--------------------------------------------------------------------- sub WaitOnProcess($$$$$) { my ($target, $procname, $timeout, $user, $pass) = @_; my (@res, $oADSIDom, $wbemLocator, $remote_services, $oServ, $res, $proc, $resultArray, $resultRef); my $Time = $timeout; defined($procname) or return 0; $wbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); (OLE_errmsg("Could not instatiate WbemScripting.SWbemLocator") && return 0 ) if ( !defined $wbemLocator ); defined($user) ? $remote_services = $wbemLocator->ConnectServer( "$target", "root\\cimv2", $user, $pass ): $remote_services = $wbemLocator->ConnectServer( "$target"); (OLE_errmsg("Couldn't connect to $target") && return 0 ) if (!defined $remote_services); print("\nWaiting on process: $procname."); while($Time--){ eval{ $resultArray = $remote_services->ExecQuery("Select * From Win32_Process Where Name ='$procname'"); last if( ! defined $resultArray ); $resultRef = [ (in $resultArray) ]; last if( ! shift(@$resultRef)); print "."; sleep 2; }; if($@){ OLE_errmsg("Fatal error: $@"); undef $remote_services; undef $wbemLocator; return 0; } } undef $remote_services; undef $wbemLocator; if(0 >= $Time && $timeout > 0) { print("timeout hit.\n"); return 0; } print("done\n"); return 1; } #--------------------------------------------------------------------- # CreateUserShare - Create a temporary 'autoboottest' user & grant # read access to autoboottest share. # # In: User, target Machine, host machine, source to share, local tools share # Out: Password # #--------------------------------------------------------------------- sub CreateUserShare($$$$$) { my ($sUser, $target, $host, $sShare, $sLocShare) = @_; my ($res, $Pass, $oNewUser, $oShare, $oADSIObj, $oADSIDom, $oNewUser, $oGroup); #Generate random pass $Pass = sprintf("%s%i%s", "!a", rand(10000), "a!"); #DEBUGUG $Pass = "_Monday_"; #If we're not dealing w/ a DFS source #if($sShare ne ""){ #Create Boottest User on Target machine & Add to administrators $oADSIDom=Win32::OLE->GetObject("WinNT://$target"); if (!defined $oADSIDom){ OLE_errmsg("Can't connect to $target:"); return 0; } if ($oNewUser = Win32::OLE->GetObject("WinNT://$target/$sUser")){ logmsg("User $target\\$sUser already exists"); $oNewUser->SetPassword($Pass); $oNewUser->SetInfo(); undef $oNewUser; logmsg("Successfully updated pass for $target\\$sUser"); } else{ if ($oNewUser = $oADSIDom->Create("user",$sUser)) { $oNewUser->{FullName} = "Autoboottester"; $oNewUser->{Description} = "Autoboottest account"; $oNewUser->{PasswordExpired} = 0; $oNewUser->SetInfo(); $oNewUser->SetPassword($Pass); $oNewUser->SetInfo(); undef $oNewUser; logmsg ("Successfully created $target\\$sUser"); } } $oGroup = Win32::OLE->GetObject("WinNT://$target/Administrators"); OLE_errmsg("Can't get Administators group") if(!defined $oGroup); if($oGroup->Add("WinNT://$target/$sUser")){ if(Win32::OLE->LastError() =~ /is already a/i){ logmsg("$target\\$sUser is already a member of the Administrators group"); }else{ OLE_errmsg("Couldn't add $target\\$sUser to Administrators group"); return 0; } } undef $oGroup; undef $oADSIDom; #} #Now create local user for Boottest dir $oADSIDom=Win32::OLE->GetObject("WinNT://$host"); if (!defined $oADSIDom){ OLE_errmsg("Can't connect to $host:"); return 0; } if ($oNewUser = Win32::OLE->GetObject("WinNT://$host/$sUser")){ logmsg("User $host\\$sUser already exists"); $oNewUser->SetPassword($Pass); $oNewUser->SetInfo(); undef $oNewUser; logmsg("Successfully updated pass for $target\\$sUser"); } else{ if ($oNewUser = $oADSIDom->Create("user",$sUser)) { $oNewUser->{FullName} = "Autoboottester"; $oNewUser->{Description} = "Autoboottest account"; $oNewUser->{PasswordExpired} = 0; $oNewUser->SetInfo(); $oNewUser->SetPassword($Pass); $oNewUser->SetInfo(); undef $oNewUser; logmsg ("Successfully created $host\\$sUser"); } } undef $oADSIDom; #Grant read access to release share if not DFS share if($sShare ne ""){ $res = `rmtshare \\\\$host\\release /GRANT $sUser:r`; if($res =~ /error|failed/i) { errmsg("Couldn't grant access to \\\\$host\\release for $sUser: $res"); return 0; } logmsg("User $sUser successfully granted read access"); } #Create local tools share $res = `rmtshare \\\\$host\\Boottest=$sLocShare`; if($res =~ /error|failed/i) { if($res =~ /2118/){ logmsg("\\\\$host\\Boottest already exists"); }else{ errmsg("Couldn't create share \\\\$host\\Boottest: $res"); return 0; } } $res = `rmtshare \\\\$host\\Boottest /GRANT $sUser:r`; if($res =~ /error|failed/i) { errmsg("Couldn't grant access to \\\\$host\\Boottest for $sUser: $res"); return 0; } `rmtshare \\\\$host\\Boottest /remove everyone`; logmsg("Successfully created \\\\$host\\Boottest"); return $Pass; } #--------------------------------------------------------------------- # CleanupUserShare - Delete user & remove autoboottest share. # # In: User, Machine, source to share # #--------------------------------------------------------------------- sub CleanupUserShare($$$$$) { #NEED TO WORK ON THIS!!!### my ($sUser, $sDomain, $sShare, $sLocShare, $target) = @_; my ($res, $oADSIDom); #Remove access to release & tools shares $res = `rmtshare \\\\$sDomain\\$sShare /grant $sUser:`; if($res =~ /error|failed/i) { errmsg("Couldn't deny access for $sUser to share \\\\$sDomain\\$sShare: $res"); return -1; } logmsg("Successfully removed access for $sUser to \\\\$sDomain\\$sShare"); $res = `rmtshare \\\\$sDomain\\$sLocShare /grant $sUser:`; if($res =~ /error|failed/i) { errmsg("Couldn't deny access for $sUser to share $sLocShare: $res"); return -1; } logmsg("Successfully removed access for $sUser to $sLocShare"); #Delete User $oADSIDom=Win32::OLE->GetObject("WinNT://$sDomain"); OLE_errmsg("Can't connect to $sDomain:") if (!defined $oADSIDom); if(!Win32::OLE->GetObject("WinNT://$sDomain/$sUser")){ OLE_errmsg("User $sUser doesn't exist"); } else{ $oADSIDom->Delete("user",$sUser); logmsg ("Successfully deleted $sDomain\\$sUser"); } if(!Win32::OLE->GetObject("WinNT://$target/$sUser")){ OLE_errmsg("User $sUser doesn't exist"); } else{ $oADSIDom->Delete("user",$sUser); logmsg ("Successfully deleted $target\\$sUser"); } #Delete temp dir logmsg ("removing $sLocShare dir"); print `rd /s /q $sLocShare`; #Clean any residual connections for my $i (`net use`){ ($i =~ /\w*\s*(\\\\$target\\\w*\$+).*/) && `net use $1 /delete /y 2>&1`; } return 1; } #--------------------------------------------------------------------- # EncryptPK - Wrap NTBCrypt.exe for encrypting ProductKeys # # In: ProductKey # #--------------------------------------------------------------------- sub EncryptPK { my ($sData, $bLabKey) = @_; my ($res, $sUser, $sPKout); $res = `where NTCrypt.exe`; if($res =~ /Could not/){ errmsg("NTCrypt.exe is necessary") && exit(1); } if($sData eq ""){ errmsg("Usage: EncryptPK(, )"); return 0; } $sUser = lc($ENV{'USERNAME'}); errmsg("Invalid data") if($sData !~ /\W+/); $sPKout = (defined($bLabKey) ? $sUser."LAB.epk" : "$sUser.epk"); mkdir($ABTWorkDir) if(! (-e $ABTWorkDir)); $res = `NTCrypt.exe -e \"$sData\" -t:$ABTWorkDir\\$sPKout`; if($res =~ /error/i ){ errmsg("Couldn't encrypt key: $res"); return -1; } else { logmsg("Successfuly created key file: $ABTWorkDir\\$sPKout"); } return 1; } #--------------------------------------------------------------------- # GetPK - # # Out: ProductKey # #--------------------------------------------------------------------- sub GetPK { my ($bLabKey) = @_; my ($res, $sUser, $sPK) = ""; $sUser = lc($ENV{'USERNAME'}); $sPK = (defined($bLabKey) ? $sUser."LAB.epk" : "$sUser.epk"); if(-e "$ABTWorkDir\\$sPK"){ $res = `NTCrypt.exe -r -t:$ABTWorkDir\\$sPK`; if($res =~ /error/i ){ errmsg("Couldn't decrypt key file: $ABTWorkDir\\$sPK"); return -1; } else { logmsg("Successfuly decrypted key file: $ABTWorkDir\\$sPK"); } } else{ errmsg("Couldn't find encrypted product key file. Run AutoBoottest::EncryptPK() to create an encrypted product key file"); #print "Enter ProductKey: "; #$res = ; #print "\n"; #chomp($res); } return $res; } #--------------------------------------------------------------------- # VerifyBT - Verify the boottestmachine meets the following criteria: # 1) test for WMI access # 2) current or specified user has admin access # 3) BTM has a second partion w/ space > 2BG to install test build # # In: Target # #--------------------------------------------------------------------- sub VerifyBT($) { my ($sTarget) = @_; my (@res, $oADSIDom, $wbemLocator, $remote_wbem_services); @res = (); #check for ADSI access $oADSIDom=Win32::OLE->GetObject("WinNT://$sTarget"); push(@res, Get_OLE_errmsg("Failed to access \\\\$sTarget via ADSI:")) if (!defined $oADSIDom); undef $oADSIDom; #check for WMI access $wbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); if(!defined($wbemLocator)){ push(@res, Get_OLE_errmsg("Could not instatiate WbemScripting.SWbemLocator")); }else{ $remote_wbem_services = $wbemLocator->ConnectServer( $sTarget ); push(@res, Get_OLE_errmsg("Failed to access \\\\$sTarget via WMI:")) if (!defined $remote_wbem_services); } if(@res){ undef $remote_wbem_services; undef $wbemLocator; errmsg("The following steps failed when verifing the boottest machine:"); for my $i (@res) { errmsg($i);} return 0; } #Check partitioning scheme if(defined($remote_wbem_services)){ my ($c, $d, $dspace, $drive) = 0; my $ResultArray = $remote_wbem_services->ExecQuery("Select * From Win32_LogicalDisk Where DriveType=3"); my $ResultArrayRef = [(in $ResultArray)]; while($drive = shift @$ResultArrayRef){ if($drive->{DriveType} == 3) { $c = 1 if($drive->{Name} =~ /c/i); if($drive->{Name} =~ /d/i) { $d = 1; $dspace = 1 if($drive->{FreeSpace} > 2097152); #what should this val be ? } } } push(@res, "\\\\$sTarget drives aren't correctly configured.") if(!($c && $d && $dspace)); } else{ push(@res, "Unable to verify partitioning scheme on \\\\$sTarget"); } #Make sure we're in the safe build #my($remProc, $res); #$remProc = $remote_wbem_services->InstancesOf('Win32_BootConfiguration') || push(@res, "Couldn't get a Win32_BootConfiguration"); #if($remProc->{BootDirectory} !~ /c:\\/i){ # push(@res, "Not in safe build"); #Verify services are running on target, if not start my @tres = AutoBoottest::QueryTarget($sTarget, "Win32_Service", "Schedule", "", ""); if(((!(grep {/State=Running/} @tres)) && !AutoBoottest::StartService($sTarget, "Schedule", "",""))) { push(@res, "Task Scheduler service isn't running on $sTarget. Enable service through mmc->Services"); } undef $remote_wbem_services; undef $wbemLocator; if(@res){ errmsg("The following steps failed:"); for my $i (@res) { errmsg($i);} return 0; } logmsg("\\\\$sTarget correctly configured."); return 1; } #--------------------------------------------------------------------- # StartService - start a service on a remote machine # # In: target machine, service name, [user, pass] #--------------------------------------------------------------------- sub StartService { my ($target, $service, $user, $pass) = @_; my (@res, $oADSIDom, $wbemLocator, $remote_services, $oServ, $res, $srvc, $resultArray, $resultRef); defined($service) or return -1; $wbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); (OLE_errmsg("Could not instatiate WbemScripting.SWbemLocator") && return 0 ) if ( !defined $wbemLocator ); defined($user) ? $remote_services = $wbemLocator->ConnectServer( "$target", "root\\cimv2", $user, $pass ): $remote_services = $wbemLocator->ConnectServer( "$target"); (OLE_errmsg("Couldn't connect to $target") && return 0 ) if (!defined $remote_services); $resultArray = $remote_services->ExecQuery("Select * From Win32_Service Where Name ='$service'"); $resultRef = [(in $resultArray)]; while ($srvc = shift @$resultRef) { logmsg "Starting service: $srvc->{Name}"; $srvc->ChangeStartMode("Manual") if ($srvc->{StartMode} eq "Disabled"); if($srvc->{State} eq "Stopped") { $res = $srvc->StartService(); ($res) ? errmsg("$srvc->{Name} could not start: $res") : logmsg("$srvc->{Name} started."); return 1; } else { logmsg("$srvc->{Name} is already running"); return 1; } } undef $remote_services; undef $wbemLocator; errmsg("Service $service not found on $target"); return 0; } #--------------------------------------------------------------------- # QueryTarget - query WMI provider on a remote machine # # In: target machine, service name, [user, pass] #--------------------------------------------------------------------- sub QueryTarget { my ($target, $service, $name, $user, $pass) = @_; my (@res, $oADSIDom, $wbemLocator, $remote_services, $oServ, $res, $srvc, $resultArray, $resultRef); defined($service) or return -1; $wbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); (OLE_errmsg("Could not instatiate WbemScripting.SWbemLocator") && return 0 ) if ( !defined $wbemLocator ); defined($user) ? $remote_services = $wbemLocator->ConnectServer( "$target", "root\\cimv2", $user, $pass ): $remote_services = $wbemLocator->ConnectServer( "$target"); (OLE_errmsg("Couldn't connect to $target") && return 0 ) if (!defined $remote_services); $resultArray = $remote_services->ExecQuery("Select * From $service Where Name='$name'"); $resultRef = [(in $resultArray)]; undef $remote_services; undef $wbemLocator; while ($srvc = shift @$resultRef) { logmsg("$service - $name is available"); return 1; } errmsg("$service $name not found on $target"); return 0; } #--------------------------------------------------------------------- # WriteUnattendFile - Generate Unattend File # # In: target, out file, lang, pid, [username, password] # Out: success = 1, fail = 0 #--------------------------------------------------------------------- sub WriteUnattendFile { my($target, $OutFile, $lang, $pid, $user, $pass) = @_; my(@Identification, $computername); my $Administrators = ($lang =~ /ger/i) ? "Administratoren" : "Administrators"; if($user){ #if($pass =~ /\*/){ # $pass = comlib::GetPassword($username); #} @Identification = ( "[Identification]\n", "JoinDomain=NTDEV\n", "DomainAdmin=$user\n", "DomainAdminPassword=$pass\n", "CreateComputerAccountInDomain = Yes\n\n"); } !$OutFile && ($OutFile = "unattend.txt"); !$target && errmsg( "Must specify target." ) && return 0; !$pid && errmsg( "Must specify pid.") && return 0; $computername = $target."1"; open(of, ">$OutFile") || die "Can't open $OutFile for writing"; print of < or where is '/' or '-' # #--------------------------------------------------------------------- sub GetCommand($) { my ($txt) = @_; $txt =~ /(.*)\/|-| /; return $1; } #--------------------------------------------------------------------- # GetPassword - eventually get a masked password # # In: item to get password for # #--------------------------------------------------------------------- sub GetPassword($) { print "Enter password for @_: "; my $pass = ; print "\n"; chomp($pass); return $pass; } #--------------------------------------------------------------------- # Get_OLE_errmsg - Wrapper for OLE errors # # In: Error text #--------------------------------------------------------------------- sub Get_OLE_errmsg { my $text = shift; return "$text (". Win32::OLE->LastError(). ")"; } #--------------------------------------------------------------------- # OLE_errmsg - Wrapper for OLE errors # # In: Error text # #--------------------------------------------------------------------- sub OLE_errmsg { errmsg(Get_OLE_errmsg(shift)); } #--------------------------------------------------------------------- # FatalError- Wrapper for error + exit # # In: Error text # #--------------------------------------------------------------------- sub FatalError { my $text = shift; errmsg("Fatal error: $text"); exit(1); } #--------------------------------------------------------------------- __END__ =head1 NAME <> - <> =head1 SYNOPSIS <> =head1 DESCRIPTION <> =head1 AUTHOR <> =head1 COPYRIGHT Copyright (c) Microsoft Corporation. All rights reserved. !AutoBoottest::StartService($starget, "Schedule", "",""))) =cut