How to re-cache an MSI file

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.

How to retrieve the PackageCode from an MSI file programatically

In addition to our VBScript function that retrieves Property Values from an MSI database, we might need to read the PackageCode, from the MSI Summary view. For that, we could use the code below.


Function GetMsiPackageCode(msiFile)
	On Error Resume Next
	dim inst, summary, view, row, str
	str = ""
	set inst = Wscript.CreateObject("WindowsInstaller.Installer") 
	set summary = inst.SummaryInformation(msiFile)	
	If Err.number Then 
		'error
	Else
		str  =  summary.Property(9) ' PID_REVNUMBER = 9, package code.
	End If
	set summary = Nothing
	set inst = Nothing
	On Error Goto 0
	GetMsiPackageCode = str
End Function

To use it, we’d simply call GetMsiPackageCode(“C:\Temp\Test.msi”) and store it into a (string) variable.

How to retrieve Property Values from an MSI file, using VBScript

The VBScript function below can be used to retrieve MSI properties from an MSI file (database). It uses the WindowsInstaller.Installer class.

Function GetMsiProperty(msiFile, strProperty)
	On Error Resume Next
	dim inst, db, view, row, str
	str = ""
	set inst = Wscript.CreateObject("WindowsInstaller.Installer") 
	Set db = inst.OpenDatabase(msiFile,0)
	If Err.number Then 
		'error
	Else
		Set view = db.OpenView("Select `Value` From Property WHERE `Property` ='"& strProperty & "'")
		view.Execute
		Set row = view.Fetch
		If Not row Is Nothing Then str=row.StringData(1)
	End If
	set row = Nothing
	set view = Nothing
	set db = Nothing
	set inst = Nothing
	On Error Goto 0
	GetMsiProperty = str
End Function

This function accepts the MSI full file path, and the property to be retrieved.

For example, in order to retrieve the ProductCode of an MSI whose full path is C:\Temp\Test.msi, one would call it like this:

strProductCode = GetMsiProperty("C:\Temp\Test.msi", "ProductCode")

If the property doesn’t exist, or if the file cannot be opened, the function will return an empty string “”.

0x80070005 – Access is denied

Recently, we have noticed failed installations that return error code 0x80070005. Among the affected applications: Microsoft Visual C++ 2015-2019, Image Reziser and others.

At first sight, it would seem that the setup doesn’t have the necessary permissions to complete the installation. However, the setup was running either as Administrator, or as the System account. So, clearly, that’s not the issue.

In our case, it seem that the issue was caused by the antivirus software. According to the software’s log (we use McAfee Endpoint Security), “<user> ran VC_redist.x86.exe, which tried to access HKLM\SOFTWARE\WOW6432NODE\MICROSOFT\WINDOWS\CURRENTVERSION\RUNONCE{49697869-BE8E-427D-81A0-C334D1D14950}, violating the rule “Registering of programs to autorun”, and was blocked. For information about how to respond to this event, see KB85494.”

We’ve identified two workarounds for this issue:

  1. Removing the antivirus software and installing the faulty setup. However, this is a bit radical and will make the machine vulnerable.
  2. Updating the antivirus software. In our case, it seems that the correct policies were not enforced locally, due to a fault in the communication between the McAfee ePO Agent and the back end. Checking further revealed that the last agent-to-server communication on the PC happened months ago. Updating the agent and rebooting the PC solved the issue.

How to use SDBINST to install SDB fixes

Installation

SDB files (databases), which we’d call shims, can easily be installed with the following command

sdbinst -q path_to_sdbfile

-q means quiet mode and the prompts for confirmation are auto accepted.

Another parameter used during installations is -p, which will allow SDBs containing patches. Not that common, though.

 

Once installed, there will be an entry in Add/Remove Programs, with the name given to the fix in the ACT (Application Compatibility Toolkit).

 

 

Uninstall

In order to uninstall a  shim, sdbinst can be called with the following parameters

-q                     quiet mode, same as for the installation

-u File.sdb      this will remove the shim installed by the provided SDB file

or

-u {guid}         this will uninstall based on the guid

-n name          this will uninstall based on the internal name (the one

 

 

Known issues

See what issues might occur when using sdbinst in our related article.

 

SDBINST issues on Windows 7 and Windows 10

Possible Problems

When migrating packages Windows 7 (or older) to Windows 10, or when simply targeting multiple OS’s with the same package, one might to pay attention on the way SDBINST.exe is used for compatibility fixes (shims).
In case the executable is included in the package (simply as a file or in the binary table, inside an MSI), there could be issues like error exit codes of sdbinst, or worse, like an incorrect behaviour even though the SDB file would appear to be installed.

Long story short:

  • the SDBINST from Windows 7 will behave incorrectly on Windows 10 (shim/sdb will appear as installed but won’t do what it’s supposed to do)
  • the SDBINST.exe from Windows 10 will not work at all on Windows 7 (visible in the exit code)

 

Solution

Adapt the package so that SDBINST.exe is excluded from it and use the executable found on the system, whether it’s an Win7 or Win10 OS.

In case this is done inside an MSI via custom action, make sure to change it from “Execute from Installation” in Wise or “EXE – Stored in Binary Table/Installed with Product” in InstallShiled to “Execute from Destination” – Wise or “EXE – Path from Directory”. That will result in a custom action with type 3106 (0x0c22) if you’re executing in Deferred – System Context, Synchronous.

 

More info

For more info on sdbinst.exe and how to use it, check our other post about this topic.

 

 

InstallAnywhere Silent Installations

<h1>InstallAnywhere Silent Installation</h1>

According to Wikipedia InstallAnywhere is a Java-based software used to create software packages.

On Windows, InstallAnywhere packages come as executables.

In order to install such a package silently, we need to follow these steps:

1. Create a configuration replay file (install.properties) by starting the setup in replay mode.
<setup.exe> -r install.properties
2. Complete the installation by selecting the desired options.
3. Edit the newly install.properties file. Add this line before the install directory definition.
Installer_UI=silent
4. Save
5. Run the following command:
<setup.exe> -i silent -f “<pathto>\install.properties”

ATTENTION: Try to keep the path to the .properties file short (no spaces). Otherwise, the setup might fail (Problem opening install properties file). Try something like c:\tmp or c:\temp…

By default, log files (or something close) can be found in c:\tmp.

<h1>InstallAnywhere Silent Uninstall</h1>

In order to uninstall the software silently, look for an Uninstall*.exe in the installation directory. Run it with the -i silent parameter.

Office Installation

Microsoft provides an uniform way of silent customizing Office products’ installations: OCT (Office Customization Tool).

In order to start it, run the setup executable of the office installation you want to start (32 or 64-bit) with /admin parameter. (setup.exe /admin)

This will start a wizard where you can configure many options, from feature selection, to the smallest details one can imagine.

Once you’re done with the configuration, save the changes. This will create an MSP file that you can use for the silent installation.

In order to install it, run the following command line:

setup.exe /adminfile <pathToMsp>

However, there’s also the possibility of using a configuration xml file for the silent installation, based on the template config.xml that can be found in the core_product_folder_name.WW folder.

Also, an XML file can be created for a silent uninstall.

 

 

OCT is available for Office (2007 or later) but other related software such as Microsoft Lync, Visio, Project, OneNote etc.

Hiding an entry in Add/Remove Programs

At some point, one might want to hide one or more entries added by software setup(s) in Add/Remove Programs (also known as “Programs and Features”, ” Uninstall a Program”, “Add or Remove Programs” under Windows 7).

Here’s a neat trick to do this:

  • Open regedit
  • Look for the Uninstall key of the software. That’s under:
    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall          OR
    • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall (in case of a 32-bit installation on a 64-bit machine)
  • The key can be a GUID or an actual software name (like “Adobe AIR”, for example).
  • Under that key, create a DWORD value called SystemComponent and set it to 1
  • Done.

In case of a silent installation of an MSI, you can add ARPSYSTEMCOMPONENT=1 to the command line. This will have the same effect as the manual sequence described above.

Stealth Google Chrome 34

Description

For those who are not able to install Google Chrome on their work PC, due to proxy blocking the original installer or due to lack of permissions, I’ve created a stripped-down version of the Chrome installation.

Also, some corporations forbid browser alternatives, forcing you to use Internet Explorer. Usually, they scan the users’ PCs and send them warnings (or worse) if a “forbidden” software is found installed. This version tries to be as stealth as possible while keeping the complete functionality. Some files are renamed, some others removed. Registry info is also changed so that SCCM (or other tools that might be used) won’t be able to find it. Of course, this doesn’t mean it is completely stealth, but you have a fair chance of getting away it with. 🙂

 

Installation

If you have admin permission, download it here.

If you do NOT have admin permissions on the PC, then download this version.

The installation will run unattended. There is no interaction needed.

If you want to install the application in a different folder than the default one (chosen by us), use the following command line:

msiexec /i [full_path_of_MSI] INSTALLDIR=[your_desired_installdir_here]

 

Updates

Please note that this version will NOT be able to install updates automatically. Therefore, please check our *Stealth Google Chrome Download page* on a regular basis, for package updates.

 

Removal

Right click on the MSI file and select Uninstall to remove it, or go to Add/Remove Programs and remove it from there (Stealth GC).