<#
.SYNOPSIS
Performs Windows updates with removal of unwanted installed and pending updates.
.DESCRIPTION
Reads a list of unwanted KB numbers from PoSh-Update.ini and uninstalls them from
the system and hides them in pending updates.
Optionally installs any other pending updates.
.REQUIREMENTS
Powershell v2+
Windows Update Powershell Module (https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc)
Elevated Powershell console
.INSTALLATION
Extract files to a folder, PoSh-Update.ini is to reside in the same folder as
PoSh-Update.ps1
See included PoSh-Update.ini for format.
.PARAMETER <paramName>
None
.EXAMPLE
C:\PoSh-Update> powershell.exe -noprofile -executionpolicy bypass -File ".\PoSh-Update.ps1"
#>
#Requires -runasadministrator
$global:restart = $false # Flag for restart requirement on (un)install
# Checks passed KB number against updates installed on system, attempts to uninstall if found
Function Check-Installed {
Param(
[String]$KB
)
if (!(Get-HotFix -Id $KB)) {
Write-Host $KB": Not installed" -ForegroundColor yellow -NoNewline
Return $false
} else {
Write-Host $KB": Found, attempting uninstall" -ForegroundColor red -BackgroundColor Black -NoNewline
$command = "wusa.exe"
$args = "/uninstall /quiet /norestart /kb:" + ($KB -replace "kb","")
$proc = Start
-Process
$command -ArgumentList $args -Wait -PassThru switch ($proc.ExitCode) {
0 { Write-Host " Successful " -ForegroundColor Green -BackgroundColor Black }
3010 { Write-Host " Successful - restart required " -ForegroundColor Green -BackgroundColor Black;
$global:restart = $true
}
default {
Write-Host " Failed (Exit code:" $proc.ExitCode")" -ForegroundColor Red -BackgroundColor Black;
Write-Host "See https://support.microsoft.com/en-us/kb/290158 for an explanation"
}
}
Return $true
}
}
# Function to search list of pending updates for occurance of passed KB number from
# unwanted list
Function Check-Pending {
Param(
[string]$KB
)
for ($i = 0; $i -lt $updCol.Count; $i++) {
if ($updCol[$i].KB -imatch $KB) {
Write-Host ", " -ForegroundColor Yellow -NoNewline
Write-Host "found pending," -ForegroundColor Red -BackgroundColor Black -NoNewline
# Try hiding the update
Hide-Update $KB
# Remove from Update collection regardless of result since we don't want it
$global:updCol.Remove($updCol[$i]) # | Out-Null
# Return TRUE if it was found
Return $true
}
}
# If it wasn't found then there's no reason to hide it
Write-Host " or pending" -ForegroundColor Yellow
Return $false
}
# Function to hide an update using KB number
Function Hide-Update {
Param(
[string]$idKB
)
$test = (Hide-WUUpdate -KBArticleID $idKB -Confirm:$false)
if ($test.Status -match "H") {
Write-Host " successfully hidden" -ForegroundColor Green
} else {
Write-Host " hiding unsuccessful " -ForegroundColor Red -BackgroundColor Gray
}
}
Function Install-Updates {
# Convert array of remaining KB IDs to string using Output Field Separator ($ofs)
# then pass to Get-WUInstall
$ofs = '","'
$KBList = '"'+[string]$updCol.KB+'"'
Get-WUInstall -KBArticleID $KBList -AcceptAll -IgnoreReboot -Verbose
}
# Read list of unwanted KBs into an object
$uwList = Get-Content PoSh-Update.ini
# Fetch list of available updates into an object
Write-Host "Fetching list of pending updates from Microsoft servers ... please wait" -BackgroundColor Black
$updates = Get-WUList -MicrosoftUpdate -IsNotHidden -NotCategory Driver
Write-Host $updates.Count "pending update(s)" -BackgroundColor Black
$global:updCol = {$updates}.Invoke() # Copy object array to collection so we can remove items
$init = $updCol.Count # Initial number of updates before cull
# For each item in the Unwanted list, iterate through collection to check for installed/pending
$uwList | foreach {
if (!(Check
-Installed
$_)) { Check
-Pending
$_ | Out-Null } }
# Results of cull
Write-Host ""
Write-Host "PoSh-Update.ini contained a total of" $uwList.Count "update(s) to ignore." -BackgroundColor Black
Write-Host "A total of" ($init - $updCol.Count) "update(s) removed from pending update list." -BackgroundColor Black
Write-Host "There is/are" $updCol.Count "update(s) left to install." -BackgroundColor Black
Write-Host ""
# If a restart was indicated during uninstallation, indicate it otherwise offer to install
# remaining updates
if ($restart) {
Write-Host "A restart was indicated to complete uninstallation of one or more updates." -ForegroundColor Yellow -BackgroundColor Black
Write-Host "Please do so before attempting installation of further updates."
Write-Host ""
Write-Host "You may re-run this script after a restart."
} else {
Write-Host "Preparing to install remaining updates:"
$updCol | Format-Table KB, Status, Size, Title -AutoSize
# Simple Yes/No requester
$a = new-object -comobject wscript.shell
$intAnswer = $a.popup("Continue with installation:", 0, "", 4)
If ($intAnswer -ne 6) {
Exit # No
} else {
Install-Updates
}
}