From 4192667eec75ea782f4dc492a269764e08027075 Mon Sep 17 00:00:00 2001 From: Micah R Ledbetter Date: Fri, 30 Oct 2015 19:47:57 -0500 Subject: [PATCH] wintriallab: WORKING BUILDS - It can auto trigger WinRM enabling - Use stronger password for vagrant user so WinRM will allow it - Reboot after installing VBox Additions before running WSUS - Way more verbose Packer - Slightly better error handling in postinstall scripts - Use the Event Log for logging in the postinstall module - Fix lots of bugs that cropped up without me realizing - Install VBox Additions from either ISO or attached disk - Install from ISO by default (smoother in Packer) - Accept EULA for Windows Updates where relevant --- buildlab.ps1 | 5 + scripts/enable-winrm.ps1 | 15 ++ .../postinstall/autounattend-postinstall.ps1 | 27 ++- .../postinstall/provisioner-postinstall.ps1 | 2 - .../postinstall/wintriallab-postinstall.psm1 | 189 +++++++++++++----- scripts/win-updates.ps1 | 18 +- windows_81_x86/Autounattend.xml | 20 +- .../vagrantfile-windows_81_x86.template | 2 +- windows_81_x86/windows_81_x86.packerfile.json | 4 +- 9 files changed, 206 insertions(+), 76 deletions(-) create mode 100644 scripts/enable-winrm.ps1 diff --git a/buildlab.ps1 b/buildlab.ps1 index 26076d7..9d57be7 100644 --- a/buildlab.ps1 +++ b/buildlab.ps1 @@ -49,6 +49,7 @@ $verbose = $true $dateStamp = get-date -UFormat "%Y-%m-%d-%H-%M-%S" $packerOutDir = "$baseOutDir\PackerOut" $packerCacheDir = "$baseOutDir\packer_cache" +$packerLogFile = "$baseOutDir\packer.log" $wsusOfflineDir = "$baseOutDir\wsusoffline" $labTempDir = "$baseOutDir\temp-$dateStamp" @@ -185,7 +186,11 @@ function Build-PackerFile { pushd (get-item $packerFile | select -expand fullname | split-path -parent) try { write-host "Building packer file '$($packerFile.fullname)' to directory '$outDir'..." + $packerCall = '' if (-not $whatif) { + $env:PACKER_DEBUG = 1 + $env:PACKER_LOG = 1 + $env:PACKER_PATH = $packerLogFile packer build -var "output_directory=$outDir" "$($packerFile.fullname)" if ($LASTEXITCODE -ne 0) { throw "External command failed with code $LASTEXITCODE" } } diff --git a/scripts/enable-winrm.ps1 b/scripts/enable-winrm.ps1 new file mode 100644 index 0000000..f79a80f --- /dev/null +++ b/scripts/enable-winrm.ps1 @@ -0,0 +1,15 @@ +cmd.exe /c 'winrm quickconfig -q' +cmd.exe /c 'winrm quickconfig -transport:http' +cmd.exe /c 'winrm set winrm/config @{MaxTimeoutms="1800000"}' +cmd.exe /c 'winrm set winrm/config/winrs @{MaxMemoryPerShellMB="2048"}' +cmd.exe /c 'winrm set winrm/config/service @{AllowUnencrypted="true"}' +cmd.exe /c 'winrm set winrm/config/client @{AllowUnencrypted="true"}' +cmd.exe /c 'winrm set winrm/config/service/auth @{Basic="true"}' +cmd.exe /c 'winrm set winrm/config/client/auth @{Basic="true"}' +cmd.exe /c 'winrm set winrm/config/service/auth @{CredSSP="true"}' +cmd.exe /c 'winrm set winrm/config/listener?Address=*+Transport=HTTP @{Port="5985"} ' +cmd.exe /c 'netsh advfirewall firewall set rule group="remote administration" new enable=yes' +cmd.exe /c 'netsh firewall add portopening TCP 5985 "Port 5985"' +cmd.exe /c 'net stop winrm' +cmd.exe /c 'sc.exe config winrm start= auto' +cmd.exe /c 'net start winrm' diff --git a/scripts/postinstall/autounattend-postinstall.ps1 b/scripts/postinstall/autounattend-postinstall.ps1 index 7c5e934..cd95a6f 100644 --- a/scripts/postinstall/autounattend-postinstall.ps1 +++ b/scripts/postinstall/autounattend-postinstall.ps1 @@ -4,21 +4,26 @@ param() import-module $PSScriptRoot\wintriallab-postinstall.psm1 try { + Write-EventLogWrapper "Starting the autounattend postinstall script" Set-PasswordExpiry -accountName "vagrant" -expirePassword $false Disable-HibernationFile Enable-MicrosoftUpdate - A:\win-updates.ps1 -RestartAction RunAtLogon -PostUpdateExpression A:\enable-winrm.bat + Install-VBoxAdditions -fromDisc # Need to reboot for some of these drivers to take + + # To reboot, then run Windows updates, then enable WinRM: + $restartCommand = "$PSHOME\powershell.exe -File A:\win-updates.ps1 -RestartAction RunAtLogon -PostUpdateExpression -CalledFromRegistry '$PSHOME\powershell.exe -File A:\enable-winrm.ps1'" + + # To reboot, then run winrm immediately without Windows Update + #$restartCommand = "$PSHOME\powershell.exe -File A:\enable-winrm.ps1" + + Set-RestartRegistryEntry -restartAction RunAtLogon -restartCommand $restartCommand + Restart-Computer -force } catch { - write-host "======== CAUGHT EXCEPTION ========" - write-host "$_" - write-host "======== CALL STACK ========" - Get-PSCallStack | format-list - write-host "======== ERROR STACK ========" - for ($i=0; $i -lt $error.count; $i+=1) { - write-host "`$error[$i]" - write-host $error[$i] - } - write-host "======== ========" + $message = "======== CAUGHT EXCEPTION ========`r`n$_`r`n" + $message += "======== ERROR STACK ========" + $error |% { $message += "$_`r`n----`r`n" } + $message += "======== ========" + Write-EventLogWrapper $message exit 666 } diff --git a/scripts/postinstall/provisioner-postinstall.ps1 b/scripts/postinstall/provisioner-postinstall.ps1 index 0c83a5c..563af79 100644 --- a/scripts/postinstall/provisioner-postinstall.ps1 +++ b/scripts/postinstall/provisioner-postinstall.ps1 @@ -23,8 +23,6 @@ $LASTEXITCODE = 0 # just in case import-module $PSScriptRoot\wintriallab-postinstall.psm1 try { Install-SevenZip - #Install-VBoxAdditions -isoPath "C:\Users\vagrant\VBoxGuestAdditions.iso" - Install-VBoxAdditions -fromDisc Disable-AutoAdminLogon Enable-RDP Install-Chocolatey diff --git a/scripts/postinstall/wintriallab-postinstall.psm1 b/scripts/postinstall/wintriallab-postinstall.psm1 index 4925588..ece16f6 100644 --- a/scripts/postinstall/wintriallab-postinstall.psm1 +++ b/scripts/postinstall/wintriallab-postinstall.psm1 @@ -1,3 +1,9 @@ +param( + [String] $ScriptProductName = "PostInstall-Marionettist", + [String] $ScriptPath = $MyInvocation.MyCommand.Path, + [String] $ScriptName = $MyInvocation.MyCommand.Name +) + <# jesus fucking christ fucking Packer @@ -5,9 +11,9 @@ TODO: - make every function 100% reliant on itself only. - get rid of calls to Get-LabTempDir - decided whether I'm using $URLs or not lol +- get better logging - use an Event Log #> - ### Global Constants that I use elsewhere $ArchitectureId = @{ @@ -65,7 +71,13 @@ $URLs = @{ } SdeleteDownload = "http://download.sysinternals.com/files/SDelete.zip" } - +$script:ScriptPath = $MyInvocation.MyCommand.Path +$script:RestartRegistryKeys = @{ + RunBeforeLogon = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce" + RunAtLogon = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" +} +$script:RestartRegistryProperty = "$ScriptProductName" + ### Private support functions I use behind the scenes function Get-WebUrl { @@ -89,9 +101,9 @@ function Invoke-ExpressionAndCheck { [int] $sleepSeconds ) $global:LASTEXITCODE = 0 - write-verbose "Invoking expression '$command'" + Write-EventLogWrapper "Invoking expression '$command'" invoke-expression -command $command - write-verbose "Expression '$command' had a last exit code of '$LastExitCode'" + Write-EventLogWrapper "Expression '$command' had a last exit code of '$LastExitCode'" if ($global:LASTEXITCODE -ne 0) { throw "LASTEXITCODE: ${global:LASTEXITCODE} for command: '${command}'" } @@ -108,7 +120,7 @@ function Invoke-ExpressionAndCheck { # ) # $path = resolve-path $path | select -expand path # $sourceItems = Get-ChildItem -Path $path -Recurse -Exclude $exclude -# write-verbose "Found $($sourceItems.count) items to copy from '$path'" +# Write-EventLogWrapper "Found $($sourceItems.count) items to copy from '$path'" # #$sourceItems | copy-item -force:$force -destination {Join-Path $destination $_.FullName.Substring($path.length)} # $sourceItems | copy-item -force:$force -destination { # if ($_.GetType() -eq [System.IO.FileInfo]) { @@ -161,7 +173,7 @@ function Get-AdkPath { $possibleAdkPaths = @("${env:ProgramFiles(x86)}\Windows Kits\8.1","${env:ProgramFiles}\Windows Kits\8.1") $possibleAdkPaths |% { if (test-path $_) { $adkPath = $_ } } if (-not $adkPath) { throw "Could not find the Windows Automated Installation Kit" } - write-verbose "Found the WAIK at '$adkPath'" + Write-EventLogWrapper "Found the WAIK at '$adkPath'" $arch = Get-OSArchitecture switch ($arch) { @@ -205,7 +217,7 @@ function Get-WOShortCode { # TODO fixme I think I don't need this anymore becaus elseif ($OSArchitecture -match $ArchitectureId.amd64) { $shortCode += "-x64" } else { throw "Could not determine shortcode for an OS of architecture '$OSArchitecture'" } - write-verbose "Found shortcode '$shortcode' for OS named '$OSName' of architecture '$OSArchitecture'" + Write-EventLogWrapper "Found shortcode '$shortcode' for OS named '$OSName' of architecture '$OSArchitecture'" return $shortCode } @@ -230,14 +242,70 @@ function Get-LabTempDir { $script:WinTrialLabTemp = "${env:Temp}\WinTrialLab-$dateStamp" } $script:WinTrialLabTemp = [System.IO.Path]::GetFullPath($script:WinTrialLabTemp) - write-verbose "Using WinTrialLabTemp directory at '${script:WinTrialLabTemp}'" + Write-EventLogWrapper "Using WinTrialLabTemp directory at '${script:WinTrialLabTemp}'" if (-not (test-path $script:WinTrialLabTemp)) { - write-verbose "Temporary directory does not exist, creating it..." + Write-EventLogWrapper "Temporary directory does not exist, creating it..." mkdir -force $script:WinTrialLabTemp | out-null } return $script:WinTrialLabTemp } +<# +.synopsis +Wrapper that writes to the event log but also to the screen +#> +function Write-EventLogWrapper { + [cmdletbinding()] param( + [parameter(mandatory=$true)] [String] $message, + [int] $eventId = 0, + [ValidateSet("Error",'Warning','Information','SuccessAudit','FailureAudit')] $entryType = "Information", + [String] $EventLogName = $ScriptProductName, + [String] $EventLogSource = $ScriptName + ) + if (-not (get-eventlog -logname * |? { $_.Log -eq $eventLogName })) { + New-EventLog -Source $EventLogSource -LogName $eventLogName + } + $messagePlus = "$message`r`n`r`nScript: $($script:ScriptPath)`r`nUser: ${env:USERDOMAIN}\${env:USERNAME}" + Write-Host -foreground magenta "====Writing to $EvengLogName event log====" + write-host -foreground darkgray "$messagePlus`r`n" + Write-EventLog -LogName $eventLogName -Source $EventLogSource -EventID $eventId -EntryType $entryType -Message $MessagePlus +} + +<# +.synopsis +Create and set the registry property which will run this script on reboot +#> +function Set-RestartRegistryEntry { + param( + [parameter(mandatory=$true)] [ValidateSet('RunBeforeLogon','RunAtLogon','NoRestart')] [string] $RestartAction, + [string] $restartCommand + ) + + if ($RestartAction -match "NoRestart") { + Write-EventLogWrapper "Called Set-RestartRegistryEntry with -RestartAction NoRestart, will not write registry key" + return + } + + $message = "Setting the Restart Registry Key at: {0}\{1}`r`n{2}" -f $script:RestartRegistryKeys.$RestartAction, $script:RestartRegistryProperty, $restartCommand + Write-EventLogWrapper -message $message + New-Item $script:RestartRegistryKeys.$RestartAction -force | out-null + Set-ItemProperty -Path $script:RestartRegistryKeys.$RestartAction -Name $script:RestartRegistryProperty -Value $restartCommand +} + +function Get-RestartRegistryEntries { + [cmdletbinding()] param() + foreach ($key in $script:RestartRegistryKeys.Keys) { + try { Get-ItemProperty -Path $script:RestartRegistryKeys[$key] -name $script:RestartRegistryProperty} catch {} + } +} + +function Remove-RestartRegistryEntries { + [cmdletbinding()] param() + foreach ($key in $script:RestartRegistryKeys.Keys) { + try { Remove-ItemProperty -Path $script:RestartRegistryKeys[$key] -name $script:RestartRegistryProperty} catch {} + } +} + <# .description Return the OS Architecture of the current system, as determined by WMI @@ -270,8 +338,8 @@ function Install-SevenZip { $OSArch = Get-OSArchitecture $szDlPath = Get-WebUrl -url $URLs.SevenZipDownload.$OSArch -outDir $env:temp try { - write-verbose "Downloaded '$szUrl' to '$szDlPath', now running msiexec..." - $msiCall = 'msiexec /qn /i "{0}"' -f $szDlPath + Write-EventLogWrapper "Downloaded '$szUrl' to '$szDlPath', now running msiexec..." + $msiCall = '& msiexec /qn /i "{0}"' -f $szDlPath # Windows suxxx so msiexec sometimes returns right away? or something idk. fuck Invoke-ExpressionAndCheck -command $msiCall -sleepSeconds 30 } @@ -282,34 +350,55 @@ function Install-SevenZip { set-alias sevenzip "${env:ProgramFiles}\7-Zip\7z.exe" function Install-VBoxAdditions { - [cmdletbinding()] - param( - [parameter(mandatory=$true)] [string] $isoPath + [cmdletbinding(DefaultParameterSetName="InstallFromDisc")] param( + [parameter(ParameterSetName="InstallFromIsoPath",mandatory=$true)] [string] $isoPath, + [parameter(ParameterSetName="InstallFromDisc",mandatory=$true)] [switch] $fromDisc ) - $isoPath = resolve-path $isoPath | select -expand Path - $vbgaPath = "${env:Temp}\InstallVbox" - try { - mkdir -force $vbgaPath - - write-verbose "Extracting iso at '$isoPath' to directory at '$vbgaPath'..." - Invoke-ExpressionAndCheck -command ('sevenzip x "{0}" -o"{1}"' -f $isoPath, $vbgaPath) - write-verbose "Installing the Oracle certificate..." - $oracleCert = resolve-path "$vbgaPath\cert\oracle-vbox.cer" | select -expand path + function InstallVBoxAdditionsFromDir { + param([Parameter(Mandatory=$true)][String]$baseDir) + $baseDir = resolve-path $baseDir | select -expand Path + Write-EventLogWrapper "Installing VBox Additions from '$baseDir'" + Write-EventLogWrapper "Installing the Oracle certificate..." + $oracleCert = resolve-path "$baseDir\cert\oracle-vbox.cer" | select -expand path # NOTE: Checking for exit code, but this command will fail with an error if the cert is already installed - Invoke-ExpressionAndCheck -command ('"{0}" add-trusted-publisher "{1}" --root "{1}"' -f "$vbgaPath\cert\VBoxCertUtil.exe",$oracleCert) - - write-verbose "Installing the virtualbox additions" - Invoke-ExpressionAndCheck -command ('"{0}" /with_wddm /S' -f "$vbgaPath\VBoxWindowsAdditions.exe") # returns IMMEDIATELY, goddamn fuckers - while (get-process -Name VBoxWindowsAdditions*) { write-verbose 'Waiting for VBox install to finish...'; sleep 1; } + Invoke-ExpressionAndCheck -command ('& "{0}" add-trusted-publisher "{1}" --root "{1}"' -f "$baseDir\cert\VBoxCertUtil.exe",$oracleCert) + Write-EventLogWrapper "Installing the virtualbox additions" + Invoke-ExpressionAndCheck -command ('& "{0}" /with_wddm /S' -f "$baseDir\VBoxWindowsAdditions.exe") # returns IMMEDIATELY, goddamn fuckers + while (get-process -Name VBoxWindowsAdditions*) { write-host 'Waiting for VBox install to finish...'; sleep 1; } + Write-EventLogWrapper "virtualbox additions have now been installed" } - finally { - rm -recurse -force $vbgaPath + + switch ($PSCmdlet.ParameterSetName) { + "InstallFromIsoPath" { + $isoPath = resolve-path $isoPath | select -expand Path + $vbgaPath = mkdir -force "${env:Temp}\InstallVbox" | select -expand fullname + try { + Write-EventLogWrapper "Extracting iso at '$isoPath' to directory at '$vbgaPath'..." + Invoke-ExpressionAndCheck -command ('sevenzip x "{0}" -o"{1}"' -f $isoPath, $vbgaPath) + InstallVBoxAdditionsFromDir $vbgaPath + } + finally { + rm -recurse -force $vbgaPath + } + } + "InstallFromDisc" { + $vboxDiskDrive = get-psdrive -PSProvider Filesystem |? { test-path "$($_.Root)\VBoxWindowsAdditions.exe" } + if ($vboxDiskDrive) { + Write-EventLogWrapper "Found VBox Windows Additions disc at $vboxDiskDrive" + InstallVBoxAdditionsFromDir $vboxDiskDrive.Root + } + else { + $message = "Could not find VBox Windows Additions disc" + Write-EventLogWrapper $message + throw $message + } + } } } function Disable-AutoAdminLogon { - write-verbose "Function: $($MyInvocation.MyCommand)..." + Write-EventLogWrapper "Disabling auto admin logon" set-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name AutoAdminLogon -Value 0 } @@ -323,13 +412,13 @@ function Install-CompiledDotNetAssemblies { # http://robrelyea.wordpress.com/2007/07/13/may-be-helpful-ngen-exe-executequeueditems/ $ngen = "${env:WinDir}\microsoft.net\framework\v4.0.30319\ngen.exe" - Invoke-ExpressionAndCheck -command "$ngen update /force /queue" - Invoke-ExpressionAndCheck -command "$ngen executequeueditems" + Invoke-ExpressionAndCheck -command "& $ngen update /force /queue" + Invoke-ExpressionAndCheck -command "& $ngen executequeueditems" if ((Get-OSArchitecture) -match $ArchitectureId.amd64) { $ngen64 = "${env:WinDir}\microsoft.net\framework64\v4.0.30319\ngen.exe" - Invoke-ExpressionAndCheck -command "$ngen64 update /force /queue" - Invoke-ExpressionAndCheck -command "$ngen64 executequeueditems" + Invoke-ExpressionAndCheck -command "& $ngen64 update /force /queue" + Invoke-ExpressionAndCheck -command "& $ngen64 executequeueditems" } } @@ -337,7 +426,7 @@ function Compress-WindowsInstall { $OSArch = Get-OSArchitecture try { $udfZipPath = Get-WebUrl -url $URLs.UltraDefragDownload.$OSArch -outDir $env:temp - $udfExPath = "${env:temp}\ultradefrag-portable-6.1.0.$udfArch" + $udfExPath = "${env:temp}\ultradefrag-portable-6.1.0.$OSArch" # This archive contains a folder - extract it directly to the temp dir Invoke-ExpressionAndCheck -command ('sevenzip x "{0}" "-o{1}"' -f $udfZipPath,$env:temp) @@ -350,10 +439,12 @@ function Compress-WindowsInstall { rm -recurse -force ${env:WinDir}\SoftwareDistribution\Download start-service wuauserv - Invoke-ExpressionAndCheck -command ('{0} --optimize --repeat "{1}"' -f "$udfExPath\udefrag.exe","$env:SystemDrive") + Invoke-ExpressionAndCheck -command ('& {0} --optimize --repeat "{1}"' -f "$udfExPath\udefrag.exe","$env:SystemDrive") - Set-ItemProperty -path HKCU\Software\Sysinternals\SDelete -name EulaAccepted -value 1 - Invoke-ExpressionAndCheck -command ('{0} -q -z "{1}"' -f $sdExPath,$env:SystemDrive) + $sdKey = "HKCU:\Software\Sysinternals\SDelete" + if (-not (test-path $sdKey)) { New-Item $sdKey -Force } + Set-ItemProperty -path $sdKey -name EulaAccepted -value 1 + Invoke-ExpressionAndCheck -command ('& {0} -q -z "{1}"' -f "$sdExPath\SDelete.exe",$env:SystemDrive) } finally { rm -recurse -force $udfZipPath,$udfExPath,$sdZipPath,$sdExPath -ErrorAction Continue @@ -375,24 +466,24 @@ function Disable-WindowsUpdates { function Enable-MicrosoftUpdate { [cmdletbinding()] param() - write-verbose "Enabling Microsoft Update..." + Write-EventLogWrapper "Enabling Microsoft Update..." stop-service wuauserv $auKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" Set-ItemProperty -path $auKey -name EnableFeaturedSoftware -value 1 Set-ItemProperty -path $auKey -name IncludeRecommendedUpdates -value 1 $ServiceManager = New-Object -ComObject "Microsoft.Update.ServiceManager" - $ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") + $ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") | out-null start-service wuauserv } function Install-Chocolatey { - [cmdleetbinding()] param() + [cmdletbinding()] param() $chocoExePath = "${env:ProgramData}\Chocolatey\bin" if ($($env:Path).ToLower().Contains($($chocoExePath).ToLower())) { - write-verbose "Chocolatey already in path, exiting..." + Write-EventLogWrapper "Attempting to install Chocolatey but it's already in path, exiting..." return } @@ -404,7 +495,9 @@ function Install-Chocolatey { $userPath = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::User) if ($userPath) { $env:Path += ";$userPath" } - iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) + # TODO: capture and log output + $chocoOutput = iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) + Write-EventLogWrapper "Chocolatey install process completed:`r`n`r`n$chocoOutput" } function Set-UserOptions { @@ -431,7 +524,7 @@ function Set-UserOptions { function Disable-HibernationFile { [cmdletbinding()] param() - write-verbose "Removing Hibernation file..." + Write-EventLogWrapper "Removing Hibernation file..." $powerKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Power' Set-ItemProperty -path $powerKey -name HibernateFileSizePercent -value 0 # hiberfil is zero bytes Set-ItemProperty -path $powerKey -name HibernateEnabled -value 0 # disable hibernation altogether @@ -439,7 +532,7 @@ function Disable-HibernationFile { function Enable-WinRM { # TODO fixme, would prefer this to be in Powershell if possible. also it's totally insecure [cmdletbinding()] param() - write-verbose "Enabling WinRM..." + Write-EventLogWrapper "Enabling WinRM..." cmd /c winrm quickconfig -q cmd /c winrm quickconfig -transport:http @@ -542,7 +635,7 @@ function New-WindowsInstallMedia { # TODO fixme not sure I wanna handle temp dir $etfsBoot = resolve-path "$existingInstallMediaDir\boot\etfsboot.com" | select -expand Path $oscdimgCall = '& "{0}" -m -n -b"{1}" "{2}" "{3}"' -f @($oscdImgPath, $etfsBoot, $installMediaTemp, $outputIsoPath) - write-verbose "Calling OSCDIMG: '$oscdimgCall" + Write-EventLogWrapper "Calling OSCDIMG: '$oscdimgCall" Invoke-ExpressionAndCheck $oscdimgCall -verbose:$verbose dismount-diskimage -imagepath $sourceIsoPath @@ -557,7 +650,7 @@ function Get-WindowsUpdateUrls { # TODO: is this how we wanna do temps tho? [switch] $debugSaveXslt ) $xsltPath = [IO.Path]::GetTempFileName() - write-verbose "Downloading XSLT to '$xsltPath'" + Write-EventLogWrapper "Downloading XSLT to '$xsltPath'" if ($osArchitecture -match $ArchitectureId.i386) { $arch = "x86" } elseif ($osArchitecture -match $ArchitectureId.amd64) { $arch = "x64" } diff --git a/scripts/win-updates.ps1 b/scripts/win-updates.ps1 index e8e32c3..e27b133 100644 --- a/scripts/win-updates.ps1 +++ b/scripts/win-updates.ps1 @@ -16,7 +16,7 @@ This script is intended to be 100% standalone because it needs to be able to tel #> param( [int] $MaxCycles = 5, - [string] $ScriptProductName = "MarionettistWindowsUpdate", + [string] $ScriptProductName = "WinUp-Marionettist", [string] $PostUpdateExpression, [string] [ValidateSet('RunBeforeLogon','RunAtLogon','NoRestart')] $RestartAction = "NoRestart", [switch] $CalledFromRegistry @@ -190,7 +190,7 @@ function Install-WindowsUpdates { [int] $MaxDownloadAttempts = 12 ) - if ((-not $UpdateList) -or ($UpdateList.Count -lt 1)) { + if (-not $UpdateList) { Write-WinUpEventLog -message "No Updates To Download..." return $false } @@ -202,6 +202,17 @@ function Install-WindowsUpdates { $UpdateComObject = New-Object -ComObject 'Microsoft.Update.UpdateColl' $UpdateList |% { $UpdateComObject.Add($_) } + $AcceptedEulas = @() + foreach ($update in $UpdateComObject) { + if ($update.PSObject.Properties['EulaAccepted']) { + $AcceptedEulas += ($update) + $update.AcceptEula() + } + } + $message = "There were $($AcceptedEulas.count) updates with a EULA which was automatically accepted`r`n" + $AcceptedEulas |% { $message += "`r`n - $($_.Title)"} + Write-WinUpEventLog $message + Write-WinUpEventLog -message 'Downloading Updates...' $ok = $false $attempts = 0 @@ -344,7 +355,7 @@ function Run-WindowsUpdate { Write-WinUpEventLog -message "Starting to check for updates. $maxCycles cycles remain." $CheckedUpdates = Check-WindowsUpdates -FilterInteractiveUpdates -UpdateSession $UpdateSession - if ((-not $CheckedUpdates) -or ($CheckedUpdates.Count -lt 1)) { + if (-not $CheckedUpdates) { Write-WinUpEventLog "No applicable updates were detected. Done!" break } @@ -355,7 +366,6 @@ function Run-WindowsUpdate { Restart-ComputerAndUpdater -CyclesRemaining $maxCycles -RestartAction $script:RestartAction } } - Run-PostUpdate } diff --git a/windows_81_x86/Autounattend.xml b/windows_81_x86/Autounattend.xml index b9c2a07..344d39c 100644 --- a/windows_81_x86/Autounattend.xml +++ b/windows_81_x86/Autounattend.xml @@ -19,7 +19,7 @@ C 1 1 - + 0 @@ -29,8 +29,11 @@ true + + - MHF9N-XY6XB-WVXMC-BTDCT-MKKG7 + + MHF9N-XY6XB-WVXMC-BTDCT-MKKG7 Never @@ -87,13 +91,13 @@ - vagrant + V@grant123 true</PlainText> </AdministratorPassword> <LocalAccounts> <LocalAccount wcm:action="add"> <Password> - <Value>vagrant</Value> + <Value>V@grant123</Value> <PlainText>true</PlainText> </Password> <Description>Vagrant User</Description> @@ -111,7 +115,7 @@ </OOBE> <AutoLogon> <Password> - <Value>vagrant</Value> + <Value>V@grant123</Value> <PlainText>true</PlainText> </Password> <Username>vagrant</Username> @@ -120,17 +124,17 @@ <FirstLogonCommands> <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force"</CommandLine> + <CommandLine>cmd.exe /c powershell -ExecutionPolicy Unrestricted -Command "Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force"</CommandLine> <Description>Set Execution Policy</Description> <Order>1</Order> <RequiresUserInput>true</RequiresUserInput> </SynchronousCommand> <SynchronousCommand wcm:action="add"> - <!-- This task must include enabling winrm --> + <!-- This task MUST include enabling winrm for Packer to be able to continue --> <CommandLine>powershell.exe -File A:\autounattend-postinstall.ps1</CommandLine> <Description>Run Postinstall Script</Description> - <Order>49</Order> + <Order>99</Order> <RequiresUserInput>true</RequiresUserInput> </SynchronousCommand> diff --git a/windows_81_x86/vagrantfile-windows_81_x86.template b/windows_81_x86/vagrantfile-windows_81_x86.template index 03ec35e..cdf19d7 100644 --- a/windows_81_x86/vagrantfile-windows_81_x86.template +++ b/windows_81_x86/vagrantfile-windows_81_x86.template @@ -10,7 +10,7 @@ Vagrant.configure("2") do |config| # Admin user name and password config.winrm.username = "vagrant" - config.winrm.password = "vagrant" + config.winrm.password = "V@grant123" config.vm.guest = :windows config.windows.halt_timeout = 15 diff --git a/windows_81_x86/windows_81_x86.packerfile.json b/windows_81_x86/windows_81_x86.packerfile.json index a941f02..4ae96a1 100644 --- a/windows_81_x86/windows_81_x86.packerfile.json +++ b/windows_81_x86/windows_81_x86.packerfile.json @@ -12,7 +12,7 @@ "boot_wait": "2m", "communicator": "winrm", "winrm_username": "vagrant", - "winrm_password": "vagrant", + "winrm_password": "V@grant123", "winrm_timeout": "8h", "shutdown_command": "shutdown /s /t 10 /f /d p:4:1 /c \"Packer Shutdown\"", "guest_os_type": "Windows81", @@ -21,7 +21,7 @@ "floppy_files": [ "./Autounattend.xml", "../scripts/win-updates.ps1", - "../scripts/enable-winrm.bat", + "../scripts/enable-winrm.ps1", "../scripts/postinstall/wintriallab-postinstall.psm1", "../scripts/postinstall/autounattend-postinstall.ps1", "../scripts/postinstall/provisioner-postinstall.ps1"