win-updates.ps1 7.43 KB
Newer Older
1
param($global:RestartRequired=0,
2
        $global:MoreUpdates=0,
3
        $global:MaxCycles=5,
4
        $MaxUpdatesPerCycle=500)
5
6

function Check-ContinueRestartOrEnd() {
7
8
9
    $RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
    $RegistryEntry = "InstallWindowsUpdates"
    switch ($global:RestartRequired) {
Stefan Scherer's avatar
Stefan Scherer committed
10
        0 {
11
12
13
14
15
            $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
            if ($prop) {
                Write-Host "Restart Registry Entry Exists - Removing It"
                Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
            }
Stefan Scherer's avatar
Stefan Scherer committed
16

17
18
19
20
21
22
23
            Write-Host "No Restart Required"
            Check-WindowsUpdates
            
            if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
                Install-WindowsUpdates
            } elseif ($script:Cycles -gt $global:MaxCycles) {
                Write-Host "Exceeded Cycle Count - Stopping"
Stefan Scherer's avatar
Stefan Scherer committed
24
            } else {
25
                Write-Host "Done Installing Windows Updates"
26
                Invoke-Expression "a:\openssh.ps1 -AutoStart"
27
28
29
30
31
32
            }
        }
        1 {
            $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
            if (-not $prop) {
                Write-Host "Restart Registry Entry Does Not Exist - Creating It"
33
                Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $($script:ScriptPath) -MaxUpdatesPerCycle $($MaxUpdatesPerCycle)"
34
35
36
            } else {
                Write-Host "Restart Registry Entry Exists Already"
            }
Stefan Scherer's avatar
Stefan Scherer committed
37

38
39
40
41
42
43
44
            Write-Host "Restart Required - Restarting..."
            Restart-Computer
        }
        default { 
            Write-Host "Unsure If A Restart Is Required" 
            break
        }
45
46
47
48
    }
}

function Install-WindowsUpdates() {
49
    $script:Cycles++
50
    Write-Host "Evaluating Available Updates with limit of $($MaxUpdatesPerCycle):"
51
    $UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
52
    $script:i = 0;
Ken Sykora's avatar
Ken Sykora committed
53
    $CurrentUpdates = $SearchResult.Updates | Select-Object
54
    while($script:i -lt $CurrentUpdates.Count -and $script:CycleUpdateCount -lt $MaxUpdatesPerCycle) {
Ken Sykora's avatar
Ken Sykora committed
55
        $Update = $CurrentUpdates[$script:i]
56
57
58
59
60
61
62
63
64
        if (($Update -ne $null) -and (!$Update.IsDownloaded)) {
            [bool]$addThisUpdate = $false
            if ($Update.InstallationBehavior.CanRequestUserInput) {
                Write-Host "> Skipping: $($Update.Title) because it requires user input"
            } else {
                if (!($Update.EulaAccepted)) {
                    Write-Host "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
                    $Update.AcceptEula()
                    [bool]$addThisUpdate = $true
65
                    $script:CycleUpdateCount++
66
67
                } else {
                    [bool]$addThisUpdate = $true
68
                    $script:CycleUpdateCount++
69
70
                }
            }
Stefan Scherer's avatar
Stefan Scherer committed
71

72
73
74
75
            if ([bool]$addThisUpdate) {
                Write-Host "Adding: $($Update.Title)"
                $UpdatesToDownload.Add($Update) |Out-Null
            }
Stefan Scherer's avatar
Stefan Scherer committed
76
        }
77
        $script:i++
78
79
80
81
82
83
84
85
86
87
    }
    
    if ($UpdatesToDownload.Count -eq 0) {
        Write-Host "No Updates To Download..."
    } else {
        Write-Host 'Downloading Updates...'
        $Downloader = $UpdateSession.CreateUpdateDownloader()
        $Downloader.Updates = $UpdatesToDownload
        $Downloader.Download()
    }
Stefan Scherer's avatar
Stefan Scherer committed
88

89
90
91
92
93
94
95
    $UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
    [bool]$rebootMayBeRequired = $false
    Write-Host 'The following updates are downloaded and ready to be installed:'
    foreach ($Update in $SearchResult.Updates) {
        if (($Update.IsDownloaded)) {
            Write-Host "> $($Update.Title)"
            $UpdatesToInstall.Add($Update) |Out-Null
96
              
97
98
99
100
101
            if ($Update.InstallationBehavior.RebootBehavior -gt 0){
                [bool]$rebootMayBeRequired = $true
            }
        }
    }
Stefan Scherer's avatar
Stefan Scherer committed
102

103
104
105
106
    if ($UpdatesToInstall.Count -eq 0) {
        Write-Host 'No updates available to install...'
        $global:MoreUpdates=0
        $global:RestartRequired=0
107
        Invoke-Expression "a:\openssh.ps1 -AutoStart"
108
        break
109
110
    }

111
112
113
114
    if ($rebootMayBeRequired) {
        Write-Host 'These updates may require a reboot'
        $global:RestartRequired=1
    }
Stefan Scherer's avatar
Stefan Scherer committed
115

116
    Write-Host 'Installing updates...'
117
  
118
119
120
    $Installer = $script:UpdateSession.CreateUpdateInstaller()
    $Installer.Updates = $UpdatesToInstall
    $InstallationResult = $Installer.Install()
Stefan Scherer's avatar
Stefan Scherer committed
121

122
123
124
125
126
127
128
129
    Write-Host "Installation Result: $($InstallationResult.ResultCode)"
    Write-Host "Reboot Required: $($InstallationResult.RebootRequired)"
    Write-Host 'Listing of updates installed and individual installation results:'
    if ($InstallationResult.RebootRequired) {
        $global:RestartRequired=1
    } else {
        $global:RestartRequired=0
    }
Stefan Scherer's avatar
Stefan Scherer committed
130

131
132
133
134
    for($i=0; $i -lt $UpdatesToInstall.Count; $i++) {
        New-Object -TypeName PSObject -Property @{
            Title = $UpdatesToInstall.Item($i).Title
            Result = $InstallationResult.GetUpdateResult($i).ResultCode
135
        }
136
    }
Stefan Scherer's avatar
Stefan Scherer committed
137

138
    Check-ContinueRestartOrEnd
139
}
140

141
function Check-WindowsUpdates() {
142
143
    Write-Host "Checking For Windows Updates"
    $Username = $env:USERDOMAIN + "\" + $env:USERNAME
Stefan Scherer's avatar
Stefan Scherer committed
144

145
    New-EventLog -Source $ScriptName -LogName 'Windows Powershell' -ErrorAction SilentlyContinue
Stefan Scherer's avatar
Stefan Scherer committed
146

147
    $Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString()
148

149
150
    Write-EventLog -LogName 'Windows Powershell' -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
    Write-Host $Message
151

152
    $script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
153
154
155
156
157
158
159
160
    $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 {
Ken Sykora's avatar
Ken Sykora committed
161
162
            Write-Host $_.Exception | Format-List -force
            Write-Host "Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
163
164
165
166
167
            $script:attempts = $script:attempts + 1
            Start-Sleep -s 10
        }
    }

168
169
170
171
172
173
174
175
    if ($SearchResult.Updates.Count -ne 0) {
        $script:SearchResult.Updates |Select-Object -Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired, EulaAccepted |Format-List
        $global:MoreUpdates=1
    } else {
        Write-Host 'There are no applicable updates'
        $global:RestartRequired=0
        $global:MoreUpdates=0
    }
176
177
178
179
180
181
182
183
184
}

$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
185
$script:CycleUpdateCount = 0
186
187
188

Check-WindowsUpdates
if ($global:MoreUpdates -eq 1) {
189
    Install-WindowsUpdates
190
} else {
191
    Check-ContinueRestartOrEnd
Stefan Scherer's avatar
Stefan Scherer committed
192
}