public/Uninstall-KbUpdate.ps1
function Uninstall-KbUpdate { <# .SYNOPSIS Uninstalls KB updates on Windows-based systems .DESCRIPTION Uninstalls KB updates on Windows-based systems Note that sometimes, an uninstall will leave registry entries and Get-KbInstalledSoftware will report the product is installed. This is the behavior of some patches and happens even when using the Windows uninstall GUI. .PARAMETER ComputerName Used to connect to a remote host .PARAMETER Credential The optional alternative credential to be used when connecting to ComputerName .PARAMETER HotfixId The HotfixId of the patch .PARAMETER InputObject Allows results to be piped in from Get-KbInstalledSoftware .PARAMETER ArgumentList Allows you to override our automatically determined ArgumentList .PARAMETER NoQuiet By default, we add a /quiet switch to the argument list to ensure the command can run from the command line. Some commands may not support this switch, however, so to remove it use NoQuiet. Not required if you use ArgumentList. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .NOTES Author: Chrissy LeMaire (@cl), Jess Pomfret (@jpomfret) Copyright: (c) licensed under MIT License: MIT https://opensource.org/licenses/MIT .EXAMPLE PS C:\> Uninstall-KbUpdate -ComputerName sql2017 -HotfixId kb4498951 Uninstalls kb4498951 on sql2017 .EXAMPLE PS C:\> Uninstall-KbUpdate -ComputerName sql2017 -HotfixId kb4498951 -Confirm:$false Uninstalls kb4498951 on sql2017 without prompts .EXAMPLE PS C:\> Get-KbInstalledSoftware -ComputerName server23, server24 -Pattern kb4498951 | Uninstall-KbUpdate Uninstalls kb4498951 from server23 and server24 .EXAMPLE PS C:\> Uninstall-KbUpdate -ComputerName sql2017 -HotfixId KB4534273 -WhatIf Shows what would happen if the command were to run but does not execute any changes .EXAMPLE PS C:\> Install-KbUpdate -ComputerName sql2017 -FilePath \\dc\sql\windows10.0-kb4486129-x64_0b61d9a03db731562e0a0b49383342a4d8cbe36a.msu PS C:\> Get-KbInstalledSoftware -Pattern kb4486129 -ComputerName sql2017 | Uninstall-KbUpdate Quick lil example to show an install, followed by an uninstall #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")] param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [PSFComputer[]]$ComputerName, [PSCredential]$Credential, [Alias("Name", "KBUpdate", "Id")] [Parameter(ValueFromPipelineByPropertyName)] [string]$HotfixId, [Parameter(ValueFromPipeline)] [pscustomobject[]]$InputObject, [string]$ArgumentList, [switch]$NoQuiet, [switch]$EnableException ) begin { $programscriptblock = { param ( $Program, $ArgumentList, $hotfix, $Name, $VerbosePreference ) function Invoke-UninstallCommand ($Program, $ArgumentList) { $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $Program $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $ArgumentList $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $null = $p.Start() $p.WaitForExit() [pscustomobject]@{ stdout = $p.StandardOutput.ReadToEnd() stderr = $p.StandardError.ReadToEnd() ExitCode = $p.ExitCode } } $firstarg = $ArgumentList -split " " | Select-Object -First 1 if ($firstarg -match ".exe") { $ArgumentList = $ArgumentList.Replace($firstarg, "") $Program = "$Program$firstarg" } Write-Verbose -Message "Program = $Program" Write-Verbose -Message "ArgumentList = $ArgumentList" $results = $null $results = Invoke-UninstallCommand -Program $Program -ArgumentList $ArgumentList $output = $results.stdout.Trim() # -2067919934 is reboot needed but the output already tells you to reboot # Perhaps suggest people check out C:\Windows\Logs\CBS\CBS.log # Only package owners can remove package: Package_10_for_KB4532947~31bf3856ad364e35~amd64~~10.0.1.2565 [HRESULT = 0x80070005 - E_ACCESSDENIED] <# 0 { "Uninstallation command triggered successfully" } 2 { "You don't have sufficient permissions to trigger the command on $Computer" } 3 { "You don't have sufficient permissions to trigger the command on $Computer" } 8 { "An unknown error has occurred" } 9 { "Path Not Found" } 9 { "Invalid Parameter"} #> switch ($results.ExitCode) { -2068052310 { $output = "$output`n`nThe exit code suggests that you need to mount the SQL Server ISO so the uninstaller can find the setup files." } -2068643839 { $output = "$output`n`nThe exit code suggests that you need to mount the SQL Server ISO so the uninstaller can find the setup files." } -2068709375 { $output = "$output`n`nYou likely need to reboot $env:ComputerName." } -2067919934 { $output = "$output`n`nThe exit code suggests that something is corrupt. See if this tutorial helps: http://www.sqlcoffee.com/Tips0026.htm" } 3010 { $output = "You have successfully uninstalled $Name. A restart is now required to finalize the uninstall." } 0 { if ($output.Trim()) { $output = "$output`n`nYou have successfully uninstalled $Name" } else { if ($Name) { $output = "$Name has been successfully uninstalled" } } } } [pscustomobject]@{ ComputerName = $env:ComputerName Name = $Name HotfixID = $hotfix ExitCode = $results.ExitCode Results = $output } } } process { if (-not $InputObject -and $HotfixId) { foreach ($hotfix in $HotfixId) { if (-not $hotfix.ToUpper().StartsWith("KB") -and $PSBoundParameters.HotfixId) { $hotfix = "KB$hotfix" } foreach ($computer in $ComputerName) { Write-PSFMessage -Level Verbose -Message "Adding uninstall for $hotfix to queue on $computer" $exists = Get-KbInstalledSoftware -Pattern $hotfix -ComputerName $computer -IncludeHidden if (-not $exists) { Write-PSFMessage -Level Warning -Message "$hotfix is not installed on $computer" } else { # turns out this is not true # Stop-PSFFunction -EnableException:$EnableException -Message "You must restart before #you can uninstall $hotfix on $computer" -Continue #} else { if ($exists.FastPackageReference -and $exists.FastPackageReference -notin $InputObject.FastPackageReference) { $InputObject += $exists } elseif ($exists.PackageObject -and $exists.PackageObject -notin $InputObject.PackageObject) { $InputObject += $exists } } } } $InputObject = $InputObject | Sort-Object FastPackageReference -Unique } if ($IsLinux -or $IsMacOs) { Stop-PSFFunction -Message "This command uses remoting and only supports Windows at this time" -EnableException:$EnableException return } foreach ($update in $InputObject) { $computer = $update.ComputerName $packagename = $update.Name if (-not $packagename) { $packagename = $update.HotFixID } if (-not $packagename) { $packagename = $update.HotFixID } if (-not $packagename) { $packagename = $update.InstallName } if (-not $computer) { Stop-PSFFunction -Message "No computername associated with $packagename, moving on" -Continue -EnableException:$EnableException } Write-PSFMessage -Level Verbose -Message "Processing $computer" if (-not (Test-ElevationRequirement -ComputerName $computer)) { Stop-PSFFunction -Message "To run this command locally, you must run as admin." -Continue -EnableException:$EnableException } if ($PSBoundParameters.ArgumentList) { $needuninstallstring = $false if ($update.QuietUninstallString) { $string = $update.QuietUninstallString } else { $string = $update.UninstallString } $path = $string -match '^(".+") (/.+) (/.+)' if ($matches) { $program = $matches[1] } if (-not $path) { $program = Split-Path $string } } elseif ($update.QuietUninstallString -and $update.ProviderName -eq "Programs" -and -not $NoQuiet) { $path = $update.QuietUninstallString -match '^(".+") (/.+) (/.+)' if ($matches) { $needuninstallstring = $false $program = $matches[1] } if (-not $path) { $program = Split-Path $update.QuietUninstallString } $ArgumentList = $update.QuietUninstallString.Replace($program, "") } elseif ($update.UninstallString -and $update.ProviderName -eq "Programs" -and $update.UninstallString -notmatch "SetupARP.exe") { $path = $update.UninstallString -match '^(".+") (/.+) (/.+)' if ($matches) { $needuninstallstring = $false $program = $matches[1] } if (-not $path) { $program = Split-Path $update.UninstallString } $ArgumentList = $update.UninstallString.Replace($program, "") if ($ArgumentList -match "msedge") { $ArgumentList = "$ArgumentList --force-uninstall" } elseif ($ArgumentList -notmatch "/quiet" -and -not $NoQuiet -and -not $PSBoundParameters.ArgumentList -and $ArgumentList -ne "/S" -and $ArgumentList -ne "/Q") { $ArgumentList = "$ArgumentList /quiet" } } if ($needuninstallstring) { <# I have so many notes from so many different attempts to address this flawlessly GET-PACKAGE Get-Package | Uninstall-Package is buggy per https://stackoverflow.com/questions/54740151/get-package-notepad-uninstall-package-force-not-working The Uninstall-Package cmdlet won't work with these entries (i.e. ones where "ProviderName" is "Programs"). Another BIG gotcha with PackageManagement/PowerShellGet Modules that I ran into recently - if you uninstall a Program that was installed via PackageManagement via the Control Panel GUI, the Get-Package cmdlet will still show it as installed until you run the Uninstall-Package cmdlet on the erroneous entry. PKGMGR http://msiworld.blogspot.com/2012/04/silent-install-and-uninstall-of-msu.html pkgmgr = DISM $ArgumentList = "/up:$installname" WUSA Newer versions of win10 doesnt support old-style wusa, go for DISM /quiet /norestart https://support.microsoft.com/en-us/help/934307/description-of-the-windows-update-standalone-installer-in-windows MSIEXEC WITH PACKAGE GUID + GUID OF PATCH Could never figure out how to get GUID-OF-PRODUCT https://docs.microsoft.com/en-us/windows/win32/msi/uninstalling-patches?redirectedfrom=MSDN Msiexec /i {installpath_of_product} MSIPATCHREMOVE={installpath_of_patch} /qb Msiexec /package {GUID-OF-PRODUCT} /uninstall {GUID_OF_PATCH} /passive WMIC Took too long wmic product where "name like 'Java 8%%'" and not name 'Java 8 Update 101%%'" call uninstall /nointeractive VARIOUS ARTISTS provides various ways from https://support.symantec.com/us/en/article.howto42396.html introduced me to msipatchremove and how to reverse enginer guid https://docs.microsoft.com/en-us/office/troubleshoot/installation/automate-uninstall-office-update DISM props for highlighting that the installversion is important for win10 this allowed me to find the InstallName https://social.technet.microsoft.com/Forums/Lync/en-US/f6594e00-2400-4276-85a1-fb06485b53e6/issues-with-wusaexe-and-windows-10-enterprise?forum=win10itprogeneral #> $installname = $update.InstallName if (-not $installname) { $installname = ($update.CBSPackageObject).PSChildName } if (-not $installname) { Stop-PSFFunction -EnableException:$EnableException -Message "Couldn't determine a way to uninstall $($update.Name). It may be marked as a permanent install or part of another package that contains the unintaller." -Continue } $program = "dism" $parms = @("/Online /Remove-Package /quiet /norestart") foreach ($install in $installname) { $parms += "/PackageName:$install" } $ArgumentList = $parms -join " " } # I tried to get this working using DSC but in end end, a Start-Process equivalent was it for the convenience of not having to specify a filename, tho that can be added as a backup if ($ArgumentList -match ".exe") { $exec = "$program$ArgumentList".Trim() } else { $exec = "$program $ArgumentList".Trim() } if ($exec.Length -lt 4) { Stop-PSFFunction -Message "Failure on $computer while attempting to uninstall $packagename | Uninstaller cannot be found" -EnableException:$EnableException -Continue } if ($PSCmdlet.ShouldProcess($computer, "Uninstalling Hotfix $packagename by executing $exec")) { try { $jobs = @() foreach ($computer in $ComputerName) { Write-PSFMessage -Level Verbose -Message "Adding job for $computer" $arglist = [pscustomobject]@{ ComputerName = $computer Credential = $Credential ScriptBlock = $programscriptblock ArgumentList = $Program, $ArgumentList, $object.HotfixId, $packagename, $VerbosePreference ModulePath = $script:dependencies } $invokeblock = { foreach ($path in $args.ModulePath) { $null = Import-Module $path 4>$null } $sb = [scriptblock]::Create($args.ScriptBlock) $parms = @{ ComputerName = $args.ComputerName Credential = $args.Credential ScriptBlock = $sb ArgumentList = $args.ArgumentList } Invoke-KbCommand @parms -ErrorAction Stop } $jobs += Start-Job -Name $computer -ScriptBlock $invokeblock -ArgumentList $arglist -ErrorAction Stop } } catch { Stop-PSFFunction -Message "Failure on $computer while attempting to uninstall $packagename" -ErrorRecord $_ -EnableException:$EnableException } if ($jobs.Name) { try { $jobs | Start-JobProcess -Activity "Uninstalling software" -Status "uninstalling software" | Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId } catch { Stop-PSFFunction -Message "Failure" -ErrorRecord $PSItem -EnableException:$EnableException -Continue } } } } } } # SIG # Begin signature block # MIIjYAYJKoZIhvcNAQcCoIIjUTCCI00CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCdtldS1s8bvnxZ # D49Ln1BZLZ94rMoCP4VxR5qImt2lsaCCHVkwggUaMIIEAqADAgECAhADBbuGIbCh # Y1+/3q4SBOdtMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcN # MjAwNTEyMDAwMDAwWhcNMjMwNjA4MTIwMDAwWjBXMQswCQYDVQQGEwJVUzERMA8G # A1UECBMIVmlyZ2luaWExDzANBgNVBAcTBlZpZW5uYTERMA8GA1UEChMIZGJhdG9v # bHMxETAPBgNVBAMTCGRiYXRvb2xzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB # CgKCAQEAvL9je6vjv74IAbaY5rXqHxaNeNJO9yV0ObDg+kC844Io2vrHKGD8U5hU # iJp6rY32RVprnAFrA4jFVa6P+sho7F5iSVAO6A+QZTHQCn7oquOefGATo43NAadz # W2OWRro3QprMPZah0QFYpej9WaQL9w/08lVaugIw7CWPsa0S/YjHPGKQ+bYgI/kr # EUrk+asD7lvNwckR6pGieWAyf0fNmSoevQBTV6Cd8QiUfj+/qWvLW3UoEX9ucOGX # 2D8vSJxL7JyEVWTHg447hr6q9PzGq+91CO/c9DWFvNMjf+1c5a71fEZ54h1mNom/ # XoWZYoKeWhKnVdv1xVT1eEimibPEfQIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAU # WsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFPDAoPu2A4BDTvsJ193ferHL # 454iMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8E # cDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVk # LWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTIt # YXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggr # BgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEw # gYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/ # BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAj835cJUMH9Y2pBKspjznNJwcYmOxeBcH # Ji+yK0y4bm+j44OGWH4gu/QJM+WjZajvkydJKoJZH5zrHI3ykM8w8HGbYS1WZfN4 # oMwi51jKPGZPw9neGS2PXrBcKjzb7rlQ6x74Iex+gyf8z1ZuRDitLJY09FEOh0BM # LaLh+UvJ66ghmfIyjP/g3iZZvqwgBhn+01fObqrAJ+SagxJ/21xNQJchtUOWIlxR # kuUn9KkuDYrMO70a2ekHODcAbcuHAGI8wzw4saK1iPPhVTlFijHS+7VfIt/d/18p # MLHHArLQQqe1Z0mTfuL4M4xCUKpebkH8rI3Fva62/6osaXLD0ymERzCCBTAwggQY # oAMCAQICEAQJGBtf1btmdVNDtW+VUAgwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UE # BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj # ZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4X # DTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTAT # BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx # MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBD # QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPjTsxx/DhGvZ3cH0wsx # SRnP0PtFmbE620T1f+Wondsy13Hqdp0FLreP+pJDwKX5idQ3Gde2qvCchqXYJawO # eSg6funRZ9PG+yknx9N7I5TkkSOWkHeC+aGEI2YSVDNQdLEoJrskacLCUvIUZ4qJ # RdQtoaPpiCwgla4cSocI3wz14k1gGL6qxLKucDFmM3E+rHCiq85/6XzLkqHlOzEc # z+ryCuRXu0q16XTmK/5sy350OTYNkO/ktU6kqepqCquE86xnTrXE94zRICUj6whk # PlKWwfIPEvTFjg/BougsUfdzvL2FsWKDc0GCB+Q4i2pzINAPZHM8np+mM6n9Gd8l # k9ECAwEAAaOCAc0wggHJMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD # AgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHkGCCsGAQUFBwEBBG0wazAkBggrBgEF # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRw # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0Eu # Y3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20v # RGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5k # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsME8GA1UdIARI # MEYwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp # Y2VydC5jb20vQ1BTMAoGCGCGSAGG/WwDMB0GA1UdDgQWBBRaxLl7KgqjpepxA8Bg # +S32ZXUOWDAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG # 9w0BAQsFAAOCAQEAPuwNWiSz8yLRFcgsfCUpdqgdXRwtOhrE7zBh134LYP3DPQ/E # r4v97yrfIFU3sOH20ZJ1D1G0bqWOWuJeJIFOEKTuP3GOYw4TS63XX0R58zYUBor3 # nEZOXP+QsRsHDpEV+7qvtVHCjSSuJMbHJyqhKSgaOnEoAjwukaPAJRHinBRHoXpo # aK+bp1wgXNlxsQyPu6j4xRJon89Ay0BEpRPw5mQMJQhCMrI2iiQC/i9yfhzXSUWW # 6Fkd6fp0ZGuy62ZD2rOwjNXpDd32ASDOmTFjPQgaGLOBm0/GkxAG/AeB+ova+YJJ # 92JuoVP6EpQYhS6SkepobEQysmah5xikmmRR7zCCBY0wggR1oAMCAQICEA6bGI75 # 0C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIG # A1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAw # MFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD # ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGln # aUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuE # DcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNw # wrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs0 # 6wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e # 5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtV # gkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85 # tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+S # kjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1Yxw # LEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzl # DlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFr # b7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATow # ggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiu # HA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQE # AwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2 # hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290 # Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/ # Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNK # ei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHr # lnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4 # oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5A # Y8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNN # n3O3AamfV6peKOK5lDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJ # KoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu # YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQg # VHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVow # YzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQD # EzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGlu # ZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklR # VcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54P # Mx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupR # PfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvo # hGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV # 5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYV # VSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6i # c/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/Ci # PMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5 # K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oi # qMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuld # yF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAG # AQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAW # gBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAww # CgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDow # OKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRS # b290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkq # hkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvH # UF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0M # CIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCK # rOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rA # J4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZ # xhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScs # PT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1M # rfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXse # GYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWY # MbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYp # hwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPww # ggbAMIIEqKADAgECAhAMTWlyS5T6PCpKPSkHgD1aMA0GCSqGSIb3DQEBCwUAMGMx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy # RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg # Q0EwHhcNMjIwOTIxMDAwMDAwWhcNMzMxMTIxMjM1OTU5WjBGMQswCQYDVQQGEwJV # UzERMA8GA1UEChMIRGlnaUNlcnQxJDAiBgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFt # cCAyMDIyIC0gMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM/spSY6 # xqnya7uNwQ2a26HoFIV0MxomrNAcVR4eNm28klUMYfSdCXc9FZYIL2tkpP0GgxbX # kZI4HDEClvtysZc6Va8z7GGK6aYo25BjXL2JU+A6LYyHQq4mpOS7eHi5ehbhVsbA # umRTuyoW51BIu4hpDIjG8b7gL307scpTjUCDHufLckkoHkyAHoVW54Xt8mG8qjoH # ffarbuVm3eJc9S/tjdRNlYRo44DLannR0hCRRinrPibytIzNTLlmyLuqUDgN5YyU # XRlav/V7QG5vFqianJVHhoV5PgxeZowaCiS+nKrSnLb3T254xCg/oxwPUAY3ugjZ # Naa1Htp4WB056PhMkRCWfk3h3cKtpX74LRsf7CtGGKMZ9jn39cFPcS6JAxGiS7uY # v/pP5Hs27wZE5FX/NurlfDHn88JSxOYWe1p+pSVz28BqmSEtY+VZ9U0vkB8nt9Kr # FOU4ZodRCGv7U0M50GT6Vs/g9ArmFG1keLuY/ZTDcyHzL8IuINeBrNPxB9Thvdld # S24xlCmL5kGkZZTAWOXlLimQprdhZPrZIGwYUWC6poEPCSVT8b876asHDmoHOWIZ # ydaFfxPZjXnPYsXs4Xu5zGcTB5rBeO3GiMiwbjJ5xwtZg43G7vUsfHuOy2SJ8bHE # uOdTXl9V0n0ZKVkDTvpd6kVzHIR+187i1Dp3AgMBAAGjggGLMIIBhzAOBgNVHQ8B # Af8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAg # BgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZ # bU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFGKK3tBh/I8xFO2XC809KpQU31Kc # MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAG # CCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy # dC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQw # DQYJKoZIhvcNAQELBQADggIBAFWqKhrzRvN4Vzcw/HXjT9aFI/H8+ZU5myXm93KK # mMN31GT8Ffs2wklRLHiIY1UJRjkA/GnUypsp+6M/wMkAmxMdsJiJ3HjyzXyFzVOd # r2LiYWajFCpFh0qYQitQ/Bu1nggwCfrkLdcJiXn5CeaIzn0buGqim8FTYAnoo7id # 160fHLjsmEHw9g6A++T/350Qp+sAul9Kjxo6UrTqvwlJFTU2WZoPVNKyG39+Xgmt # dlSKdG3K0gVnK3br/5iyJpU4GYhEFOUKWaJr5yI+RCHSPxzAm+18SLLYkgyRTzxm # lK9dAlPrnuKe5NMfhgFknADC6Vp0dQ094XmIvxwBl8kZI4DXNlpflhaxYwzGRkA7 # zl011Fk+Q5oYrsPJy8P7mxNfarXH4PMFw1nfJ2Ir3kHJU7n/NBBn9iYymHv+XEKU # gZSCnawKi8ZLFUrTmJBFYDOA4CPe+AOk9kVH5c64A0JH6EE2cXet/aLol3ROLtoe # HYxayB6a1cLwxiKoT5u92ByaUcQvmvZfpyeXupYuhVfAYOd4Vn9q78KVmksRAsiC # nMkaBXy6cbVOepls9Oie1FqYyJ+/jbsYXEP10Cro4mLueATbvdH7WwqocH7wl4R4 # 4wgDXUcsY6glOJcB0j862uXl9uab3H4szP8XTE0AotjWAQ64i+7m4HJViSwnGWH2 # dwGMMYIFXTCCBVkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD # ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGln # aUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQAwW7hiGwoWNf # v96uEgTnbTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCAjUO+FYDS5vUyM+Gc0VO0BsYMY # PihNL0jMJrdpx6UUtDANBgkqhkiG9w0BAQEFAASCAQA+lNI5zvOK3SVILewtIRX+ # 8em2+AkhCo1GIwOYxmSAL3yYq4yKODoS62sAx1HECoyNzZT5uDNTlXzNakBEfIje # bkhdRtREqHiWjaUo0W+oJOyd2nqlWyNjEKzrW+xB1U+33epaBkiJaUUFnDMgjUu5 # UtdRE0TLtai7+R1BaStYIiJREpZnSZ+XMx5iV3ZD6Rw/yzEVoAszXnOdiwMcCbG7 # +ZFzZX9pTlpo7KGz+fPbl0hQPHB9XZcFScfaOhgJEtb8QbCuMxr7Ld94D8IM4/DL # dPznYcbdzza1aVW0TXZRNBqZAZALBapgtaPciIgHki4lc3ouI/oceVU2p9KvgbMM # oYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMx # FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVz # dGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQDE1pckuU+jwq # Sj0pB4A9WjANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0B # BwEwHAYJKoZIhvcNAQkFMQ8XDTIyMTAwNzA2MTIyNFowLwYJKoZIhvcNAQkEMSIE # IAbPQh6eBayBerOgGDTa6PdlMjYRYg1dFp6nPNymthFjMA0GCSqGSIb3DQEBAQUA # BIICAI/eZo7BmMNPqEF1mo/YEK9W+brPXkOBOsjPvPgWDSRCgf6pBiqFuPe/R6X0 # HxVPFbPNXfELxKD8/VoFeky5gzhM4Y32VAiYzUD0bYIjwLmrOVphSgOoXYs/v0Sh # ZAxrju9JGk4KAU9UmBOROIlNWtVRWQH4/6Kf12rJIn/gW/sY10UCneaKhVfZb5HV # uj2H3rwgxS1G3LX2+yUPgjT1CVxozaRWNt2SlVdR08NAxxyo6NS4ggawMsIWXDyO # fwksDBOudeEeSN96Iwl/9KoP4TQOpv2644bukCFrL6RkCdzlxvTwsqKLfX1+pZtQ # HT2HhlpC+gw64lCWAzLs9GwZOp/O1EHr/fTrixbP/BYY3pTrxsy98DkirPaqhQ+S # K3jFJtn61ApfHkCWg6QlMb7uh7KRl7RoBh8jRD5nn9ScFVDYTnUg3n5e3jnEQMd0 # e+y4Ct4bmnYibtuher90uvBxI49aBxb83F+XHCd23oAHR4eFNyuFg3fFWcJSD4+3 # PjuhRWC2wfS/OggZrSlkM/+CgYOJyaPy8SBoLApVdp3iaVZ56znHVbS4am0H7JJF # AV3XOAIK+rJKlY3epYf7x6IUnC93o81oG754XH9IDWRc6qwtjGiwZmZauZwOb5Qs # dR7IduKat5Vpfv5qfzT81SeI0o6I+XDBUF7HW0dB4vTCGwH6 # SIG # End signature block |