I want to export information about all our Hotfixes in our WSUS Server, to share with the community as it’s sometimes hard to find up to date info of which hotfixes to apply in an environment.
Here is a quick and dirty script. No, scratch that, it’s not quick in any way but very dirty. The problem is that the WSUS Database does not contain the Description or Title of a Hotfix, so it’s not possible to export that info. Thus, I’ve to use a scripted Internet Explorer, to navigate to the URL of each Hotfix and grab the Title. Which makes the process veeeeeeery slow but I’ve been unable to come up with any better solution than that.
This is how the output looks like:
And here is the full script, I will be really grateful if you share any changes you do as I’m sure there is a lot of ways to improve this script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# Load WSUS Stuff [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null if (!$wsus) { $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer(); } $updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope; $updateScope.UpdateApprovalActions = [Microsoft.UpdateServices.Administration.UpdateApprovalActions]::Install $computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope; [DateTime]::UtcNow.ToShortDateString() Function Get-Title($Web) { if ($Web -ne "https://go.microsoft.com/fwlink/?LinkId=133041") { $ie = new-object -com internetexplorer.application $ie.navigate($Web) while ($ie.busy -eq $true) { Start-Sleep -Milliseconds 600 } $BaseResponse = $ie.LocationURL if ($BaseResponse -ne $Web) { $Title = "Site may no longer be available. Site redirection occurred - new target $BaseResponse." } else { while (($ie.LocationName -eq "Microsoft Support") -or ($ie.LocationName -eq $Web)) { $ie.refresh(); while ($ie.busy -eq $true) { Start-Sleep -Milliseconds 600 } } $Title = $ie.LocationName.tostring() $ie.Quit() } } Else { $Title = "Invalid URL - Original KB was for IE 9.0..." } start-sleep -Seconds 1 return $Title.ToString() }#end function Get-Title Function Get-KB($HotfixList){ $TestList = @() foreach ($Hotfix in $HotfixList) { $KB = $null write-Host "Processing Hotfix $Hotfix Please Wait." $KB = $wsus.GetUpdates($updateScope) | where { ( $_.KnowledgebaseArticles -match "$Hotfix" )} if ($KB -ne $null) { $summary = $KB.GetSummary($computerscope); $neededCount = ($summary.InstalledPendingRebootCount + $summary.NotInstalledCount) $CreationDate = $KB.CreationDate $InstalledCount = $Summary.InstalledCount.ToString() $MUUri = "http://catalog.update.microsoft.com/v7/site/Search.aspx?q="+$KB.KnowledgebaseArticles $KBUri = $KB.AdditionalInformationUrls -replace 'http:','https:' -replace 'microsoft.com/kb/','microsoft.com/en-us/kb/' $KBTitle = Get-Title ($KB.AdditionalInformationUrls -replace "http:", "https:" -replace "microsoft.com/kb/", "microsoft.com/en-us/kb/") $KBsummary = New-Object -TypeName System.Object Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name KB -Value $Hotfix Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name KBTitle -Value $KBTitle Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name KBUri -Value "$KBUri" Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name MUUri -Value $MUUri Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name ReleaseDate -Value $CreationDate.ToShortDateString() Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name ProductTitles -Value $KB.ProductTitles Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name ProductFamilyTitles -Value $KB.ProductFamilyTitles Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name UnknownCount -Value $summary.UnknownCount Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name NotApplicableCount -Value $summary.NotApplicableCount Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name DownloadedCount -Value $summary.DownloadedCount Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name InstalledCount -Value $summary.InstalledCount Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name InstalledPendingRebootCount -Value $summary.InstalledPendingRebootCount Add-Member -InputObject $KBsummary -MemberType NoteProperty -Name FailedCount -Value $summary.FailedCount $TestList += $KBsummary } else{ Write-Host "$Hotfix not found" } } return $TestList } $allhotfixes = $wsus.GetUpdates($updateScope) | where { ( $_.UpdateClassificationTitle -match "Hotfix" ) -and ( $_.IsDeclined -eq $false ) -and ( $_.IsLatestRevision -eq $true) -and ( $_.IsSuperseded -eq $false) -and ( $_.ProductTitles -like "*2012 R2*") } $Details = Get-KB $allhotfixes.KnowledgebaseArticles $Details | Export-Clixml -Path c:\temp\details.xml $Details |