Last active
June 12, 2018 08:27
-
-
Save mhudasch/3d91f7f03f6a513cf19c0b18d00ecfba to your computer and use it in GitHub Desktop.
Find pending windows updates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Function Get-PendingWindowsUpdate { | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0, ValueFromPipeline = $true)] | |
[string[]]$ComputerName = $env:COMPUTERNAME) | |
Process { | |
# Use this scriptblock for both remote and local execution | |
$unifiedScriptBlock = [scriptblock]{ | |
param([string]$computer) | |
$ErrorActionPreference = $using:ErrorActionPreference; | |
$VerbosePreference = $using:VerbosePreference; | |
$ConfirmPreference = $using:ConfirmPreference; | |
$start = [datetime]::now; | |
# Prepare output | |
$result = New-Object psobject -Property @{ | |
ComputerName=$computer; | |
Error=$null; | |
Updates=@(); | |
LastCheck=$null; | |
Took=0; | |
}; | |
Try { | |
# Only do this when you are in the local administrators group | |
If (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { | |
throw "You are not running this as an Administrator!`nPlease re-run this with an Administrator account."; | |
} | |
# Don't go further if the machine already needs a reboot because of an earlier update. | |
IF (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") { | |
throw "There is an update related reboot pending. Please reboot the machine an perform this command again." | |
} | |
# Before we perform a slow search for updates we check the registry flags to maybe skip the search | |
# When there was a search in the last 3 days and no updates need to be installed return here | |
If (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\UAS") { | |
If ( ((Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\UAS").GetValue("UpdateCount") -eq 0) -and | |
((Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Detect").GetValue("LastSuccessTime") -lt | |
([datetime]::Now.Subtract([timespan]::FromDays(3)))) ) { | |
$result.LastCheck = ([datetime](Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Detect").GetValue("LastSuccessTime")).ToLocalTime(); | |
$result.Took = [datetime]::Now.Subtract($start).TotalMilliseconds; | |
return $result; | |
} | |
} | |
#Create Session COM object | |
Write-Verbose ("Creating COM object for WSUS Session. > Computer: {0}" -f $computer); | |
$updateSession = New-Object -ComObject microsoft.update.session; | |
#Configure Session COM Object | |
Write-Verbose ("Creating COM object for WSUS update Search. > Computer: {0}" -f $computer); | |
$updateSearcher = $updateSession.CreateUpdateSearcher(); | |
#Configure Searcher object to look for Updates awaiting installation | |
Write-Verbose ("Searching for WSUS updates on client. > Computer: {0}" -f $computer); | |
$searchResult = $updateSearcher.Search("IsInstalled=0"); | |
$updates = $searchResult.Updates; | |
#Verify if Updates need installed | |
Write-Verbose ("Verifing that updates are available to install. > Computer: {0}" -f $computer); | |
If ($updates.Count -gt 0) { | |
#Updates are waiting to be installed | |
Write-Verbose ("Found {1} update\s! > Computer: {0}" -f $computer, $updates.Count); | |
#Cache the count to make the For loop run faster | |
$count = $updates.Count | |
#Begin iterating through Updates available for installation | |
Write-Verbose ("Iterating through list of updates. > Computer: {0}" -f $computer); | |
For ($i=0; $i -lt $count; $i++) { | |
#Create object holding update | |
$update = $updates.Item($i) | |
$result.Updates += New-Object psobject -Property @{ | |
Computer = $computer; | |
Title = $update.Title; | |
KB = $($update.KBArticleIDs); | |
SecurityBulletin = $($update.SecurityBulletinIDs); | |
MsrcSeverity = $update.MsrcSeverity; | |
IsDownloaded = $update.IsDownloaded; | |
Url = $($update.MoreInfoUrls); | |
Categories = ($update.Categories | Select-Object -ExpandProperty Name); | |
RebootRequired = $update.RebootRequired; | |
MaxDownloadSize = $update.MaxDownloadSize; | |
MinDownloadSize = $update.MinDownloadSize; | |
ID = $update.Identity.UpdateID; | |
Revision = $update.Identity.RevisionNumber; | |
BundledUpdates = @($update.BundledUpdates) | ForEach-Object { | |
New-Object psobject -Property @{ | |
Title = $_.Title; | |
DownloadUrl = @($_.DownloadContents).DownloadUrl; | |
}; | |
}; | |
}; | |
} | |
} Else { | |
#Nothing to install at this time | |
Write-Verbose ("No updates to install. > Computer: {0}" -f $computer); | |
} | |
$result.LastCheck = $([datetime]::Now); | |
$result.Took = [datetime]::Now.Subtract($start).TotalMilliseconds; | |
Return $result; | |
} Catch { | |
$result.Error = $Error[0]; | |
$result.LastCheck = $([datetime]::Now); | |
$result.Took = [datetime]::Now.Subtract($start).TotalMilliseconds; | |
Return $result; | |
} | |
}; | |
$results = $ComputerName | ForEach-Object { $computer = $_; | |
Try { | |
If(!(Test-Connection -ComputerName $computer -Count 1 -Quiet)) { | |
throw ("Connecting to remote computer {0} failed." -f $computer); | |
} Else { | |
If($computer -eq $env:COMPUTERNAME) { | |
Start-Job -ScriptBlock $unifiedScriptBlock -ArgumentList @($computer); | |
} Else { | |
Invoke-Command -ComputerName $computer -ScriptBlock $unifiedScriptBlock -ArgumentList @($computer) -AsJob -HideComputerName; | |
} | |
} | |
} Catch { | |
Return @{ | |
ComputerName=$computer; | |
Error=$_; | |
Updates=@(); | |
LastCheck=$([datetime]::Now); | |
Took = 0; | |
}; | |
} | |
}; | |
$jobs = $results | Where-Object { $_ -is [System.Management.Automation.Job] }; | |
$jobs | Wait-Job | Out-Null; | |
$u = @($results | Where-Object { $_ -is [hashtable] } | ForEach-Object { New-Object psobject -Property $_; }); | |
$jobs | Receive-Job | ForEach-Object { | |
$u += $_; | |
}; | |
$jobs | Remove-Job | Out-Null; | |
# hide the workflow meta data | |
Return [PsObject[]]($u | ForEach-Object { $_ | Select-Object -Property * -ExcludeProperty PSComputerName,PSSourceJobInstanceId,RunspaceId,PSShowComputerName }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment