-
Notifications
You must be signed in to change notification settings - Fork 0
/
Auto-WsusUpdates.ps1
238 lines (205 loc) · 8.37 KB
/
Auto-WsusUpdates.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
<#
.SYNOPSIS
Approve, decline and delete updates in Windows Server Update Services (WSUS).
.DESCRIPTION
Decline several types of WSUS updates, such as preview, beta, superseded, language packs, drivers, old Windows versions. Also decline all updates for ARM and x86 architectures.
Approve all updates that are not declined.
Delete all declined updates.
.PARAMETER DeclineAll
Decline all updates on the WSUS server. Useful before a cleanup, when you want to save disk space.
.PARAMETER AutoDecline
Decline WSUS updates that are preview, beta, superseded, language packs, drivers. Decline all updates for ARM and x86 architectures.
Any update meant for a Windows 10 version before 22H2 will also be declined.
.PARAMETER AutoApprove
Approve all updates that have not been approved or declined, for the target group "All Computers".
.PARAMETER DeleteDeclined
Delete from WSUS all updates that are marked as declined.
.PARAMETER WsusSync
Start the sync process on the WSUS server. This parameter takes precedence over the others, except cleanup. If both WsusCleanup and WsusSync are selected, the script will first perform a cleanup and then sync.
The script will wait until the sync is completed, then process the other operations, if any.
.PARAMETER WsusCleanup
Start the cleanup process on the WSUS server. This parameter takes precedence over all others. If both WsusCleanup and WsusSync are selected, the script will first perform a cleanup and then sync.
The script will wait until the cleanup is completed, then process the other operations, if any.
.PARAMETER Server
The WSUS server. Deafult is localhost.
.PARAMETER UseSSL
If SSL is needed to connect to the WSUS server. Default is False.
.PARAMETER PortNumber
The port number used by WSUS. Default is 8530.
.EXAMPLE
Auto-WSUSUpdates.ps1 -WsusSync -AutoDecline -AutoApprove
Trigger a sync and wait for it to complete. Decline all updates that are not needed, and approve the remaining ones.
.EXAMPLE
Auto-WSUSUpdates.ps1 -AutoDecline -DeleteDeclined
Decline all updates that are not needed, and then delete them from the server.
.EXAMPLE
Auto-WSUSUpdates.ps1 -WsusSync -WsusCleanup
Start the WSUS cleanup, then trigger a sync and wait for it to complete.
.EXAMPLE
Auto-WSUSUpdates.ps1 -DeclineAll -DeleteDeclined
Mark all updates as declined, then delete them. This will remove all updates from the server.
#>
[cmdletbinding()]
Param(
[Parameter(Position = 1)]
[string]$Server = ([system.net.dns]::GetHostByName('localhost')).hostname,
[Parameter(Position = 2)]
[bool]$UseSSL = $False,
[Parameter(Position = 3)]
[int]$PortNumber = 8530,
[switch]$AutoDecline,
[switch]$DeclineAll,
[switch]$DeleteDeclined,
[switch]$AutoApprove,
[switch]$WsusSync,
[switch]$WsusCleanup
)
$versions = @(
'Windows 10 Version 1507',
'Windows 10 Version 1607',
'Windows 10 Version 1809',
'Windows 10 Version 21H2'
)
try {
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
}
catch {
Write-Host 'Could not load the Microsoft.UpdateServices.Administration assembly.'
exit
}
try {
$WsusServer = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($Server, $UseSSL, $PortNumber)
}
catch {
Write-Host 'Could not connect to the WSUS server.'
exit
}
if ($WsusCleanup) {
Write-Host 'Starting the cleanup process. This will take a while.'
$cleanupScope = new-object Microsoft.UpdateServices.Administration.CleanupScope
$cleanupScope.CleanupLocalPublishedContentFiles = $true
$cleanupScope.CleanupObsoleteComputers = $true
$cleanupScope.CleanupObsoleteUpdates = $true
$cleanupScope.CleanupUnneededContentFiles = $true
$cleanupScope.CompressUpdates = $true
$cleanupScope.DeclineExpiredUpdates = $true
$cleanupScope.DeclineSupersededUpdates = $true
$cleanupManager = $wsusServer.getCleanupManager()
$res = $cleanupManager.PerformCleanup($cleanupScope)
Write-Host 'Cleanup results'
Write-Host ('Disk space freed: ' + ($res.DiskSpaceFreed/1MB) + ' MB')
Write-Host ('Expired updates declined: ' + $res.ExpiredUpdatesDeclined)
Write-Host ('Obsolete computers deleted: ' + $res.ObsoleteComputersDeleted)
Write-Host ('Obsolete updates deleted: ' + $res.ObsoleteUpdatesDeleted)
Write-Host ('Superseded updates declined: ' + $res.SupersededUpdatesDeclined)
Write-Host ('Updates with old revisions removed: ' + $res.UpdatesCompressed)
Write-Host ''
}
if ($WsusSync) {
$subscription = $WsusServer.GetSubscription()
Write-Host 'Starting syncronization'
$subscription.StartSynchronization()
Start-Sleep -Seconds 60
while ($subscription.GetSynchronizationProgress().Phase -ne 'NotProcessing')
{
Start-Sleep -Seconds 300
Write-Host '.' -NoNewline
}
Write-Host '.'
Write-Host 'Syncronization finished'
Write-Host ''
}
if ($AutoDecline -or $DeclineAll) {
$allUpdates = $WsusServer.GetUpdates()
$totalCount = $allUpdates.count
$declinedCount = 0
foreach ($update in $allUpdates) {
# Skip updates that are already declined
if ($update.IsDeclined) {
continue
}
# DeclineAll option will decline all updates
if ($DeclineAll) {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline all updates in Preview or Beta
if (($update.Title -match "preview|beta|dev channel") -or ($update.IsBeta -eq $true)) {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline superseeded updates
if ($update.IsSuperseded -eq $true) {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline updates for Arm64
if ($update.Title -match "ARM64") {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline updates for x86
# The title can contain either 'x86-based' or 'x86 based' text
if ($update.Title -like "*x86?based*") {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline updates for old versions of Windows 10
$declined = $false
foreach ($v in $versions) {
if ($update.Title -match $v) {
$update.Decline()
$declinedCount = $declinedCount + 1
$declined = $true
break
}
}
if ($declined) {
continue
}
# Decline Language packs
if ($update.Title -match "LanguageFeatureOnDemand|Lang Pack (Language Feature) Feature On Demand|LanguageInterfacePack") {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
# Decline driver updates
if ($update.Classification -match "Drivers") {
$update.Decline()
$declinedCount = $declinedCount + 1
continue
}
}
Write-Host "Declined $declinedCount updates out of $totalCount."
}
# Delete all declined updates
if ($DeleteDeclined) {
# get all declined updates
$allDeclined = $WsusServer.GetUpdates([Microsoft.UpdateServices.Administration.ApprovedStates]::Declined, [DateTime]::MinValue, [DateTime]::MaxValue, $null, $null)
Write-Host ('' + $allDeclined.count + ' declined updates found')
$count = 0
foreach ($update in $allDeclined) {
$WsusServer.DeleteUpdate($update.Id.UpdateId.ToString())
$count++
}
Write-Host "$count updates deleted."
}
# Auto-approve updates
if ($autoApprove) {
# Select only the updates that are marked as needed and are not already installed
$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updatescope.ApprovedStates = [Microsoft.UpdateServices.Administration.ApprovedStates]::NotApproved
$allUpdates = $WsusServer.GetUpdates($updatescope)
$approvalGroups = $WsusServer.GetComputerTargetGroups()
$approvalGroup = $approvalGroups[0]
foreach ($update in $allUpdates) {
$update.Approve([Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install, $approvalGroup) | Out-Null
$update.Refresh() | Out-Null
}
Write-Host ('' + $allUpdates.count + " updates approved.")
}