Preserving properties used during install

Русская версия здесь.

 

One of the most common questions is how to preserve the value of property used during install (either passed through command line or properties like INSTALLLOCATION which can be changed in the UI) so that it can be used during maintenance or uninstall.

For example, here is one of the possible situations.  Consider this very simple example.  The idea here is that user passes the value to be written in the xml file through command line parameter.  We need to make sure that during repair that value will be preserved in the xml file.  Here is the source WiX file:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi"

     xmlns:util="https://schemas.microsoft.com/wix/UtilExtension">

  <?define UpgradeCode="{D1C829D8-5A5B-412C-90ED-7F92750F8152}"?>

  <?define CurrentVersion="1.0.0.0"?>

  <Product Id="*"

           Name="PreserveProperty"

           Language="1033"

           Version="$(var.CurrentVersion)"

           Manufacturer="PreserveProperty"

           UpgradeCode="$(var.UpgradeCode)">

    <Package InstallerVersion="200"

             Compressed="yes"

             InstallScope="perMachine"

             Languages="1033" />

    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

<!-- Make sure properties are passed in the command line -->

<Condition Message="MYPROPERTY variable must be set in the command line">

Installed OR MYPROPERTY

</Condition>

    <!-- Installation -->

    <Directory Id="TARGETDIR" Name="SourceDir">

      <Directory Id="ProgramFilesFolder">

        <Directory Id="INSTALLLOCATION" Name="PreserveProperty">

          <Component Id="ProductComponent"

                    Guid="cf13f922-e33c-4b78-a849-46e32c000e09">

            <File Id="XmlFile"

                 Name="test.xml"

                 Source="test.xml"

                 KeyPath="yes" />

            <util:XmlFile Id="SetMYPROPERTY"

                  Action="setValue"

                          ElementPath="//config/parameter[\[]@name='MyProperty'[\]]/@value"

                          Value="[MYPROPERTY]"

                          File="[#XmlFile]" />

           

          </Component>

        </Directory>

      </Directory>

    </Directory>

    <Feature Id="ProductFeature" Title="PreserveProperty" Level="1">

      <ComponentRef Id="ProductComponent" />

    </Feature>

  </Product>

</Wix>

To make sure MYPROPERTY is in the command line we will be using Custom Action Type 19 (<Condition> element).

Installer will install test.xml file and update value of the attribute to value of MYPROPERTY property.  Here is the content of test.xml:

<config>

 <parameter name='MyProperty' value='' />

</config>

If you will compile this sample and install it, you'll see that test.xml is created and its value is set to provided value in the command line.  Try it with the following command line:

msiexec /i PreserveProperty.msi MYPROPERTY="123"

You can also try to install it without providing MYPROPERTY.  Installation should fail with error message from <Condition> element.

Now, after installation is done, try to repair the installation.  After repair is completed, open test.xml.  You will see that the value of attribute is empty.  The problem is that during repair MYPROPRTY="123" is not passed to msiexec.exe.  It is our responsibility to preserve the value of property passed to msiexec.exe during initial install.

Let's modify our WiX file to:

  1. Save the value of property in registry during initial installation
  2. Recover saved value from registry during AppSearch
  3. Set the value of MYPROPRTY to value recovered from registry provided that this is NOT initial install

First item is straightforward:

<RegistryKey Id="PreservePropertyInRegistry"

  Root="HKLM"

  Key="SOFTWARE\ACME Corp" Action="createAndRemoveOnUninstall">

  <RegistryValue Id="SavedProperty"

  Action="write"

  Type="string"

  Name="SavedProperty"

   Value="[MYPROPERTY]" />

</RegistryKey>

Second item is just plain vanilla RegistrySearch: 

<Property Id="SAVEDMYPROPERTY" Secure="yes">

  <RegistrySearch Id="FindSavedMYPROPERTY"

                  Root="HKLM"

                  Key="SOFTWARE\ACME Corp"

                  Name="SavedProperty"

                  Type="raw"

                  Win64="no" />

</Property>

Third item is simple <SetProperty> (or Custom Action Type 51, if you still use V2), but conditioned to be executed during all types of install other than fresh install:

<SetProperty Id="MYPROPERTY" After="AppSearch" Value="[SAVEDMYPROPERTY]">

  Installed

</SetProperty>

Source code for this sample is in attachment. 

 

PreserveProperty.zip