Sometimes, installed MSIs fail to uninstall. There can be various reasons, but one of the most common ones is when a custom action fails.
'Error 1720: There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor.
This could happen because the target script/exe is missing, or because the custom action script has an error in it, or due to a missing condition (maybe the custom action only had to run during the installation). What’s relevant is that the MSI will always try to run that custom action and probably fail.
The solution to this issue is editing the MSI and fixing the issue (disabling the custom action for uninstall, for example), and then re-caching it. This way, Windows Installer will use the new version. It’s important that the elements used for identification remain the same: ProductCode, PackageCode, ProductVersion and so on.
To re-cache an MSI, one might want to use the command line:
msiexec /fv "path_to_msi" <optional parameters>
However, the script below takes this further and goes through the following logic:
– It reads MSI info from the MSI file (ProductCode, PackageCode)
– It checks if a product with the corresponding ProductCode is installed
– If Yes, it retrieves the PackageCode and if it’s the same as the one we’re trying to re-cache, then it actually re-caches the MSI
'Logic:
'The Script retrieves the PackageCode and ProductCode from the MSI file, then it searches (by ProductCode).
'If the Product IS installed and the PackageCode is THE SAME, it recaches the MSI
Option Explicit
Const ERR_NOTFOUND = 2605
Const ERR_MSI = 2603 'general MSI io/query failure
Const ERR_DIFPACKAGE = 3000
'Create Objects, declare variables
dim installer
dim strProductCodeIn, strPackageCodeFound, strMsiFilePath, strLogFile, strPackageCodeIn
dim retCode, verFound, bStatus
retCode = 1
strMsiFilePath = wscript.arguments(0)
strProductCodeIn = GetMsiProperty(strMsiFilePath, "ProductCode")
strPackageCodeIn = GetMsiPackageCode(strMsiFilePath)
strLogFile = wscript.arguments(1)
If strProductCodeIn = "" Or strPackageCodeIn = "" Then wscript.quit(ERR_MSI)
' Check if Product Is Installed, by Checking PC
On error resume next
Set installer = Wscript.CreateObject("WindowsInstaller.Installer")
strPackageCodeFound = installer.ProductInfo(strProductCodeIn,"PackageCode")
On error Goto 0
If strPackageCodeFound = "" then
bStatus = False
retCode = ERR_NOTFOUND
ElseIf strPackageCodeFound = strPackageCodeIn Then
bStatus = True ' present
dim strCmd, shell
Set shell = CreateObject("Wscript.Shell")
strCmd = "msiexec /fv " & Chr(34) & strMsiFilePath & Chr(34) & " /norestart /qn REBOOT=ReallySuppress /L*v " & Chr(34) & strLogFile & Chr(34)
retCode = shell.Run(strCmd, 0, True)
Else
'ProductCode foundversion found but cannot be replaced.
retCode = ERR_DIFPACKAGE
End If
Set installer = Nothing
wscript.quit retCode
Please feel free to use the script.
The extra functions can be found on the corresponding articles, here:
GetMsiProperty
GetMsiPackageCode
The exit codes of the script can be customized, of course.