fredag den 30. maj 2014

Windows Update with PowerShell

I’ve had a PowerShell script (rewritten from VBS) for a long time. It works and all, but once in a while when your testing stuff on fresh machines it would drive me nuts I couldn’t get a “status” like when your doing it though GUI.

Doing a progress bar while downloading is/was easy enough, but we all know it’s the installation that takes time, and that gave me a few issues. I finally figured out, I couldn’t re-use the installer, and sometimes it fails if you assign each update without first adding it to an “UpdateColl”. So, here it is (download link)

[CmdletBinding()]
Param
(
[switch]$skipReboot
)
Begin {
$Install = $true;
$EulaAccept = $true;

write-progress -id 1 -Activity "Windows Update" -Status "Initialising"
$UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
$UpdateSession.ClientApplicationID = 'Wingu Update Client'
}
Process {
write-progress -id 1 -Activity "Windows Update" -Status "Checking for available updates"
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'") # and IsHidden=0
$UpdatesToDownload = New-Object -com Microsoft.Update.UpdateColl
foreach ($Update in $SearchResult.Updates)
{
[bool]$addThisUpdate = $false
if ($Update.InstallationBehavior.CanRequestUserInput)
{
#Write-Verbose "> Skipping: $($Update.Title) because it requires user input"
[bool]$addThisUpdate = $true
} else {
if (!($Update.EulaAccepted)) {
Write-Verbose "> Note: $($Update.Title) has a license agreement that must be accepted:"
$Update.AcceptEula() | Out-Null
[bool]$addThisUpdate = $true
} else {
[bool]$addThisUpdate = $true
}
}
if ([bool]$addThisUpdate) {
Write-Verbose "Adding: $($Update.Title)"
$UpdatesToDownload.Add($Update) | Out-Null
}
}
if ($UpdatesToDownload.Count -eq 0) {
Write-Verbose 'All applicable updates were skipped.'
return $false
}
$downloader = $updateSession.CreateUpdateDownloader()
foreach($update in $UpdatesToDownload) {
$counter += 1
write-progress -id 1 -Activity "Updating" -Status "Downloading $counter/$($UpdatesToDownload.count) updates"
if(!$update.IsDownloaded) {
write-progress -id 2 -ParentId 1 -Activity "Updating" -Status "Downloading $($update.Title) $([int]($update.MaxDownloadSize / 1MB))MB"
$updateCollection=New-Object -com Microsoft.Update.UpdateColl
$updateCollection.Add($Update) | Out-Null
$downloader.Updates = $updateCollection
$Result = $downloader.Download()
} else {
write-progress -id 2 -ParentId 1 -Activity "Updating" -Status "isready $($update.Title)"
}
}


$needreboot = $false
$updateSystemInfo = new-object -com Microsoft.Update.SystemInfo
if($updateSystemInfo.rebootRequired){ $needreboot = $true }
$counter = 0
foreach($update in $UpdatesToDownload) {
$counter += 1
write-progress -id 1 -Activity "Updating" -Status "Installing $counter/$($UpdatesToDownload.count) updates"
write-progress -id 2 -ParentId 1 -Activity "Updating" -Status "Installing $($update.Title)"
$updatesToInstall = New-object -com "Microsoft.Update.UpdateColl"
$updatesToInstall.Add($update) | out-null
$installer = $updateSession.CreateUpdateInstaller()
$updateCollection=New-Object -com Microsoft.Update.UpdateColl
$updateCollection.Add($Update) | Out-Null
if($installer.ForceQuiet -eq $false) { $installer.ForceQuiet=$true }
$installer.Updates = $updateCollection
$installationResult = $installer.Install()
if($installationResult.rebootRequired){ $needreboot = $true }
if($installationResult.HResult -eq 4) {
#$resultcode= @{0="Not Started"; 1="In Progress"; 2="Succeeded"; 3="Succeeded With Errors"; 4="Failed" ; 5="Aborted" }
Write-Warning "Failed installting $($update.Title) ResultCode $($installationResult.ResultCode) HResult $($installationResult.HResult)"
}
if($installationResult.HResult -eq 5) {
#$resultcode= @{0="Not Started"; 1="In Progress"; 2="Succeeded"; 3="Succeeded With Errors"; 4="Failed" ; 5="Aborted" }
Write-Warning "Aborted $($update.Title) ResultCode $($installationResult.ResultCode) HResult $($installationResult.HResult)"
}
}

if(!$needreboot) {
$arguments = @('/c wuauclt /reportnow')
Start-Process -FilePath "cmd.exe" -ArgumentList $arguments -Wait
}

if(!$skipReboot -and $needreboot){
write-progress -id 2 -ParentId 1 -Activity "Updating" -Status "Rebooting system"
Write-Warning "Reboot required"
Restart-Computer -Force
}
return $needreboot
}
End {
write-progress -id 1 -Activity "Updating" -Status "Windows Update Check Complete" -Completed
}

Ingen kommentarer:

Send en kommentar