From 4d2090148e931f4f766e12a489f7870b42e3eb8a Mon Sep 17 00:00:00 2001 From: freedbygrace Date: Mon, 9 Sep 2024 12:48:35 -0400 Subject: [PATCH] Add files via upload --- Get-MicrosoftUpdateHistory.ps1 | 446 +++++++++++++++++++++++++++++++++ 1 file changed, 446 insertions(+) create mode 100644 Get-MicrosoftUpdateHistory.ps1 diff --git a/Get-MicrosoftUpdateHistory.ps1 b/Get-MicrosoftUpdateHistory.ps1 new file mode 100644 index 0000000..320a823 --- /dev/null +++ b/Get-MicrosoftUpdateHistory.ps1 @@ -0,0 +1,446 @@ +## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx + +#region Function Get-MicrosoftUpdateHistory +Function Get-MicrosoftUpdateHistory + { + <# + .SYNOPSIS + Gets the list of installed updates + + .DESCRIPTION + Slightly more detailed description of what your function does + + .EXAMPLE + Get-MicrosoftUpdateHistory + + .EXAMPLE + Get-MicrosoftUpdateHistory | Group-Object -Property @('UpdateID') | Sort-Object -Property @('Count') -Descending + + .EXAMPLE + Get-MicrosoftUpdateHistory -Advanced + + .EXAMPLE + Get-MicrosoftUpdateHistory -Advanced | Group-Object -Property @('UpdateID') | Sort-Object -Property @('Count') -Descending + + .NOTES + Any useful tidbits + + .LINK + Place any useful link here where your function or cmdlet can be referenced + #> + + [CmdletBinding(ConfirmImpact = 'Low', DefaultParameterSetName = '__AllParameterSets', HelpURI = '', SupportsShouldProcess = $True, PositionalBinding = $True)] + + Param + ( + [Parameter(Mandatory=$False)] + [Switch]$Advanced, + + [Parameter(Mandatory=$False)] + [Switch]$ContinueOnError + ) + + Begin + { + Try + { + $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss tt' ###Monday, January 01, 2019 @ 10:15:34 AM### + [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)} + $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347### + [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)} + $DateFileFormat = 'yyyyMMdd' ###20190403### + [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)} + $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354### + [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)} + $TextInfo = (Get-Culture).TextInfo + $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $LoggingDetails.Add('LogMessage', $Null) + $LoggingDetails.Add('WarningMessage', $Null) + $LoggingDetails.Add('ErrorMessage', $Null) + $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters) + $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters) + + [ScriptBlock]$ErrorHandlingDefinition = { + $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $ErrorMessageList.Add('Message', $_.Exception.Message) + $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID) + $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName) + $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber) + $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine) + $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim()) + + ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator()) + { + $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)" + Write-Warning -Message ($LoggingDetails.ErrorMessage) + } + + Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False)) + { + {($_ -eq $True)} + { + Throw + } + } + } + + #Determine the date and time we executed the function + $FunctionStartTime = (Get-Date) + + [String]$CmdletName = $MyInvocation.MyCommand.Name + + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is beginning. Please Wait..." + Write-Verbose -Message $LogMessage + + #Define Default Action Preferences + $ErrorActionPreference = 'Stop' + + [String[]]$AvailableScriptParameters = (Get-Command -Name ($CmdletName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"} + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + [String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"} + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))" + Write-Verbose -Message $LogMessage + + #Create an object that will contain the functions output. + $OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + } + Catch + { + $ErrorHandlingDefinition.Invoke() + } + Finally + { + + } + } + + Process + { + Try + { + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the Microsoft update history. Please Wait..." + Write-Verbose -Message $LogMessage + + $MicrosoftUpdateSession = New-Object -ComObject 'Microsoft.Update.Session' + $MicrosoftUpdateSearcher = $MicrosoftUpdateSession.CreateUpdateSearcher() + $MicrosoftUpdateTotalHistoryCount = $MicrosoftUpdateSearcher.GetTotalHistoryCount() + $MicrosoftUpdateList = $MicrosoftUpdateSearcher.QueryHistory(0, $MicrosoftUpdateTotalHistoryCount) + + $MicrosoftUpdateLoopCounter = 1 + + $MicrosoftUpdateHashSet = New-Object -TypeName 'System.Collections.Generic.HashSet[String]' + + :MicrosoftUpdateLoop For ($MicrosoftUpdateListIndex = 0; $MicrosoftUpdateListIndex -lt $MicrosoftUpdateTotalHistoryCount; $MicrosoftUpdateListIndex++) + { + $MicrosoftUpdate = $MicrosoftUpdateList[$MicrosoftUpdateListIndex] + + $MicrosoftUpdatePropertyDictionary = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $MicrosoftUpdatePropertyDictionary.ArticleID = $Null + $MicrosoftUpdatePropertyDictionary.Title = $MicrosoftUpdate.Title + $MicrosoftUpdatePropertyDictionary.Description = $MicrosoftUpdate.Description -ireplace '(\s{2,})', ' ' + $MicrosoftUpdatePropertyDictionary.UpdateID = $MicrosoftUpdate.UpdateIdentity.UpdateID.ToUpper() + $MicrosoftUpdatePropertyDictionary.Revision = $MicrosoftUpdate.UpdateIdentity.RevisionNumber + $MicrosoftUpdatePropertyDictionary.Category = New-Object -TypeName 'System.Collections.Generic.List[String]' + $MicrosoftUpdatePropertyDictionary.UpdateType = New-Object -TypeName 'System.Collections.Generic.List[String]' + $MicrosoftUpdatePropertyDictionary.InstallationDate = $MicrosoftUpdate.Date + $MicrosoftUpdatePropertyDictionary.SupportURL = $MicrosoftUpdate.SupportURL + + $LogMessage = "Attempting to retrieve details for update $($MicrosoftUpdateLoopCounter) of $($MicrosoftUpdateTotalHistoryCount) - [Title: $($MicrosoftUpdatePropertyDictionary.Title)] [Update ID: $($MicrosoftUpdatePropertyDictionary.UpdateID)]. Please Wait..." + Write-Verbose -Message $LogMessage + + $ArticleIDExpressionEvaluation = [Regex]::Match($MicrosoftUpdate.Title, 'KB(\d+)') + + Switch ($ArticleIDExpressionEvaluation.Success) + { + {($_ -eq $True)} + { + Switch (([String]::IsNullOrEmpty($ArticleIDExpressionEvaluation.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($ArticleIDExpressionEvaluation.Value) -eq $False)) + { + {($_ -eq $True)} + { + $MicrosoftUpdatePropertyDictionary.ArticleID = $ArticleIDExpressionEvaluation.Value + } + } + } + } + + ForEach ($Category In $MicrosoftUpdate.Categories) + { + Switch (([String]::IsNullOrEmpty($Category.Type) -eq $False) -and ([String]::IsNullOrWhiteSpace($Category.Type) -eq $False)) + { + {($_ -eq $True)} + { + $MicrosoftUpdatePropertyDictionary.UpdateType.Add($Category.Type.Trim()) + } + } + + Switch (([String]::IsNullOrEmpty($Category.Name) -eq $False) -and ([String]::IsNullOrWhiteSpace($Category.Name) -eq $False)) + { + {($_ -eq $True)} + { + $MicrosoftUpdatePropertyDictionary.Category.Add($Category.Name.Trim()) + } + } + } + + $MicrosoftUpdatePropertyDictionary.UpdateType = $MicrosoftUpdatePropertyDictionary.UpdateType.ToArray() | Sort-Object -Unique + + $MicrosoftUpdatePropertyDictionary.Category = $MicrosoftUpdatePropertyDictionary.Category.ToArray() | Sort-Object -Unique + + $MicrosoftUpdatePropertyDictionary.OperationCode = $MicrosoftUpdate.Operation + + Switch ($MicrosoftUpdate.Operation) + { + {($_ -eq 1)} {$MicrosoftUpdatePropertyDictionary.Operation = 'Installation'} + {($_ -eq 2)} {$MicrosoftUpdatePropertyDictionary.Operation = 'Uninstallation'} + {($_ -eq 3)} {$MicrosoftUpdatePropertyDictionary.Operation = 'Other'} + Default {$MicrosoftUpdatePropertyDictionary.Operation = 'Unknown'} + } + + $MicrosoftUpdatePropertyDictionary.ResultCode = $MicrosoftUpdate.ResultCode + + Switch ($MicrosoftUpdate.ResultCode) + { + {($_ -eq 0)} {$MicrosoftUpdatePropertyDictionary.Result = 'Not Started'} + {($_ -eq 1)} {$MicrosoftUpdatePropertyDictionary.Result = 'In Progress'} + {($_ -eq 2)} {$MicrosoftUpdatePropertyDictionary.Result = 'Succeeded'} + {($_ -eq 3)} {$MicrosoftUpdatePropertyDictionary.Result = 'Succeeded With Errors'} + {($_ -eq 4)} {$MicrosoftUpdatePropertyDictionary.Result = 'Failed'} + {($_ -eq 5)} {$MicrosoftUpdatePropertyDictionary.Result = 'Aborted'} + Default {$MicrosoftUpdatePropertyDictionary.Result = 'Unknown'} + } + + $MicrosoftUpdatePropertyDictionary.Advanced = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + Switch ($Advanced.IsPresent) + { + {($_ -eq $True)} + { + Switch ($MicrosoftUpdateHashSet.Add($MicrosoftUpdatePropertyDictionary.UpdateID)) + { + {($_ -eq $True)} + { + $LogMessage = "Attempting to retrieve advanced details for update $($MicrosoftUpdateLoopCounter) of $($MicrosoftUpdateTotalHistoryCount) - [Title: $($MicrosoftUpdatePropertyDictionary.Title)] [Update ID: $($MicrosoftUpdatePropertyDictionary.UpdateID)]. Please Wait..." + Write-Verbose -Message $LogMessage + + $AdvancedUpdateInfo = $MicrosoftUpdateSearcher.Search("UpdateID = '$($MicrosoftUpdatePropertyDictionary.UpdateID)'") + + Switch ($Null -ine $AdvancedUpdateInfo) + { + {($_ -eq $True)} + { + Switch ($AdvancedUpdateInfo.Updates.Count -gt 0) + { + {($_ -eq $True)} + { + ForEach ($Update In $AdvancedUpdateInfo.Updates) + { + $UpdateAdvancedPropertyDictionary = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $UpdateAdvancedPropertyDictionary.KBArticleIDs = New-Object -TypeName 'System.Collections.Generic.List[String]' + $UpdateAdvancedPropertyDictionary.CVEIDs = New-Object -TypeName 'System.Collections.Generic.List[String]' + $UpdateAdvancedPropertyDictionary.SecurityBulletinIDs = New-Object -TypeName 'System.Collections.Generic.List[String]' + $UpdateAdvancedPropertyDictionary.SupersededUpdateIDs = New-Object -TypeName 'System.Collections.Generic.List[String]' + $UpdateAdvancedPropertyDictionary.Languages = New-Object -TypeName 'System.Collections.Generic.List[String]' + $UpdateAdvancedPropertyDictionary.RebootRequired = $Update.RebootRequired + $UpdateAdvancedPropertyDictionary.MinimumDownloadSize = $Update.MinDownloadSize + $UpdateAdvancedPropertyDictionary.MaximumDownloadSize = $Update.MaxDownloadSize + $UpdateAdvancedPropertyDictionary.LastDeploymentChangeTime = $Update.LastDeploymentChangeTime + $UpdateAdvancedPropertyDictionary.DownloadURLs = New-Object -TypeName 'System.Collections.Generic.List[String]' + + Switch ($True) + { + {($Update.Languages.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.Languages.Count) supported languages. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($Language In $Update.Languages) + { + Switch (([String]::IsNullOrEmpty($Language) -eq $False) -and ([String]::IsNullOrWhiteSpace($Language) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.Languages.Add($Language) + } + } + } + } + + {($Update.SecurityBulletinIDs.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.SecurityBulletinIDs.Count) security bulletin IDs. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($SecurityBulletinID In $Update.SecurityBulletinIDs) + { + Switch (([String]::IsNullOrEmpty($SecurityBulletinID) -eq $False) -and ([String]::IsNullOrWhiteSpace($SecurityBulletinID) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.SecurityBulletinIDs.Add($SecurityBulletinID) + } + } + } + } + + {($Update.SupersededUpdateIDs.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.SupersededUpdateIDs.Count) superseded Update IDs. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($SupersededUpdateID In $Update.SupersededUpdateIDs) + { + Switch (([String]::IsNullOrEmpty($SupersededUpdateID) -eq $False) -and ([String]::IsNullOrWhiteSpace($SupersededUpdateID) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.SupersededUpdateIDs.Add($SupersededUpdateID) + } + } + } + } + + {($Update.CVEIDs.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.CVEIDs.Count) CVE IDs. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($CVEID In $Update.CVEIDs) + { + Switch (([String]::IsNullOrEmpty($CVEID) -eq $False) -and ([String]::IsNullOrWhiteSpace($CVEID) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.CVEIDs.Add($CVEID) + } + } + } + } + + {($Update.KBArticleIDs.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.KBArticleIDs.Count) KB article IDs. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($KBArticleID In $Update.KBArticleIDs) + { + Switch (([String]::IsNullOrEmpty($KBArticleID) -eq $False) -and ([String]::IsNullOrWhiteSpace($KBArticleID) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.KBArticleIDs.Add($KBArticleID) + } + } + } + } + + {($Update.DownloadContents.Count -gt 0)} + { + $LogMessage = "Attempting to add $($Update.DownloadContents.Count) URLs to the download URL list. Please Wait..." + Write-Verbose -Message $LogMessage + + ForEach ($DownloadContent In $Update.DownloadContents) + { + Switch (([String]::IsNullOrEmpty($DownloadContent.DownloadUrl) -eq $False) -and ([String]::IsNullOrWhiteSpace($DownloadContent.DownloadUrl) -eq $False)) + { + {($_ -eq $True)} + { + $UpdateAdvancedPropertyDictionary.DownloadURLs.Add($DownloadContent.DownloadUrl) + } + } + } + } + } + + $UpdateAdvancedObject = New-Object -TypeName 'PSObject' -Property ($UpdateAdvancedPropertyDictionary) + + $MicrosoftUpdatePropertyDictionary.Advanced.Add($UpdateAdvancedObject) + } + } + } + } + } + + $MicrosoftUpdateObject = New-Object -TypeName 'PSObject' -Property ($MicrosoftUpdatePropertyDictionary) + + ForEach ($MicrosoftUpdateObjectProperty In $MicrosoftUpdateObject.PSObject.Properties) + { + Switch ($Null -ine $MicrosoftUpdateObjectProperty.Value) + { + {($_ -eq $True)} + { + Switch ($MicrosoftUpdateObjectProperty.Value.GetType().FullName) + { + {($_ -imatch 'System\.Collections\.Generic\.List.*\[.*\]')} + { + $MicrosoftUpdateObject.$($MicrosoftUpdateObjectProperty.Name) = $MicrosoftUpdateObjectProperty.Value.ToArray() + } + } + } + } + } + } + + Default + { + $MicrosoftUpdatePropertyDictionary.Advanced = ($OutputObjectList | Where-Object {($_.UpdateID -ieq $MicrosoftUpdatePropertyDictionary.UpdateID)} | Select-Object -First 1).Advanced + } + } + } + } + + $MicrosoftUpdateObject = New-Object -TypeName 'PSObject' -Property ($MicrosoftUpdatePropertyDictionary) + + $OutputObjectList.Add($MicrosoftUpdateObject) + + $MicrosoftUpdateLoopCounter++ + } + } + Catch + { + $ErrorHandlingDefinition.Invoke() + } + Finally + { + + } + } + + End + { + Try + { + #Determine the date and time the function completed execution + $FunctionEndTime = (Get-Date) + + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))" + Write-Verbose -Message $LogMessage + + #Log the total script execution time + $FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime) + + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)" + Write-Verbose -Message $LogMessage + + $LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is completed." + Write-Verbose -Message $LogMessage + } + Catch + { + $ErrorHandlingDefinition.Invoke() + } + Finally + { + $OutputObjectList = $OutputObjectList.ToArray() | Sort-Object -Property @('InstallationDate') + + Write-Output -InputObject ($OutputObjectList) + } + } + } +#endregion \ No newline at end of file