Passing property values in Remove action using UAB for MSIs
Problem: An application which you are developing is using UAB (Updater Application Block) to pull in updates from a server. There is a requirement to uninstall the application using UAB with the help of an MSI, but the uninstall needs to happen conditionally so that, based on the value of a property, parts of the uninstall steps are skipped. The issue now is that the infrastructure that the UAB provides does not allow us to pass property-value pairs using the MsiProcessor to invoke the msi uninstall action AND pass some property=value pairs.
Solution: The usual way in which a manifest is authored for a msi processor to use the Remove action will be something like:
<?xml version="1.0" encoding="utf-8" ?>
<manifest manifestId="{311085F7-9320-4318-9A67-9BE32F04E933}" mandatory="True"
xmlns="urn:schemas-microsoft-com:PAG:updater-application-block:v2:manifest">
<description>TestUAB Manifest</description>
<application applicationId="{215E1AD7-9ABA-432f-A952-24BABA556850}">
<entryPoint file="" parameters="" />
<location>.\..\..</location>
</application>
<activation>
<tasks>
<task name="MSIProcessorInstall" type="Microsoft.ApplicationBlocks.Updater.ActivationProcessors.MsiProcessor, Microsoft.ApplicationBlocks.Updater.ActivationProcessors" taskId="{425E1AD7-9ABA-432f-A952-24BABA556850}">
<config>
<installType>Remove</installType>
<productCode>{F7924949-7D0A-47E5-B133-AD2CC5C081F4}</productCode>
<uiLevel>msiUILevelDefault</uiLevel>
</config>
</task>
</tasks>
</activation>
</manifest>
The one glaring mess-up (uhum... miss-up) is that unlike the Install action, there is no provision to pass propertyValues to the Remove action! There are two things that need to be done for the UAB MSI uninstall or rather the remove action to recognize the various property values being passed.
Modify the MsiProcessor.cs found in Microsoft.ApplicationBlocks.Updater.ActivationProcessors (aka ActivationProcessors project)
Modify the RemoveProduct(...) to include the follow bits of code...
session = installer.OpenProduct( productCode );propertyValuePairs = this.GetPropertValuePairs(propertyValues);for (int i = 0; i < propertyValuePairs.Length; i++)
{
string[] parts = propertyValuePairs[i].Split('='
);
session.set_Property(parts[0], parts[1]);
}
session.DoAction( "INSTALL" );
...And, in the same class put in the definition for parsing the property values
private string[] GetPropertValuePairs(string propertyValues)
{
string[] propertyValuePairs = propertyValues.Split(' ');
return propertyValuePairs;
}If this doesn't make much sense the full code is attached along this post!
Modify the Manifest to include the propertyValues tag
Once the MsiProcessor is modified, we need to tag a tag to the manifest so that we will be able to pass on the property to the msiexec.exe process which actually hadles all requests for MSI actions. (Again, refer the RemoveManifest.xml attached in this mail)
That's all folks... you are up and running.