/Unregister-MissingMSIs.ps1 Secret
-
-
Save BrentHumphreys/111ac670e577a94bf1531cc4d9a9d8a0 to your computer and use it in GitHub Desktop.
#Requires -Version 3 | |
# The MIT License (MIT) | |
# Copyright (C) Microsoft Corporation. All rights reserved. | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
[CmdletBinding(SupportsShouldProcess = $true)] | |
param () | |
$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_Remove_Key_Args1 = Removing registry key {0} | |
Verbose_Remove_Value_Args2 = Removing registry value {1} from {0} | |
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 | Test-Path -ErrorAction continue) { | |
return $true | |
} | |
if ($Product.PackageName) { | |
$Product | Get-MSISource | ForEach-Object { | |
$path = Join-Path $_.Path $Product.PackageName | |
if ($path | Test-Path) { | |
Write-Verbose ($loc.Verbose_Found_Source_Args2 -f $Product.ProductCode, $path) | |
return $true | |
} | |
} | |
} | |
$false | |
} | |
$remove = { | |
param ( | |
[string] $Key | |
) | |
if (Test-Path $Key) { | |
Write-Verbose ($loc.Verbose_Remove_Key_Args1 -f $Key) | |
Remove-Item -Recurse -Force -UseTransaction $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-Verbose ($loc.Verbose_Remove_Value_Args2 -f $_.Name, $Name) | |
Remove-ItemProperty -Force -UseTransaction -Name $Name -LiteralPath $_.PSPath | |
$obj = Get-ItemProperty -UseTransaction -LiteralPath $_.PSPath | |
if (!$obj) { | |
Write-Verbose ($loc.Verbose_Remove_Key_Args1 -f $_.Name) | |
Remove-Item -Recurse -Force -UseTransaction -LiteralPath $_.PSPath | |
} | |
} | |
} | |
} | |
} | |
# Install the MSI module if missing. | |
if (!(Get-Module -ListAvailable MSI)) { | |
Write-Verbose $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 | |
} | |
foreach ($msi in (Get-MSIProductInfo -UserContext Machine)) { | |
if (!(&$test $msi)) { | |
if ($PSCmdlet.ShouldProcess($msi, $loc.Process_Remove_Args1 -f $msi.ProductCode)) { | |
$packedProductCode = &$pack $msi.ProductCode | |
Start-Transaction | |
Write-Verbose $loc.Verbose_Remove_Source_Reg | |
&$remove "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Products\$packedProductCode" | |
&$remove "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Features\$packedProductCode" | |
Write-Verbose $loc.Verbose_Remove_Product_Reg | |
&$remove "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedProductCode" | |
&$remove "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$($msi.ProductCode)" | |
&$remove "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$($msi.ProductCode)" | |
Write-Verbose $loc.Verbose_Remove_Upgrade_Reg | |
&$removeChild "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" $packedProductCode | |
Write-Verbose $loc.Verbose_Remove_Component_Reg | |
&$removeChild "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components" $packedProductCode | |
Complete-Transaction | |
} | |
} | |
} |
I get the same error as HakanL above - was there a solution to this? Thank you for providing the script!
I had the same error as HakanL with the original version of this script but indeed this version worked for me.
The original version of this script exited with the same error as HakanL. The modified version also emitted that error but continued to run. It ran for quite a long time, maybe 15 minutes or more, and emitted that error four times altogether. Unfortunately the VS installer still fails to install a working environment.
Tried using this script. Getting an error though: Join-Path : Cannot find drive. A drive with the name 'm' does not exist.
At C:\Unregister-MissingMSIs.ps1:77 char:21
-
$path = Join-Path $_.Path $Product.PackageName
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CategoryInfo : ObjectNotFound: (m:String) [Join-Path], DriveNotFoundException
- FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.JoinPathCommand
Help would be appreciated.
The problem is because of corrupt MSI registration. I'll fix the original script to skip these.
The 'Get-MSIProductInfo' command was found in the module 'MSI', but the module could not be loaded. For more
information, run 'Import-Module MSI'.
+ CategoryInfo : ObjectNotFound: (Get-MSIProductInfo:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
I'm getting this error:
Test-Path : Cannot bind argument to parameter 'LiteralPath' because it is null.
At C:\users\username\Downloads\Unregister-MissingMSIs (1).ps1:71 char:20