Data On Demand Windows update history probe action

Community.DataOnDemand.Probe.GetWindowsUpdateHistory (ProbeActionModuleType)

Returns a list of Windows update events on the target computer.

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeMicrosoft.Windows.SerializedObjectData

Member Modules:

ID Module Type TypeId RunAs 
Probe ProbeAction Microsoft.Windows.PowerShellTriggerOnlyProbe Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
ExcludedKBstring$Config/ExcludedKB$Excluded KBsA comma seperated list of KBs to exclude from the results.
Formatstring$Config/Format$FormatOutput format. Allowed values: csv, json, text, list.
ShowTopstring$Config/ShowTop$TopIf specified, only return the specified number of results.
LastHoursstring$Config/LastHours$Last HoursIf specified, only return events from the last X hours.
TimeoutSecondsint$Config/TimeoutSeconds$Timeout (seconds)Script timeout in seconds.

Source Code:

<ProbeActionModuleType ID="Community.DataOnDemand.Probe.GetWindowsUpdateHistory" Accessibility="Public" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ExcludedKB" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Format" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:int"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="LastHours" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ShowTop" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="ExcludedKB" Selector="$Config/ExcludedKB$" ParameterType="string"/>
<OverrideableParameter ID="Format" Selector="$Config/Format$" ParameterType="string"/>
<OverrideableParameter ID="ShowTop" Selector="$Config/ShowTop$" ParameterType="string"/>
<OverrideableParameter ID="LastHours" Selector="$Config/LastHours$" ParameterType="string"/>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.PowerShellTriggerOnlyProbe">
<ScriptName>Get-WindowsUpdateHistory.ps1</ScriptName>
<ScriptBody><Script>&lt;#
.SYNOPSIS
Community.DataOnDemand windows update history enumeration script
.DESCRIPTION
This script enumerates windows update history and outputs formatted text
.PARAMETER Format
Permitted values: text, csv, json, list
.PARAMETER ShowTop
(optional) Max number of results to output
.PARAMETER ExcludedKB
(optional) A comma seperated list of KB numbers to exclude
.PARAMETER LastHours
(optional) Only display update events from the last x hours
.NOTES
Copyright 2018 Squared Up Limited, All Rights Reserved.
#&gt;
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
Param(
[ValidateSet("text","csv","csvEx","json","list")]
[string] $Format = "csv",
[int]$ShowTop,
[string]$ExcludedKB,
[int]$LastHours
)

# define a variable to hold the output, with header as the first item
$output = @('KB Article,KB Name,Installation Date,Installation Status')

# create a new instance of the Update Session COM object
$Session = New-Object -ComObject Microsoft.Update.Session

# create a searcher object
$Searcher = $Session.CreateUpdateSearcher()

# query for all events in the Update History
$queryResult = $Searcher.QueryHistory(0,$Searcher.GetTotalHistoryCount())

# create a collection to hold the items we are about to create
[System.Collections.ArrayList]$WindowsUpdates = New-Object -Type System.Collections.ArrayList

# Populate Exclusion List (adding if specified)
$ExclusionList = @()
if ($ExcludedKB -ne "")
{
# split the string out
$ExclusionList = $ExcludedKB.Split(",") | ForEach-Object { $_ -replace '^(KB)?(\d{6,7})','KB$2'}
}

# generate the date events must be newer than
$since = [datetime]::MinValue
if ($LastHours) {
$since = [datetime]::UtcNow.AddHours(-1 * $LastHours)
}

# loop through the query results
foreach ($item in $queryResult)
{

# Skip if update installed outside LastHours timewindow
if ($item.Date -lt $since) {
continue;
}

# Default to title from query
$KBArticle = $null
$Title = $item.Title

# if the title contains a KB article number then...
if($item.Title -match "\(?KB\d{6,7}\)?"){

# put the actual title, minus the KB ref, into the title variable
$KBArticle = $Matches[0].Trim(' ','(',')')
$Title = $item.title -replace "\s?\(?$KBArticle\)?",''
}

# Skip null entries or if the KBArticle is in the exclusion list
if ([string]::IsNullOrEmpty($item.Title) -or $ExclusionList -contains "$KBArticle") {
continue;
}

# make sure the result is empty
$Result = $null

# load the result based on the value of the result code
Switch ($item.ResultCode)
{
0 { $Result = 'NotStarted'}
1 { $Result = 'InProgress' }
2 { $Result = 'Succeeded' }
3 { $Result = 'SucceededWithErrors' }
4 { $Result = 'Failed' }
5 { $Result = 'Aborted' }
default { $Result = $item.ResultCode }
}

# create a new object and populate it with values; note that the InstallOn value is converted to the local Server time
$newObject = New-Object -TypeName PSObject -Property @{
InstalledOn =$item.Date;
KBArticle = $KBArticle;
Name = $Title;
Status = $Result
}

# add to the collection
$WindowsUpdates.Add($newObject) | Out-Null
}

# sort by installedOn value
$WindowsUpdates = @($WindowsUpdates | Sort-Object InstalledOn -Descending:$true)

# loop through the elements to build the output string, limited by ShowTop
# Due to the way null values are bound by SCOM -&gt; PS, a default value in the param will always be overridden
if (-not $ShowTop) {
$ShowTop = [int]::MaxValue
}
$outputCount = [math]::Min($ShowTop, $WindowsUpdates.Count)

for ($i = 0; $i -lt $outputCount; $i++) {
$item = $WindowsUpdates[$i]

# create a new line in the output file
$output += '"{0}","{1}","{2}","{3}"' -f `
$item.KBArticle,
$item.Name,
$item.InstalledOn.ToString("u"),
$item.Status
}

# output to the required format
if ($Format -eq 'text')
{
ConvertFrom-Csv $output `
| Format-Table -AutoSize `
| Out-String -Width 4096 `
| Write-Host
}
elseif ($Format -eq 'csv')
{
$output`
| Out-String -Width 4096 `
| Write-Host
}
elseif ($Format -eq 'csvEx')
{
$output `
| ForEach-Object {"$_%EOL%"} `
| Out-String -Width 4096 `
| Write-Host
}
elseif ($Format -eq 'json')
{
ConvertFrom-Csv $output `
| ConvertTo-Json `
| Out-String -Width 4096 `
| Write-Host
}
elseif ($Format -eq 'list')
{
ConvertFrom-Csv $output `
| Format-List `
| Out-String -Width 4096 `
| Write-Host
}

# Done. (do not remove blank line following this comment as it can cause problems when script is sent to SCOM agent!)
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>ExcludedKB</Name>
<Value>$Config/ExcludedKB$</Value>
</Parameter>
<Parameter>
<Name>Format</Name>
<Value>$Config/Format$</Value>
</Parameter>
<Parameter>
<Name>ShowTop</Name>
<Value>$Config/ShowTop$</Value>
</Parameter>
<Parameter>
<Name>LastHours</Name>
<Value>$Config/LastHours$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Probe"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>Windows!Microsoft.Windows.SerializedObjectData</OutputType>
<TriggerOnly>true</TriggerOnly>
</ProbeActionModuleType>