Skip to content

Instantly share code, notes, and snippets.

@randomchance
Last active August 18, 2016 21:45
Show Gist options
  • Save randomchance/e0e54f93fb32d83cd869e50dfab39e76 to your computer and use it in GitHub Desktop.
Save randomchance/e0e54f93fb32d83cd869e50dfab39e76 to your computer and use it in GitHub Desktop.
Query computers for windows update status. Now writes out warnings for computers needing patches.
<#
.EXAMPLE
Get-WindowsUpdateStatus -ComputerName ('Server01.test.local,'Server02.test.local')
ComputerName HasPendingUpdates Updates
------------ ----------------- -------
Server01 False {}
Server01 False {}
.EXAMPLE
Get-WindowsUpdateStatus -DiscoverDomainComputers
WARNING: Server03 requires 9 updates
ComputerName HasPendingUpdates Updates
------------ ----------------- -------
Server01 False {}
Server02 False {}
Server03 True {@{T...
#>
Function Get-WindowsUpdateStatus{
[cmdletbinding(DefaultParameterSetName='computername')]
param(
[parameter(ValueFromPipeline=$true,ParameterSetName='computername')]
[string[]]
$ComputerName = $env:COMPUTERNAME,
[switch]
[parameter(Mandatory=$true,ParameterSetName='discover')]
$DiscoverDomainComputers
)
begin{
if($DiscoverDomainComputers){
$Domain = Get-ADDomain
[string[]] $clusters = Get-Cluster -Domain $Domain.DNSRoot
$AllDomainComputers = Get-ADComputer -Filter {Name -like "*" } | Where-Object { $_.Name -notin $clusters}
$ComputerName =$AllDomainComputers.DnsHostName
}
$script:ServerUpdateStatus = {
$Query = "IsInstalled=0"
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchResult = $Searcher.Search($Query).Updates
$BasicUpdateInfo =@(
'Title'
@{Name='KBArticleIDs';Expression={[string[]]$_.KBArticleIDs}}
@{Name='Categories';Expression={$_.Categories | Select-Object -Property ('Name','Description')}}
'RebootRequired'
)
$DetailedUpdateInfo = @(
'Title'
@{Name='KBArticleIDs';Expression={[string[]]$_.KBArticleIDs}}
@{Name='Categories';Expression={$_.Categories | Select-Object -Property ('Name','Description')}}
'Description'
'IsDownloaded'
'IsInstalled'
'IsMandatory'
'IsUninstallable'
'UninstallationNotes'
'RebootRequired'
@{Name='BundledUpdates';Expression={$_.BundledUpdates | Select-Object -Property $BasicUpdateInfo }}
)
if($SearchResult.Count -ne 0){
Write-Warning -Message "$env:COMPUTERNAME requires $($SearchResult.Count) updates"
} else {
Write-Verbose -Message "$env:COMPUTERNAME does not require patches."
}
# This ensures the property is a collection, even when empty.
# That means $Updates[0].Updates.Count will always work.
$Updates = @()
$Updates += ($SearchResult | Select-Object -Property $DetailedUpdateInfo )
[pscustomobject]@{
ComputerName = $env:COMPUTERNAME
HasPendingUpdates= ($SearchResult.Count -ne 0)
Updates = $Updates
}
}
}
process{
# Invoke-Command can be finicky when targeting the localhost, so just skip that and run directly.
# Using -icontains and -inotin to be explictly case insensitive.
if($ComputerName -icontains $env:COMPUTERNAME -or
$ComputerName -icontains "$env:computername.$env:userdnsdomain" -or
$ComputerName -icontains "localhost"
){
& $script:ServerUpdateStatus
}
# Now just remove localhost
[string[]]$RemoteServers = $ComputerName |
Where-Object {$_ -inotin @($env:COMPUTERNAME,"$env:computername.$env:userdnsdomain","localhost")}
if($RemoteServers.Count -gt 0){
$commandParameters = @{
ComputerName= $RemoteServers
ScriptBlock = $script:ServerUpdateStatus
}
Invoke-Command @commandParameters | Select-Object -Property ('ComputerName','HasPendingUpdates','Updates')
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment