Windows Update from Specific date.

We had a pretty standard situation, wanted to patch a bunch of servers with all patches up to a specific date. Colleague and friend of mine created the below script which proved extremely helpful.

All credits to the below mentioned people.

#------------------------------------------------------------------------
NAME: update-installer.ps1
AUTHOR: Mads H. Larsen
DATE:28/05/2013
Tested on PSversions: 2.0, 3.0

COMMENTS:
This script checks windows update for applicable updates to the system,
and then downloads and installs them. If you enter a date that is earlier
than todays date, only updates from that date or earlier are installed.

Most of the inner workings of the script is copied from:
http://www.ehow.com/how_8724332_use-powershell-run-windows-updates.html

I just added some code to compare the dates, check connectivity, show size
and elapsed time and do some formatting.
#------------------------------------------------------------------------
$runTime = [System.Diagnostics.Stopwatch]::StartNew()
cls
Write-Host "Verifying connectivity, please wait..."
[string] $url = 'https://www.update.microsoft.com'
[net.httpWebRequest] $req = [net.webRequest]::create($url)
$req.Method = "HEAD"

Try {[net.httpWebResponse] $res = $req.getResponse()}
Catch {Write-Host "$url is not available. Could not resolve $($url) " -foregroundColor red;return}
if (!($res.StatusCode -ge "200" -and $res.StatusCode -lt "400")) {Write-Host "$($url) is not available. HTTP StatusCode $($res.StatusCode)" -foregroundColor red;return}

cls

function Get-WIAStatusValue($value)
{
switch -exact ($value)
{
0 {"NotStarted"}
1 {"InProgress"}
2 {"Succeeded"}
3 {"SucceededWithErrors"}
4 {"Failed"}
5 {"Aborted"}
}
}
$sw = New-Object System.Diagnostics.Stopwatch

$number = 0
$totalSize = 0
$totalDownloaded = 0
$needsReboot = $false

$date = Get-Date (Read-Host "Input target date ($((Get-culture).DateTimeFormat.ShortDatePattern))")

$updateSession = New-Object -ComObject Microsoft.Update.Session
$updateSearcher = $updateSession.CreateUpdateSearcher()

Write-Host " - Searching for updates"
$searchResult = $updateSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0")
$updates = $searchResult.Updates | Where-Object {($_.LastDeploymentChangeTime -le $date)}

Write-Host " - Found [$($updates.count)] updates to download and install"
if($($updates.count) -eq $null) {return}

$updates | Format-Table @{Expression={($_.LastDeploymentChangeTime).ToString(" dd-MM-yyyy ")};Alignment=”center”;Label="dd-MM-yyyy"},@{Expression={$_.KBArticleIDs};Alignment=”center”;Label=" KBID "},@{Expression={$_.MsrcSeverity};Alignment=”center”;Label="Severity "} -AutoSize
$totalSize = ($searchResult.Updates | measure-Object -sum MaxDownloadSize).Sum
Write-Host " ---------------------------------"
Write-Host (" = Total of {0:n2} MB to download`n" -f ($totalSize/1MB))

foreach($update in $updates)
{
# Add update to collection
Write-Host " [$(Get-Date -Format dd)-$(Get-Date -Format MM)-$(Get-Date -Format yyyy) @ $(Get-Date -Format HH):$(Get-Date -Format mm):$(Get-Date -Format ss)]"
$updatesCollection = New-Object -ComObject Microsoft.Update.UpdateColl
if ( $update.EulaAccepted -eq 0 ) { $update.AcceptEula() }
$updatesCollection.Add($update) | out-null
# Download
$number++
$size = $update.MaxDownloadSize/1MB
$size = "{0:N2}" -f $size
$totalDownloaded = $totalDownloaded + $size
Write-Host " + Downloading $number of $($updates.count) - $size MB:" $($update.Title)
$sw.Reset();$sw.Start()
$updatesDownloader = $updateSession.CreateUpdateDownloader()
$updatesDownloader.Updates = $updatesCollection
$downloadResult = $updatesDownloader.Download()
$sw.Stop()
$message = " - Download {0}" -f (Get-WIAStatusValue $downloadResult.ResultCode)
if($sw.Elapsed.Seconds -lt 1){Write-Host $message "in less than 1 second"}else{Write-Host $message "in $($sw.Elapsed.Hours)h$($sw.Elapsed.Minutes)m$($sw.Elapsed.Seconds)s"}
# Install
Write-Host " - Installing update"
$sw.Reset();$sw.Start()
$updatesInstaller = $updateSession.CreateUpdateInstaller()
$updatesInstaller.Updates = $updatesCollection
$installResult = $updatesInstaller.Install()
$sw.Stop()
$message = " - Install {0}" -f (Get-WIAStatusValue $downloadResult.ResultCode)
if($sw.Elapsed.Seconds -lt 1){Write-Host $message "in less than 1 second"}else{Write-Host $message "in $($sw.Elapsed.Hours)h$($sw.Elapsed.Minutes)m$($sw.Elapsed.Seconds)s"}
Write-Host
$needsReboot = $installResult.rebootRequired
}
if($needsReboot){Write-Host " One or more updates require a reboot to complete installation" -foregroundcolor "red"}

$runTime.Stop()
Write-Host -foregroundColor yellow "`n $totalDownloaded MB of updates downloaded and installed in $($runTime.Elapsed.Hours) hour(s) $($runTime.Elapsed.Minutes) minute(s) $($runTime.Elapsed.Seconds) second(s)."
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s