11param ($global :RestartRequired = 0 ,
22 $global :MoreUpdates = 0 ,
3- $global :MaxCycles = 5 )
3+ $global :MaxCycles = 5 ,
4+ $MaxUpdatesPerCycle = 500 )
5+
6+ $Logfile = " C:\Windows\Temp\win-updates.log"
7+
8+ function LogWrite {
9+ Param ([string ]$logstring )
10+ $now = Get-Date - format s
11+ Add-Content $Logfile - value " $now $logstring "
12+ Write-Host $logstring
13+ }
414
515function Check-ContinueRestartOrEnd () {
616 $RegistryKey = " HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
717 $RegistryEntry = " InstallWindowsUpdates"
818 switch ($global :RestartRequired ) {
9- 0 {
19+ 0 {
1020 $prop = (Get-ItemProperty $RegistryKey ).$RegistryEntry
1121 if ($prop ) {
12- Write-Host " Restart Registry Entry Exists - Removing It"
22+ LogWrite " Restart Registry Entry Exists - Removing It"
1323 Remove-ItemProperty - Path $RegistryKey - Name $RegistryEntry - ErrorAction SilentlyContinue
1424 }
15-
16- Write-Host " No Restart Required"
25+
26+ LogWrite " No Restart Required"
1727 Check- WindowsUpdates
18-
28+
1929 if (($global :MoreUpdates -eq 1 ) -and ($script :Cycles -le $global :MaxCycles )) {
2030 Install-WindowsUpdates
2131 } elseif ($script :Cycles -gt $global :MaxCycles ) {
22- Write-Host " Exceeded Cycle Count - Stopping"
23- } else {
24- Write-Host " Done Installing Windows Updates"
32+ LogWrite " Exceeded Cycle Count - Stopping"
33+ Invoke-Expression " a:\openssh.ps1 -AutoStart"
34+ } else {
35+ LogWrite " Done Installing Windows Updates"
2536 Invoke-Expression " a:\openssh.ps1 -AutoStart"
2637 }
2738 }
2839 1 {
2940 $prop = (Get-ItemProperty $RegistryKey ).$RegistryEntry
3041 if (-not $prop ) {
31- Write-Host " Restart Registry Entry Does Not Exist - Creating It"
32- Set-ItemProperty - Path $RegistryKey - Name $RegistryEntry - Value " C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $ ( $script :ScriptPath ) "
42+ LogWrite " Restart Registry Entry Does Not Exist - Creating It"
43+ Set-ItemProperty - Path $RegistryKey - Name $RegistryEntry - Value " C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $ ( $script :ScriptPath ) -MaxUpdatesPerCycle $ ( $MaxUpdatesPerCycle ) "
3344 } else {
34- Write-Host " Restart Registry Entry Exists Already"
45+ LogWrite " Restart Registry Entry Exists Already"
3546 }
36-
37- Write-Host " Restart Required - Restarting..."
47+
48+ LogWrite " Restart Required - Restarting..."
3849 Restart-Computer
3950 }
40- default {
41- Write-Host " Unsure If A Restart Is Required"
51+ default {
52+ LogWrite " Unsure If A Restart Is Required"
4253 break
4354 }
4455 }
4556}
4657
4758function Install-WindowsUpdates () {
4859 $script :Cycles ++
49- Write-Host ' Evaluating Available Updates: '
60+ LogWrite " Evaluating Available Updates with limit of $ ( $MaxUpdatesPerCycle ) : "
5061 $UpdatesToDownload = New-Object - ComObject ' Microsoft.Update.UpdateColl'
51- foreach ($Update in $SearchResult.Updates ) {
62+ $script :i = 0 ;
63+ $CurrentUpdates = $SearchResult.Updates | Select-Object
64+ while ($script :i -lt $CurrentUpdates.Count -and $script :CycleUpdateCount -lt $MaxUpdatesPerCycle ) {
65+ $Update = $CurrentUpdates [$script :i ]
5266 if (($Update -ne $null ) -and (! $Update.IsDownloaded )) {
5367 [bool ]$addThisUpdate = $false
5468 if ($Update.InstallationBehavior.CanRequestUserInput ) {
55- Write-Host " > Skipping: $ ( $Update.Title ) because it requires user input"
69+ LogWrite " > Skipping: $ ( $Update.Title ) because it requires user input"
5670 } else {
5771 if (! ($Update.EulaAccepted )) {
58- Write-Host " > Note: $ ( $Update.Title ) has a license agreement that must be accepted. Accepting the license."
72+ LogWrite " > Note: $ ( $Update.Title ) has a license agreement that must be accepted. Accepting the license."
5973 $Update.AcceptEula ()
6074 [bool ]$addThisUpdate = $true
75+ $script :CycleUpdateCount ++
6176 } else {
6277 [bool ]$addThisUpdate = $true
78+ $script :CycleUpdateCount ++
6379 }
6480 }
65-
81+
6682 if ([bool ]$addThisUpdate ) {
67- Write-Host " Adding: $ ( $Update.Title ) "
83+ LogWrite " Adding: $ ( $Update.Title ) "
6884 $UpdatesToDownload.Add ($Update ) | Out-Null
6985 }
70- }
86+ }
87+ $script :i ++
7188 }
72-
89+
7390 if ($UpdatesToDownload.Count -eq 0 ) {
74- Write-Host " No Updates To Download..."
91+ LogWrite " No Updates To Download..."
7592 } else {
76- Write-Host ' Downloading Updates...'
77- $Downloader = $UpdateSession.CreateUpdateDownloader ()
78- $Downloader.Updates = $UpdatesToDownload
79- $Downloader.Download ()
93+ LogWrite ' Downloading Updates...'
94+ $ok = 0 ;
95+ while (! $ok ) {
96+ try {
97+ $Downloader = $UpdateSession.CreateUpdateDownloader ()
98+ $Downloader.Updates = $UpdatesToDownload
99+ $Downloader.Download ()
100+ $ok = 1 ;
101+ } catch {
102+ LogWrite $_.Exception | Format-List - force
103+ LogWrite " Error downloading updates. Retrying in 30s."
104+ $script :attempts = $script :attempts + 1
105+ Start-Sleep - s 30
106+ }
107+ }
80108 }
81-
109+
82110 $UpdatesToInstall = New-Object - ComObject ' Microsoft.Update.UpdateColl'
83111 [bool ]$rebootMayBeRequired = $false
84- Write-Host ' The following updates are downloaded and ready to be installed:'
112+ LogWrite ' The following updates are downloaded and ready to be installed:'
85113 foreach ($Update in $SearchResult.Updates ) {
86114 if (($Update.IsDownloaded )) {
87- Write-Host " > $ ( $Update.Title ) "
115+ LogWrite " > $ ( $Update.Title ) "
88116 $UpdatesToInstall.Add ($Update ) | Out-Null
89-
117+
90118 if ($Update.InstallationBehavior.RebootBehavior -gt 0 ){
91119 [bool ]$rebootMayBeRequired = $true
92120 }
93121 }
94122 }
95-
123+
96124 if ($UpdatesToInstall.Count -eq 0 ) {
97- Write-Host ' No updates available to install...'
125+ LogWrite ' No updates available to install...'
98126 $global :MoreUpdates = 0
99127 $global :RestartRequired = 0
100128 Invoke-Expression " a:\openssh.ps1 -AutoStart"
101129 break
102130 }
103131
104132 if ($rebootMayBeRequired ) {
105- Write-Host ' These updates may require a reboot'
133+ LogWrite ' These updates may require a reboot'
106134 $global :RestartRequired = 1
107135 }
108-
109- Write-Host ' Installing updates...'
110-
136+
137+ LogWrite ' Installing updates...'
138+
111139 $Installer = $script :UpdateSession.CreateUpdateInstaller ()
112140 $Installer.Updates = $UpdatesToInstall
113141 $InstallationResult = $Installer.Install ()
114-
115- Write-Host " Installation Result: $ ( $InstallationResult.ResultCode ) "
116- Write-Host " Reboot Required: $ ( $InstallationResult.RebootRequired ) "
117- Write-Host ' Listing of updates installed and individual installation results:'
142+
143+ LogWrite " Installation Result: $ ( $InstallationResult.ResultCode ) "
144+ LogWrite " Reboot Required: $ ( $InstallationResult.RebootRequired ) "
145+ LogWrite ' Listing of updates installed and individual installation results:'
118146 if ($InstallationResult.RebootRequired ) {
119147 $global :RestartRequired = 1
120148 } else {
121149 $global :RestartRequired = 0
122150 }
123-
151+
124152 for ($i = 0 ; $i -lt $UpdatesToInstall.Count ; $i ++ ) {
125153 New-Object - TypeName PSObject - Property @ {
126154 Title = $UpdatesToInstall.Item ($i ).Title
127155 Result = $InstallationResult.GetUpdateResult ($i ).ResultCode
128156 }
129157 }
130-
158+
131159 Check- ContinueRestartOrEnd
132160}
133161
134162function Check-WindowsUpdates () {
135- Write-Host " Checking For Windows Updates"
163+ LogWrite " Checking For Windows Updates"
136164 $Username = $env: USERDOMAIN + " \" + $env: USERNAME
137-
165+
138166 New-EventLog - Source $ScriptName - LogName ' Windows Powershell' - ErrorAction SilentlyContinue
139-
167+
140168 $Message = " Script: " + $ScriptPath + " `n Script User: " + $Username + " `n Started: " + (Get-Date ).toString()
141169
142170 Write-EventLog - LogName ' Windows Powershell' - Source $ScriptName - EventID " 104" - EntryType " Information" - Message $Message
143- Write-Host $Message
171+ LogWrite $Message
144172
145173 $script :UpdateSearcher = $script :UpdateSession.CreateUpdateSearcher ()
146- $script :SearchResult = $script :UpdateSearcher.Search (" IsInstalled=0 and Type='Software' and IsHidden=0" )
174+ $script :successful = $FALSE
175+ $script :attempts = 0
176+ $script :maxAttempts = 12
177+ while (-not $script :successful -and $script :attempts -lt $script :maxAttempts ) {
178+ try {
179+ $script :SearchResult = $script :UpdateSearcher.Search (" IsInstalled=0 and Type='Software' and IsHidden=0" )
180+ $script :successful = $TRUE
181+ } catch {
182+ LogWrite $_.Exception | Format-List - force
183+ LogWrite " Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
184+ $script :attempts = $script :attempts + 1
185+ Start-Sleep - s 10
186+ }
187+ }
188+
147189 if ($SearchResult.Updates.Count -ne 0 ) {
148- $script :SearchResult.Updates | Select-Object - Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired, EulaAccepted | Format-List
149- $global :MoreUpdates = 1
190+ $Message = " There are " + $SearchResult.Updates.Count + " more updates."
191+ LogWrite $Message
192+ try {
193+ $script :SearchResult.Updates | Select-Object - Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired, EulaAccepted | Format-List
194+ $global :MoreUpdates = 1
195+ } catch {
196+ LogWrite $_.Exception | Format-List - force
197+ LogWrite " Showing SearchResult was unsuccessful. Rebooting."
198+ $global :RestartRequired = 1
199+ $global :MoreUpdates = 0
200+ Check- ContinueRestartOrEnd
201+ LogWrite " Show never happen to see this text!"
202+ Restart-Computer
203+ }
150204 } else {
151- Write-Host ' There are no applicable updates'
205+ LogWrite ' There are no applicable updates'
152206 $global :RestartRequired = 0
153207 $global :MoreUpdates = 0
154208 }
@@ -161,10 +215,11 @@ $script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
161215$script :UpdateSearcher = $script :UpdateSession.CreateUpdateSearcher ()
162216$script :SearchResult = New-Object - ComObject ' Microsoft.Update.UpdateColl'
163217$script :Cycles = 0
218+ $script :CycleUpdateCount = 0
164219
165220Check- WindowsUpdates
166221if ($global :MoreUpdates -eq 1 ) {
167222 Install-WindowsUpdates
168223} else {
169224 Check- ContinueRestartOrEnd
170- }
225+ }
0 commit comments