win_updates: Add post search category matching to support product matching (#45708)
* win_update: Add post search category matching to support product matching * win_updates: Return categories of each update * win_updates: Documentation fix-up * win_updates: Adjusted documentation to reflect regex vs sub-string match of post-cat strings * win_updates: Sped up post-category checking * win_updates: Updated documentation to suggest querying post-category strings * win_updates: Simplified saving and checking post-categories * fixed some issues and added filtered categories to return value * win_updates: Moved all category matching to occur after initial search * win_updates: Adjustments to satisfy PowerShell lint checks * win_updates: Dropped category validation from action plugin * win_updates: Documentation updates * win_updates: Fixed plugin unit tests
This commit is contained in:
parent
8245441b2e
commit
a2f3f16930
6 changed files with 113 additions and 149 deletions
2
changelogs/fragments/win_updates-post-categories.yaml
Normal file
2
changelogs/fragments/win_updates-post-categories.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- win_updates - Reworked filtering updates based on category classification - https://github.com/ansible/ansible/issues/45476
|
|
@ -17,31 +17,27 @@ $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "insta
|
||||||
$blacklist = Get-AnsibleParam -obj $params -name "blacklist" -type "list"
|
$blacklist = Get-AnsibleParam -obj $params -name "blacklist" -type "list"
|
||||||
$whitelist = Get-AnsibleParam -obj $params -name "whitelist" -type "list"
|
$whitelist = Get-AnsibleParam -obj $params -name "whitelist" -type "list"
|
||||||
|
|
||||||
Function Get-CategoryGuid($category_name) {
|
# For backwards compatibility
|
||||||
$guid = switch -exact ($category_name) {
|
Function Get-CategoryMapping ($category_name) {
|
||||||
"Application" {"5C9376AB-8CE6-464A-B136-22113DD69801"}
|
switch -exact ($category_name) {
|
||||||
"Connectors" {"434DE588-ED14-48F5-8EED-A15E09A991F6"}
|
"CriticalUpdates" {return "Critical Updates"}
|
||||||
"CriticalUpdates" {"E6CF1350-C01B-414D-A61F-263D14D133B4"}
|
"DefinitionUpdates" {return "Definition Updates"}
|
||||||
"DefinitionUpdates" {"E0789628-CE08-4437-BE74-2495B842F43B"}
|
"DeveloperKits" {return "Developer Kits"}
|
||||||
"DeveloperKits" {"E140075D-8433-45C3-AD87-E72345B36078"}
|
"FeaturePacks" {return "Feature Packs"}
|
||||||
"FeaturePacks" {"B54E7D24-7ADD-428F-8B75-90A396FA584F"}
|
"SecurityUpdates" {return "Security Updates"}
|
||||||
"Guidance" {"9511D615-35B2-47BB-927F-F73D8E9260BB"}
|
"ServicePacks" {return "Service Packs"}
|
||||||
"SecurityUpdates" {"0FA1201D-4330-4FA8-8AE9-B877473B6441"}
|
"UpdateRollups" {return "Update Rollups"}
|
||||||
"ServicePacks" {"68C5B0A3-D1A6-4553-AE49-01D3A7827828"}
|
default {return $category_name}
|
||||||
"Tools" {"B4832BD8-E735-4761-8DAF-37F882276DAB"}
|
|
||||||
"UpdateRollups" {"28BC880E-0592-4CBF-8F95-C79B17911D5F"}
|
|
||||||
"Updates" {"CD5FFD1E-E932-4E3A-BF74-18BF0B1BBD83"}
|
|
||||||
default { Fail-Json -message "Unknown category_name $category_name, must be one of (Application,Connectors,CriticalUpdates,DefinitionUpdates,DeveloperKits,FeaturePacks,Guidance,SecurityUpdates,ServicePacks,Tools,UpdateRollups,Updates)" }
|
|
||||||
}
|
}
|
||||||
return $guid
|
|
||||||
}
|
}
|
||||||
$category_guids = $category_names | ForEach-Object { Get-CategoryGuid -category_name $_ }
|
|
||||||
|
$category_names = $category_names | ForEach-Object { Get-CategoryMapping -category_name $_ }
|
||||||
|
|
||||||
$common_functions = {
|
$common_functions = {
|
||||||
Function Write-DebugLog($msg) {
|
Function Write-DebugLog($msg) {
|
||||||
$date_str = Get-Date -Format u
|
$date_str = Get-Date -Format u
|
||||||
$msg = "$date_str $msg"
|
$msg = "$date_str $msg"
|
||||||
|
|
||||||
Write-Debug -Message $msg
|
Write-Debug -Message $msg
|
||||||
if ($log_path -ne $null -and (-not $check_mode)) {
|
if ($log_path -ne $null -and (-not $check_mode)) {
|
||||||
Add-Content -Path $log_path -Value $msg
|
Add-Content -Path $log_path -Value $msg
|
||||||
|
@ -59,7 +55,7 @@ $update_script_block = {
|
||||||
|
|
||||||
Function Start-Updates {
|
Function Start-Updates {
|
||||||
Param(
|
Param(
|
||||||
$category_guids,
|
$category_names,
|
||||||
$log_path,
|
$log_path,
|
||||||
$state,
|
$state,
|
||||||
$blacklist,
|
$blacklist,
|
||||||
|
@ -71,7 +67,7 @@ $update_script_block = {
|
||||||
updates = @{}
|
updates = @{}
|
||||||
filtered_updates = @{}
|
filtered_updates = @{}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating Windows Update session..."
|
Write-DebugLog -msg "Creating Windows Update session..."
|
||||||
try {
|
try {
|
||||||
$session = New-Object -ComObject Microsoft.Update.Session
|
$session = New-Object -ComObject Microsoft.Update.Session
|
||||||
|
@ -80,7 +76,7 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create Microsoft.Update.Session COM object: $($_.Exception.Message)"
|
$result.msg = "Failed to create Microsoft.Update.Session COM object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Create Windows Update searcher..."
|
Write-DebugLog -msg "Create Windows Update searcher..."
|
||||||
try {
|
try {
|
||||||
$searcher = $session.CreateUpdateSearcher()
|
$searcher = $session.CreateUpdateSearcher()
|
||||||
|
@ -89,24 +85,17 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create Windows Update search from session: $($_.Exception.Message)"
|
$result.msg = "Failed to create Windows Update search from session: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
# OR is only allowed at the top-level, so we have to repeat base criteria inside
|
Write-DebugLog -msg "Searching for updates to install"
|
||||||
# FUTURE: change this to client-side filtered?
|
|
||||||
$criteria_base = "IsInstalled = 0"
|
|
||||||
$criteria_list = $category_guids | ForEach-Object { "($criteria_base AND CategoryIds contains '$_') " }
|
|
||||||
$criteria = [string]::Join(" OR", $criteria_list)
|
|
||||||
Write-DebugLog -msg "Search criteria: $criteria"
|
|
||||||
|
|
||||||
Write-DebugLog -msg "Searching for updates to install in category Ids $category_guids..."
|
|
||||||
try {
|
try {
|
||||||
$search_result = $searcher.Search($criteria)
|
$search_result = $searcher.Search("IsInstalled = 0")
|
||||||
} catch {
|
} catch {
|
||||||
$result.failed = $true
|
$result.failed = $true
|
||||||
$result.msg = "Failed to search for updates with criteria '$criteria': $($_.Exception.Message)"
|
$result.msg = "Failed to search for updates: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
Write-DebugLog -msg "Found $($search_result.Updates.Count) updates"
|
Write-DebugLog -msg "Found $($search_result.Updates.Count) updates"
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating update collection..."
|
Write-DebugLog -msg "Creating update collection..."
|
||||||
try {
|
try {
|
||||||
$updates_to_install = New-Object -ComObject Microsoft.Update.UpdateColl
|
$updates_to_install = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||||
|
@ -115,7 +104,7 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create update collection object: $($_.Exception.Message)"
|
$result.msg = "Failed to create update collection object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($update in $search_result.Updates) {
|
foreach ($update in $search_result.Updates) {
|
||||||
$update_info = @{
|
$update_info = @{
|
||||||
title = $update.Title
|
title = $update.Title
|
||||||
|
@ -123,10 +112,10 @@ $update_script_block = {
|
||||||
kb = $update.KBArticleIDs
|
kb = $update.KBArticleIDs
|
||||||
id = $update.Identity.UpdateId
|
id = $update.Identity.UpdateId
|
||||||
installed = $false
|
installed = $false
|
||||||
|
categories = ($update.Categories | ForEach-Object { $_.Name })
|
||||||
}
|
}
|
||||||
|
|
||||||
# validate update again blacklist/whitelist
|
# validate update again blacklist/whitelist/post_category_names/hidden
|
||||||
$skipped = $false
|
|
||||||
$whitelist_match = $false
|
$whitelist_match = $false
|
||||||
foreach ($whitelist_entry in $whitelist) {
|
foreach ($whitelist_entry in $whitelist) {
|
||||||
if ($update_info.title -imatch $whitelist_entry) {
|
if ($update_info.title -imatch $whitelist_entry) {
|
||||||
|
@ -142,33 +131,52 @@ $update_script_block = {
|
||||||
}
|
}
|
||||||
if ($whitelist.Length -gt 0 -and -not $whitelist_match) {
|
if ($whitelist.Length -gt 0 -and -not $whitelist_match) {
|
||||||
Write-DebugLog -msg "Skipping update $($update_info.id) - $($update_info.title) as it was not found in the whitelist"
|
Write-DebugLog -msg "Skipping update $($update_info.id) - $($update_info.title) as it was not found in the whitelist"
|
||||||
$skipped = $true
|
$update_info.filtered_reason = "whitelist"
|
||||||
|
$result.filtered_updates[$update_info.id] = $update_info
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($kb in $update_info.kb) {
|
$blacklist_match = $false
|
||||||
if ("KB$kb" -imatch $blacklist_entry) {
|
foreach ($blacklist_entry in $blacklist) {
|
||||||
$kb_match = $true
|
if ($update_info.title -imatch $blacklist_entry) {
|
||||||
|
$blacklist_match = $true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
foreach ($blacklist_entry in $blacklist) {
|
foreach ($kb in $update_info.kb) {
|
||||||
$kb_match = $false
|
if ("KB$kb" -imatch $blacklist_entry) {
|
||||||
foreach ($kb in $update_info.kb) {
|
$blacklist_match = $true
|
||||||
if ("KB$kb" -imatch $blacklist_entry) {
|
|
||||||
$kb_match = $true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($kb_match -or $update_info.title -imatch $blacklist_entry) {
|
|
||||||
Write-DebugLog -msg "Skipping update $($update_info.id) - $($update_info.title) as it was found in the blacklist"
|
|
||||||
$skipped = $true
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($skipped) {
|
if ($blacklist_match) {
|
||||||
|
Write-DebugLog -msg "Skipping update $($update_info.id) - $($update_info.title) as it was found in the blacklist"
|
||||||
|
$update_info.filtered_reason = "blacklist"
|
||||||
$result.filtered_updates[$update_info.id] = $update_info
|
$result.filtered_updates[$update_info.id] = $update_info
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($update.IsHidden) {
|
||||||
|
Write-DebugLog -msg "Skipping update $($update_info.title) as it was hidden"
|
||||||
|
$update_info.filtered_reason = "skip_hidden"
|
||||||
|
$result.filtered_updates[$update_info.id] = $update_info
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$category_match = $false
|
||||||
|
foreach ($match_cat in $category_names) {
|
||||||
|
if ($update_info.categories -ieq $match_cat) {
|
||||||
|
$category_match = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($category_names.Length -gt 0 -and -not $category_match) {
|
||||||
|
Write-DebugLog -msg "Skipping update $($update_info.id) - $($update_info.title) as it was not found in the category names filter"
|
||||||
|
$update_info.filtered_reason = "category_names"
|
||||||
|
$result.filtered_updates[$update_info.id] = $update_info
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (-not $update.EulaAccepted) {
|
if (-not $update.EulaAccepted) {
|
||||||
Write-DebugLog -msg "Accepting EULA for $($update_info.id)"
|
Write-DebugLog -msg "Accepting EULA for $($update_info.id)"
|
||||||
try {
|
try {
|
||||||
|
@ -179,36 +187,31 @@ $update_script_block = {
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($update.IsHidden) {
|
|
||||||
Write-DebugLog -msg "Skipping hidden update $($update_info.title)"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-DebugLog -msg "Adding update $($update_info.id) - $($update_info.title)"
|
Write-DebugLog -msg "Adding update $($update_info.id) - $($update_info.title)"
|
||||||
$updates_to_install.Add($update) > $null
|
$updates_to_install.Add($update) > $null
|
||||||
|
|
||||||
$result.updates[$update_info.id] = $update_info
|
$result.updates[$update_info.id] = $update_info
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Calculating pre-install reboot requirement..."
|
Write-DebugLog -msg "Calculating pre-install reboot requirement..."
|
||||||
|
|
||||||
# calculate this early for check mode, and to see if we should allow updates to continue
|
# calculate this early for check mode, and to see if we should allow updates to continue
|
||||||
$result.reboot_required = (New-Object -ComObject Microsoft.Update.SystemInfo).RebootRequired
|
$result.reboot_required = (New-Object -ComObject Microsoft.Update.SystemInfo).RebootRequired
|
||||||
$result.found_update_count = $updates_to_install.Count
|
$result.found_update_count = $updates_to_install.Count
|
||||||
$result.installed_update_count = 0
|
$result.installed_update_count = 0
|
||||||
|
|
||||||
# Early exit of check mode/state=searched as it cannot do more after this
|
# Early exit of check mode/state=searched as it cannot do more after this
|
||||||
if ($check_mode -or $state -eq "searched") {
|
if ($check_mode -or $state -eq "searched") {
|
||||||
Write-DebugLog -msg "Check mode: exiting..."
|
Write-DebugLog -msg "Check mode: exiting..."
|
||||||
Write-DebugLog -msg "Return value:`r`n$(ConvertTo-Json -InputObject $result -Depth 99)"
|
Write-DebugLog -msg "Return value:`r`n$(ConvertTo-Json -InputObject $result -Depth 99)"
|
||||||
|
|
||||||
if ($updates_to_install.Count -gt 0 -and ($state -ne "searched")) {
|
if ($updates_to_install.Count -gt 0 -and ($state -ne "searched")) {
|
||||||
$result.changed = $true
|
$result.changed = $true
|
||||||
}
|
}
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($updates_to_install.Count -gt 0) {
|
if ($updates_to_install.Count -gt 0) {
|
||||||
if ($result.reboot_required) {
|
if ($result.reboot_required) {
|
||||||
Write-DebugLog -msg "FATAL: A reboot is required before more updates can be installed"
|
Write-DebugLog -msg "FATAL: A reboot is required before more updates can be installed"
|
||||||
|
@ -221,7 +224,7 @@ $update_script_block = {
|
||||||
# no updates to install exit here
|
# no updates to install exit here
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Downloading updates..."
|
Write-DebugLog -msg "Downloading updates..."
|
||||||
$update_index = 1
|
$update_index = 1
|
||||||
foreach ($update in $updates_to_install) {
|
foreach ($update in $updates_to_install) {
|
||||||
|
@ -231,7 +234,7 @@ $update_script_block = {
|
||||||
$update_index++
|
$update_index++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating downloader object..."
|
Write-DebugLog -msg "Creating downloader object..."
|
||||||
try {
|
try {
|
||||||
$dl = $session.CreateUpdateDownloader()
|
$dl = $session.CreateUpdateDownloader()
|
||||||
|
@ -240,7 +243,7 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create downloader object: $($_.Exception.Message)"
|
$result.msg = "Failed to create downloader object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating download collection..."
|
Write-DebugLog -msg "Creating download collection..."
|
||||||
try {
|
try {
|
||||||
$dl.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
$dl.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||||
|
@ -249,10 +252,10 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create download collection object: $($_.Exception.Message)"
|
$result.msg = "Failed to create download collection object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Adding update $update_number $($update.Identity.UpdateId)"
|
Write-DebugLog -msg "Adding update $update_number $($update.Identity.UpdateId)"
|
||||||
$dl.Updates.Add($update) > $null
|
$dl.Updates.Add($update) > $null
|
||||||
|
|
||||||
Write-DebugLog -msg "Downloading $update_number $($update.Identity.UpdateId)"
|
Write-DebugLog -msg "Downloading $update_number $($update.Identity.UpdateId)"
|
||||||
try {
|
try {
|
||||||
$download_result = $dl.Download()
|
$download_result = $dl.Download()
|
||||||
|
@ -261,7 +264,7 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to download update $update_number $($update.Identity.UpdateId) - $($update.Title): $($_.Exception.Message)"
|
$result.msg = "Failed to download update $update_number $($update.Identity.UpdateId) - $($update.Title): $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Download result code for $update_number $($update.Identity.UpdateId) = $($download_result.ResultCode)"
|
Write-DebugLog -msg "Download result code for $update_number $($update.Identity.UpdateId) = $($download_result.ResultCode)"
|
||||||
# FUTURE: configurable download retry
|
# FUTURE: configurable download retry
|
||||||
if ($download_result.ResultCode -ne 2) { # OperationResultCode orcSucceeded
|
if ($download_result.ResultCode -ne 2) { # OperationResultCode orcSucceeded
|
||||||
|
@ -269,14 +272,14 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to download update $update_number $($update.Identity.UpdateId) - $($update.Title): Download Result $($download_result.ResultCode)"
|
$result.msg = "Failed to download update $update_number $($update.Identity.UpdateId) - $($update.Title): Download Result $($download_result.ResultCode)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
$result.changed = $true
|
$result.changed = $true
|
||||||
$update_index++
|
$update_index++
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Installing updates..."
|
Write-DebugLog -msg "Installing updates..."
|
||||||
|
|
||||||
# install as a batch so the reboot manager will suppress intermediate reboots
|
# install as a batch so the reboot manager will suppress intermediate reboots
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating installer object..."
|
Write-DebugLog -msg "Creating installer object..."
|
||||||
try {
|
try {
|
||||||
$installer = $session.CreateUpdateInstaller()
|
$installer = $session.CreateUpdateInstaller()
|
||||||
|
@ -285,7 +288,7 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create Update Installer object: $($_.Exception.Message)"
|
$result.msg = "Failed to create Update Installer object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Creating install collection..."
|
Write-DebugLog -msg "Creating install collection..."
|
||||||
try {
|
try {
|
||||||
$installer.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
$installer.Updates = New-Object -ComObject Microsoft.Update.UpdateColl
|
||||||
|
@ -294,12 +297,12 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to create Update Collection object: $($_.Exception.Message)"
|
$result.msg = "Failed to create Update Collection object: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($update in $updates_to_install) {
|
foreach ($update in $updates_to_install) {
|
||||||
Write-DebugLog -msg "Adding update $($update.Identity.UpdateID)"
|
Write-DebugLog -msg "Adding update $($update.Identity.UpdateID)"
|
||||||
$installer.Updates.Add($update) > $null
|
$installer.Updates.Add($update) > $null
|
||||||
}
|
}
|
||||||
|
|
||||||
# FUTURE: use BeginInstall w/ progress reporting so we can at least log intermediate install results
|
# FUTURE: use BeginInstall w/ progress reporting so we can at least log intermediate install results
|
||||||
try {
|
try {
|
||||||
$install_result = $installer.Install()
|
$install_result = $installer.Install()
|
||||||
|
@ -308,10 +311,10 @@ $update_script_block = {
|
||||||
$result.msg = "Failed to install update from Update Collection: $($_.Exception.Message)"
|
$result.msg = "Failed to install update from Update Collection: $($_.Exception.Message)"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
$update_success_count = 0
|
$update_success_count = 0
|
||||||
$update_fail_count = 0
|
$update_fail_count = 0
|
||||||
|
|
||||||
# WU result API requires us to index in to get the install results
|
# WU result API requires us to index in to get the install results
|
||||||
$update_index = 0
|
$update_index = 0
|
||||||
foreach ($update in $updates_to_install) {
|
foreach ($update in $updates_to_install) {
|
||||||
|
@ -325,9 +328,9 @@ $update_script_block = {
|
||||||
}
|
}
|
||||||
$update_resultcode = $update_result.ResultCode
|
$update_resultcode = $update_result.ResultCode
|
||||||
$update_hresult = $update_result.HResult
|
$update_hresult = $update_result.HResult
|
||||||
|
|
||||||
$update_index++
|
$update_index++
|
||||||
|
|
||||||
$update_dict = $result.updates[$update.Identity.UpdateID]
|
$update_dict = $result.updates[$update.Identity.UpdateID]
|
||||||
if ($update_resultcode -eq 2) { # OperationResultCode orcSucceeded
|
if ($update_resultcode -eq 2) { # OperationResultCode orcSucceeded
|
||||||
$update_success_count++
|
$update_success_count++
|
||||||
|
@ -341,18 +344,18 @@ $update_script_block = {
|
||||||
Write-DebugLog -msg "Update $update_number $($update.Identity.UpdateID) failed, resultcode: $update_resultcode, hresult: $update_hresult"
|
Write-DebugLog -msg "Update $update_number $($update.Identity.UpdateID) failed, resultcode: $update_resultcode, hresult: $update_hresult"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Performing post-install reboot requirement check..."
|
Write-DebugLog -msg "Performing post-install reboot requirement check..."
|
||||||
$result.reboot_required = (New-Object -ComObject Microsoft.Update.SystemInfo).RebootRequired
|
$result.reboot_required = (New-Object -ComObject Microsoft.Update.SystemInfo).RebootRequired
|
||||||
$result.installed_update_count = $update_success_count
|
$result.installed_update_count = $update_success_count
|
||||||
$result.failed_update_count = $update_fail_count
|
$result.failed_update_count = $update_fail_count
|
||||||
|
|
||||||
if ($update_fail_count -gt 0) {
|
if ($update_fail_count -gt 0) {
|
||||||
$result.failed = $true
|
$result.failed = $true
|
||||||
$result.msg = "Failed to install one or more updates"
|
$result.msg = "Failed to install one or more updates"
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DebugLog -msg "Return value:`r`n$(ConvertTo-Json -InputObject $result -Depth 99)"
|
Write-DebugLog -msg "Return value:`r`n$(ConvertTo-Json -InputObject $result -Depth 99)"
|
||||||
|
|
||||||
return $result
|
return $result
|
||||||
|
@ -389,7 +392,7 @@ Function Start-Natively($common_functions, $script) {
|
||||||
# add the update script block and required parameters
|
# add the update script block and required parameters
|
||||||
$ps_pipeline.AddStatement().AddScript($script) > $null
|
$ps_pipeline.AddStatement().AddScript($script) > $null
|
||||||
$ps_pipeline.AddParameter("arguments", @{
|
$ps_pipeline.AddParameter("arguments", @{
|
||||||
category_guids = $category_guids
|
category_names = $category_names
|
||||||
log_path = $log_path
|
log_path = $log_path
|
||||||
state = $state
|
state = $state
|
||||||
blacklist = $blacklist
|
blacklist = $blacklist
|
||||||
|
@ -450,7 +453,7 @@ Function Start-AsScheduledTask($common_functions, $script) {
|
||||||
Name = $job_name
|
Name = $job_name
|
||||||
ArgumentList = @(
|
ArgumentList = @(
|
||||||
@{
|
@{
|
||||||
category_guids = $category_guids
|
category_names = $category_names
|
||||||
log_path = $log_path
|
log_path = $log_path
|
||||||
state = $state
|
state = $state
|
||||||
blacklist = $blacklist
|
blacklist = $blacklist
|
||||||
|
@ -499,7 +502,7 @@ Function Start-AsScheduledTask($common_functions, $script) {
|
||||||
Write-DebugLog -msg "Waiting for job output to populate..."
|
Write-DebugLog -msg "Waiting for job output to populate..."
|
||||||
Start-Sleep -Milliseconds 500
|
Start-Sleep -Milliseconds 500
|
||||||
}
|
}
|
||||||
|
|
||||||
# NB: fallthru on both timeout and success
|
# NB: fallthru on both timeout and success
|
||||||
$ret = @{
|
$ret = @{
|
||||||
ErrorOutput = $job.Error
|
ErrorOutput = $job.Error
|
||||||
|
@ -553,3 +556,4 @@ if ($wua_available) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Exit-Json -obj $result
|
Exit-Json -obj $result
|
||||||
|
|
||||||
|
|
|
@ -33,22 +33,14 @@ options:
|
||||||
version_added: '2.5'
|
version_added: '2.5'
|
||||||
category_names:
|
category_names:
|
||||||
description:
|
description:
|
||||||
- A scalar or list of categories to install updates from
|
- A scalar or list of categories to install updates from. To get the list
|
||||||
|
of categories, run the module with C(state=searched). The category must
|
||||||
|
be the full category string, but is case insensitive.
|
||||||
|
- Some possible categories are Application, Connectors, Critical Updates,
|
||||||
|
Definition Updates, Developer Kits, Feature Packs, Guidance, Security
|
||||||
|
Updates, Service Packs, Tools, Update Rollups and Updates.
|
||||||
type: list
|
type: list
|
||||||
default: [ CriticalUpdates, SecurityUpdates, UpdateRollups ]
|
default: [ CriticalUpdates, SecurityUpdates, UpdateRollups ]
|
||||||
choices:
|
|
||||||
- Application
|
|
||||||
- Connectors
|
|
||||||
- CriticalUpdates
|
|
||||||
- DefinitionUpdates
|
|
||||||
- DeveloperKits
|
|
||||||
- FeaturePacks
|
|
||||||
- Guidance
|
|
||||||
- SecurityUpdates
|
|
||||||
- ServicePacks
|
|
||||||
- Tools
|
|
||||||
- UpdateRollups
|
|
||||||
- Updates
|
|
||||||
reboot:
|
reboot:
|
||||||
description:
|
description:
|
||||||
- Ansible will automatically reboot the remote host if it is required
|
- Ansible will automatically reboot the remote host if it is required
|
||||||
|
@ -191,6 +183,11 @@ updates:
|
||||||
returned: always
|
returned: always
|
||||||
type: boolean
|
type: boolean
|
||||||
sample: True
|
sample: True
|
||||||
|
categories:
|
||||||
|
description: A list of category strings for this update
|
||||||
|
returned: always
|
||||||
|
type: list of strings
|
||||||
|
sample: [ 'Critical Updates', 'Windows Server 2012 R2' ]
|
||||||
failure_hresult_code:
|
failure_hresult_code:
|
||||||
description: The HRESULT code from a failed update
|
description: The HRESULT code from a failed update
|
||||||
returned: on install failure
|
returned: on install failure
|
||||||
|
@ -199,12 +196,17 @@ updates:
|
||||||
|
|
||||||
filtered_updates:
|
filtered_updates:
|
||||||
description: List of updates that were found but were filtered based on
|
description: List of updates that were found but were filtered based on
|
||||||
I(blacklist) or I(whitelist). The return value is in the same form as
|
I(blacklist), I(whitelist) or I(category_names). The return value is in
|
||||||
I(updates).
|
the same form as I(updates), along with I(filtered_reason).
|
||||||
returned: success
|
returned: success
|
||||||
type: complex
|
type: complex
|
||||||
sample: see the updates return value
|
sample: see the updates return value
|
||||||
contains: {}
|
contains:
|
||||||
|
filtered_reason:
|
||||||
|
description: The reason why this update was filtered
|
||||||
|
returned: always
|
||||||
|
type: string
|
||||||
|
sample: 'skip_hidden'
|
||||||
|
|
||||||
found_update_count:
|
found_update_count:
|
||||||
description: The number of updates found needing to be applied
|
description: The number of updates found needing to be applied
|
||||||
|
|
|
@ -20,26 +20,6 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
DEFAULT_REBOOT_TIMEOUT = 1200
|
DEFAULT_REBOOT_TIMEOUT = 1200
|
||||||
|
|
||||||
def _validate_categories(self, category_names):
|
|
||||||
valid_categories = [
|
|
||||||
'Application',
|
|
||||||
'Connectors',
|
|
||||||
'CriticalUpdates',
|
|
||||||
'DefinitionUpdates',
|
|
||||||
'DeveloperKits',
|
|
||||||
'FeaturePacks',
|
|
||||||
'Guidance',
|
|
||||||
'SecurityUpdates',
|
|
||||||
'ServicePacks',
|
|
||||||
'Tools',
|
|
||||||
'UpdateRollups',
|
|
||||||
'Updates'
|
|
||||||
]
|
|
||||||
for name in category_names:
|
|
||||||
if name not in valid_categories:
|
|
||||||
raise AnsibleError("Unknown category_name %s, must be one of "
|
|
||||||
"(%s)" % (name, ','.join(valid_categories)))
|
|
||||||
|
|
||||||
def _run_win_updates(self, module_args, task_vars, use_task):
|
def _run_win_updates(self, module_args, task_vars, use_task):
|
||||||
display.vvv("win_updates: running win_updates module")
|
display.vvv("win_updates: running win_updates module")
|
||||||
wrap_async = self._task.async_val
|
wrap_async = self._task.async_val
|
||||||
|
@ -172,14 +152,6 @@ class ActionModule(ActionBase):
|
||||||
use_task = boolean(self._task.args.get('use_scheduled_task', False),
|
use_task = boolean(self._task.args.get('use_scheduled_task', False),
|
||||||
strict=False)
|
strict=False)
|
||||||
|
|
||||||
# Validate the options
|
|
||||||
try:
|
|
||||||
self._validate_categories(category_names)
|
|
||||||
except AnsibleError as exc:
|
|
||||||
result['failed'] = True
|
|
||||||
result['msg'] = to_text(exc)
|
|
||||||
return result
|
|
||||||
|
|
||||||
if state not in ['installed', 'searched']:
|
if state not in ['installed', 'searched']:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = "state must be either installed or searched"
|
result['msg'] = "state must be either installed or searched"
|
||||||
|
|
|
@ -5,14 +5,6 @@
|
||||||
register: invalid_state
|
register: invalid_state
|
||||||
failed_when: invalid_state.msg != 'state must be either installed or searched'
|
failed_when: invalid_state.msg != 'state must be either installed or searched'
|
||||||
|
|
||||||
- name: expect failure with invalid category name
|
|
||||||
win_updates:
|
|
||||||
state: searched
|
|
||||||
category_names:
|
|
||||||
- Invalid
|
|
||||||
register: invalid_category_name
|
|
||||||
failed_when: invalid_category_name.msg != 'Unknown category_name Invalid, must be one of (Application,Connectors,CriticalUpdates,DefinitionUpdates,DeveloperKits,FeaturePacks,Guidance,SecurityUpdates,ServicePacks,Tools,UpdateRollups,Updates)'
|
|
||||||
|
|
||||||
- name: ensure log file not present before tests
|
- name: ensure log file not present before tests
|
||||||
win_file:
|
win_file:
|
||||||
path: '{{win_updates_dir}}/update.log'
|
path: '{{win_updates_dir}}/update.log'
|
||||||
|
|
|
@ -16,14 +16,6 @@ from ansible.playbook.task import Task
|
||||||
class TestWinUpdatesActionPlugin(object):
|
class TestWinUpdatesActionPlugin(object):
|
||||||
|
|
||||||
INVALID_OPTIONS = (
|
INVALID_OPTIONS = (
|
||||||
(
|
|
||||||
{"category_names": ["fake category"]},
|
|
||||||
False,
|
|
||||||
"Unknown category_name fake category, must be one of (Application,"
|
|
||||||
"Connectors,CriticalUpdates,DefinitionUpdates,DeveloperKits,"
|
|
||||||
"FeaturePacks,Guidance,SecurityUpdates,ServicePacks,Tools,"
|
|
||||||
"UpdateRollups,Updates)"
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
{"state": "invalid"},
|
{"state": "invalid"},
|
||||||
False,
|
False,
|
||||||
|
|
Loading…
Reference in a new issue