Skip to content

Commit

Permalink
add update during packer
Browse files Browse the repository at this point in the history
  • Loading branch information
Mayfly277 committed Oct 22, 2023
1 parent 79cc250 commit 7fdd18d
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 6 deletions.
20 changes: 20 additions & 0 deletions packer/proxmox/answer_files/10_proxmox_cloudinit/Autounattend.xml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@
<Description>Install-WMF3Hotfix.ps1</Description>
<Order>97</Order>
</SynchronousCommand>
<!-- no updates -->
<SynchronousCommand wcm:action="add">
<CommandLine>powershell -NoProfile -ExecutionPolicy Bypass -Command "G:\ConfigureRemotingForAnsible.ps1"</CommandLine>
<Description>ConfigureRemotingForAnsible</Description>
Expand All @@ -283,6 +284,25 @@
<Description>Enable WinRM</Description>
<Order>99</Order>
</SynchronousCommand>
<!-- WITH WINDOWS UPDATES
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c G:\microsoft-updates.bat</CommandLine>
<Order>98</Order>
<Description>Enable Microsoft Updates</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\disable-screensaver.ps1</CommandLine>
<Description>Disable Screensaver</Description>
<Order>99</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\win-updates.ps1</CommandLine>
<Description>Install Windows Updates</Description>
<Order>100</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
END WITH WINDOWS UPDATES -->
</FirstLogonCommands>
<ShowWindowsLive>false</ShowWindowsLive>
</component>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@
<Description>Install-WMF3Hotfix.ps1</Description>
<Order>97</Order>
</SynchronousCommand>
<!-- no updates -->
<SynchronousCommand wcm:action="add">
<CommandLine>powershell -NoProfile -ExecutionPolicy Bypass -Command "G:\ConfigureRemotingForAnsible.ps1"</CommandLine>
<Description>ConfigureRemotingForAnsible</Description>
Expand All @@ -252,6 +253,26 @@
<Description>Enable WinRM</Description>
<Order>99</Order>
</SynchronousCommand>
<!-- end no updates -->
<!-- WITH WINDOWS UPDATES
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c G:\microsoft-updates.bat</CommandLine>
<Order>98</Order>
<Description>Enable Microsoft Updates</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\disable-screensaver.ps1</CommandLine>
<Description>Disable Screensaver</Description>
<Order>99</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\win-updates.ps1</CommandLine>
<Description>Install Windows Updates</Description>
<Order>100</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
END WITH WINDOWS UPDATES -->
</FirstLogonCommands>
<OOBE>
<HideEULAPage>true</HideEULAPage>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
<Description>Install-WMF3Hotfix.ps1</Description>
<Order>97</Order>
</SynchronousCommand>
<!-- no updates -->
<SynchronousCommand wcm:action="add">
<CommandLine>powershell -NoProfile -ExecutionPolicy Bypass -Command "G:\ConfigureRemotingForAnsible.ps1"</CommandLine>
<Description>ConfigureRemotingForAnsible</Description>
Expand All @@ -251,6 +252,26 @@
<Description>Enable WinRM</Description>
<Order>99</Order>
</SynchronousCommand>
<!-- end no update -->
<!-- WITH WINDOWS UPDATES
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c G:\microsoft-updates.bat</CommandLine>
<Order>98</Order>
<Description>Enable Microsoft Updates</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\disable-screensaver.ps1</CommandLine>
<Description>Disable Screensaver</Description>
<Order>99</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File G:\win-updates.ps1</CommandLine>
<Description>Install Windows Updates</Description>
<Order>100</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
END WITH WINDOWS UPDATES -->
</FirstLogonCommands>
<OOBE>
<HideEULAPage>true</HideEULAPage>
Expand Down
5 changes: 3 additions & 2 deletions packer/proxmox/packer.json.pkr.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ source "proxmox-iso" "windows" {
cores = "${var.vm_cpu_cores}"
disks {
disk_size = "${var.vm_disk_size}"
format = "qcow2"
format = "${var.vm_disk_format}"
storage_pool = "${var.proxmox_storage}"
type = "sata"
}
Expand All @@ -57,9 +57,10 @@ source "proxmox-iso" "windows" {
winrm_insecure = true
winrm_no_proxy = true
winrm_password = "${var.winrm_password}"
winrm_timeout = "30m"
winrm_timeout = "120m"
winrm_use_ssl = true
winrm_username = "${var.winrm_username}"
task_timeout = "40m"
}

build {
Expand Down
4 changes: 4 additions & 0 deletions packer/proxmox/scripts/disable-screensaver.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Write-Output "Disabling Screensaver"
Set-ItemProperty "HKCU:\Control Panel\Desktop" -Name ScreenSaveActive -Value 0 -Type DWord
& powercfg -x -monitor-timeout-ac 0
& powercfg -x -monitor-timeout-dc 0
12 changes: 12 additions & 0 deletions packer/proxmox/scripts/microsoft-updates.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
net stop wuauserv

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v EnableFeaturedSoftware /t REG_DWORD /d 1 /f

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v IncludeRecommendedUpdates /t REG_DWORD /d 1 /f

echo Set ServiceManager = CreateObject("Microsoft.Update.ServiceManager") > A:\temp.vbs
echo Set NewUpdateService = ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") >> A:\temp.vbs

cscript A:\temp.vbs

net start wuauserv
252 changes: 252 additions & 0 deletions packer/proxmox/scripts/win-updates.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
param($global:RestartRequired = 0,
$global:MoreUpdates = 0,
$global:MaxCycles = 5,
$MaxUpdatesPerCycle = 500,
$BeginWithRestart = 0)

$Logfile = "C:\Windows\Temp\win-updates.log"

function LogWrite {
Param ([string]$logstring)
$now = Get-Date -format s
Add-Content $Logfile -value "$now $logstring"
Write-Output $logstring
}

function Check-ContinueRestartOrEnd() {
$RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
$RegistryEntry = "InstallWindowsUpdates"
switch ($global:RestartRequired) {
0 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if ($prop) {
LogWrite "Restart Registry Entry Exists - Removing It"
Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
}

LogWrite "No Restart Required"
Check-WindowsUpdates

if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
Install-WindowsUpdates
}
elseif ($script:Cycles -gt $global:MaxCycles) {
LogWrite "Exceeded Cycle Count - Stopping"
& "G:\ConfigureRemotingForAnsible.ps1"
}
else {
LogWrite "Done Installing Windows Updates"
& "G:\ConfigureRemotingForAnsible.ps1"
}
}
1 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if (-not $prop) {
LogWrite "Restart Registry Entry Does Not Exist - Creating It"
Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $($script:ScriptPath) -MaxUpdatesPerCycle $($MaxUpdatesPerCycle)"
}
else {
LogWrite "Restart Registry Entry Exists Already"
}

LogWrite "Restart Required - Restarting..."
Restart-Computer
}
default {
LogWrite "Unsure If A Restart Is Required"
break
}
}
}

function Install-WindowsUpdates()
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
param()
$script:Cycles++
LogWrite "Evaluating Available Updates with limit of $($MaxUpdatesPerCycle):"
$UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$script:i = 0;
$CurrentUpdates = $SearchResult.Updates
while ($script:i -lt $CurrentUpdates.Count -and $script:CycleUpdateCount -lt $MaxUpdatesPerCycle) {
$Update = $CurrentUpdates.Item($script:i)
if ($null -ne $Update) {
[bool]$addThisUpdate = $false
if ($Update.InstallationBehavior.CanRequestUserInput) {
LogWrite "> Skipping: $($Update.Title) because it requires user input"
}
else {
if (!($Update.EulaAccepted)) {
LogWrite "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
$Update.AcceptEula()
[bool]$addThisUpdate = $true
$script:CycleUpdateCount++
}
else {
[bool]$addThisUpdate = $true
$script:CycleUpdateCount++
}
}

if ([bool]$addThisUpdate) {
LogWrite "Adding: $($Update.Title)"
$UpdatesToDownload.Add($Update) | Out-Null
}
}
$script:i++
}

if ($UpdatesToDownload.Count -eq 0) {
LogWrite "No Updates To Download..."
}
else {
LogWrite 'Downloading Updates...'
$ok = 0;
while (! $ok) {
try {
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Downloader.Download()
$ok = 1;
}
catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Error downloading updates. Retrying in 30s."
$script:attempts = $script:attempts + 1
Start-Sleep -s 30
}
}
}

$UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
[bool]$rebootMayBeRequired = $false
LogWrite 'The following updates are downloaded and ready to be installed:'
foreach ($Update in $SearchResult.Updates) {
if (($Update.IsDownloaded)) {
LogWrite "> $($Update.Title)"
$UpdatesToInstall.Add($Update) | Out-Null

if ($Update.InstallationBehavior.RebootBehavior -gt 0) {
[bool]$rebootMayBeRequired = $true
}
}
}

if ($UpdatesToInstall.Count -eq 0) {
LogWrite 'No updates available to install...'
$global:MoreUpdates = 0
$global:RestartRequired = 0
& "G:\ConfigureRemotingForAnsible.ps1"
break
}

if ($rebootMayBeRequired) {
LogWrite 'These updates may require a reboot'
$global:RestartRequired = 1
}

LogWrite 'Installing updates...'

$Installer = $script:UpdateSession.CreateUpdateInstaller()
$Installer.Updates = $UpdatesToInstall
$InstallationResult = $Installer.Install()

LogWrite "Installation Result: $($InstallationResult.ResultCode)"
LogWrite "Reboot Required: $($InstallationResult.RebootRequired)"
LogWrite 'Listing of updates installed and individual installation results:'
if ($InstallationResult.RebootRequired) {
$global:RestartRequired = 1
}
else {
$global:RestartRequired = 0
}

for ($i = 0; $i -lt $UpdatesToInstall.Count; $i++) {
New-Object -TypeName PSObject -Property @{
Title = $UpdatesToInstall.Item($i).Title
Result = $InstallationResult.GetUpdateResult($i).ResultCode
}
LogWrite "Item: $($UpdatesToInstall.Item($i).Title)"
LogWrite "Result: $($InstallationResult.GetUpdateResult($i).ResultCode)"
}

Check-ContinueRestartOrEnd
}

function Check-WindowsUpdates() {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
param()
LogWrite "Checking For Windows Updates"
$Username = $env:USERDOMAIN + "\" + $env:USERNAME
LogWrite "Script: $script:ScriptPath `nScript User: $Username `nStarted: $(Get-Date)"

$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:successful = $FALSE
$script:attempts = 0
$script:maxAttempts = 12
while (-not $script:successful -and $script:attempts -lt $script:maxAttempts) {
try {
$script:SearchResult = $script:UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
$script:successful = $TRUE
}
catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
$script:attempts = $script:attempts + 1
Start-Sleep -s 10
}
}

if ($SearchResult.Updates.Count -ne 0) {
$Message = "There are " + $SearchResult.Updates.Count + " more updates."
LogWrite $Message
try {
for ($i = 0; $i -lt $script:SearchResult.Updates.Count; $i++) {
LogWrite $script:SearchResult.Updates.Item($i).Title
LogWrite $script:SearchResult.Updates.Item($i).Description
LogWrite $script:SearchResult.Updates.Item($i).RebootRequired
LogWrite $script:SearchResult.Updates.Item($i).EulaAccepted
}
$global:MoreUpdates = 1
}
catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Showing SearchResult was unsuccessful. Rebooting."
$global:RestartRequired = 1
$global:MoreUpdates = 0
Check-ContinueRestartOrEnd
LogWrite "Show never happen to see this text!"
Restart-Computer
}
}
else {
LogWrite 'There are no applicable updates'
$global:RestartRequired = 0
$global:MoreUpdates = 0
}
}

$script:ScriptName = $MyInvocation.MyCommand.ToString()
$script:ScriptPath = $MyInvocation.MyCommand.Path
$script:UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
$script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:SearchResult = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$script:Cycles = 0
$script:CycleUpdateCount = 0

if ($BeginWithRestart) {
$global:RestartRequired = 1
Check-ContinueRestartOrEnd
}

Check-WindowsUpdates
if ($global:MoreUpdates -eq 1) {
Install-WindowsUpdates
}
else {
Check-ContinueRestartOrEnd
}
Loading

0 comments on commit 7fdd18d

Please sign in to comment.