Limpiar todo rastro, en el registro de Windows, de entradas a instaladores MSI que no se encuentren presentes en el sistema o que simplemente den conflictos pos fallas de instalación o desinstalación.
Es magia pura para solucionar cierto tipo de problemas relacionados con entradas de registro de paquetes MSI huérfanos.
Autor del código original: https://gist.github.com/heaths/77fbe0b44496960fab25c2eb0b9e8475
Código
#Requires -Version 3 # https://gist.github.com/heaths/77fbe0b44496960fab25c2eb0b9e8475 [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string[]] $ProductCode ) [System.Console]::Title = "Remove Windows Installer product registration for missing MSI packages" [CultureInfo]::CurrentUICulture = "en-US" try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } $ErrorActionPreference = 'Stop' [int[]] $translation = 7,6,5,4,3,2,1,0,11,10,9,8,15,14,13,12,17,16,19,18,21,20,23,22,25,24,27,26,29,28,31,30 $loc = data { ConvertFrom-StringData @' Error_Elevation_Required = You must run this script in an elevated command prompt Error_64Bit_Required = You must run this in a 64-bit command prompt Error_PackageManagement_Required = Please install PackageManagement from http://go.microsoft.com/fwlink/?LinkID=746217 Process_Remove_Args1 = Remove registration for {0} Verbose_Install_MSI = Installing the "MSI" module Verbose_Scan_Missing = Scanning for products missing cached packages Verbose_Remove_Key_Args1 = Removing key : {0} Verbose_Remove_Value_Args2 = Removing value: {0}\\{1} Verbose_Remove_Source_Reg = Removing source registration Verbose_Remove_Product_Reg = Removing product registration Verbose_Remove_Upgrade_Reg = Removing upgrade registration Verbose_Remove_Component_Reg = Removing component registration Verbose_Found_Source_Args2 = Cache missing for {0} but found source at {1} '@ } $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal $identity if (!$principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { throw $loc.Error_Elevation_Required } if ([System.Environment]::Is64BitOperatingSystem) { if (![System.Environment]::Is64BitProcess) { throw $loc.Error_64Bit_Required } } $pack = { param ( [string] $Guid ) if (!$Guid) { return } $Guid = (New-Object System.Guid $Guid).ToString("N").ToUpperInvariant() $sb = New-Object System.Text.StringBuilder $translation.Count foreach ($i in $translation) { $null = $sb.Append($Guid[$i]) } $sb.ToString() } $test = { param ( $Product ) if ($Product.PSPath -and ($Product | Test-Path)) { return $true } if ($Product.PackageName) { $Product | Get-MSISource | ForEach-Object { $path = Join-Path $_.Path $Product.PackageName if ($path | Test-Path) { Write-Host ($loc.Verbose_Found_Source_Args2 -f $Product.ProductCode, $path) return $true } } } $false } $remove = { param ( [string] $Key ) if (Test-Path $Key) { Write-Host ($loc.Verbose_Remove_Key_Args1 -f $Key) Remove-Item -Recurse -Force $Key } } $removeChild = { param ( [string] $Key, [string] $Name ) if (Test-Path $Key) { Get-ChildItem $Key | ForEach-Object { $obj = $_ | Get-ItemProperty if ($obj.$Name -ne $null) { Write-Host ($loc.Verbose_Remove_Value_Args2 -f $_.Name, $Name) Remove-ItemProperty -Force -Name $Name -LiteralPath $_.PSPath $obj = Get-ItemProperty -LiteralPath $_.PSPath if (!$obj) { Write-Host ($loc.Verbose_Remove_Key_Args1 -f $_.Name) Remove-Item -Recurse -Force -LiteralPath $_.PSPath } } } } } if (!$ProductCode) { # Install the MSI module if missing. if (!(Get-Module -ListAvailable MSI)) { Write-Host $loc.Verbose_Install_MSI # Make sure PackageManagement is installed (comes with WMF 5.0 / Windows 10). if (!(Get-Module -ListAvailable PackageManagement)) { throw $loc.Error_PackageManagement_Required } Install-Module MSI -Scope CurrentUser -SkipPublisherCheck -Force } Write-Host $loc.Verbose_Scan_Missing foreach ($msi in (Get-MSIProductInfo -UserContext Machine)) { if (!(&$test $msi)) { $ProductCode += $msi.ProductCode } } } foreach ($code in $ProductCode) { if ($PSCmdlet.ShouldProcess($msi, $loc.Process_Remove_Args1 -f $code)) { $packedProductCode = &$pack $code Write-Host $loc.Verbose_Remove_Source_Reg &$remove "Registry::HKCL\SOFTWARE\Classes\Installer\Products\$packedProductCode" &$remove "Registry::HKCL\SOFTWARE\Classes\Installer\Features\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Classes\Installer\Products\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Classes\Installer\Features\$packedProductCode" Write-Host $loc.Verbose_Remove_Product_Reg &$remove "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedProductCode" &$remove "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$code" &$remove "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$code" &$remove "Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$code" Write-Host $loc.Verbose_Remove_Upgrade_Reg &$removeChild "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" $packedProductCode &$removeChild "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" $packedProductCode Write-Host $loc.Verbose_Remove_Component_Reg &$removeChild "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components" $packedProductCode &$removeChild "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components" $packedProductCode } } Write-Host "Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit(0) <# .SYNOPSIS Removes Windows Installer product registrtation for missing or specified MSIs .DESCRIPTION If Windows Installer product registration is corrupt (exit code 1610) or package sources are missing (exit code 1603, error message 1714; or exit code 1612), you can use this script in an elevated PowerShell command shell to clean up the registration is a transactional manner to avoid making machine state worse. Please note that this should be a last resort and only for those issues above. The old msizap.exe program was frought with issues and can make matters worse if not used properly. .PARAMETER ProductCode Optional list of ProductCode to clean up; otherwise, ProductCodes are scanned from products with missing sources. .EXAMPLE PS> Unregister-MissingMSIs.ps1 Removes per-machine product registration for products with missing cached MSIs. .EXAMPLE PS> Unregister-MissingMSIs.ps1 '{7B88D6BB-A664-4E5A-AB81-C435C8639A4D}' Remove per-machine product registration for the specified ProductCode only. #>