Monday, June 27, 2005

All About Properties

Late last week an anonymous poster commented it has been a while since my last blog post. I'm going to attempt to make up for it with this rather long post as the first in a short series on MSI Properties. Newbies to MSI technology have a difficult time understanding them, and even experienced setup developers get burned by forgetting something. Let's start by looking at some of the basic properties of, well, Properties.

Properties are sort of like variables. Properties cannot have spaces in their name and must begin with a letter or underscore. All properties can be defined in the Property table or set by other mechanisms – via AppSearch, Custom Actions, dialog control elements, etc. They have scope: Public, Private, and Restricted. Cosmetically, Private properties have lower case letters, Public properties are all uppercase. Under the hood, there are plenty of differences. I am going to ignore the Win9x and Terminal Server aware differences and concentrate on the NT based MSI engine.

We first need to cover something I should have covered in an earlier blog post – the MSI engine's UI phase and execution phase. The UI phase (sometimes also referred to as the 'acquisition phase') is carried out in the current logged on user's context. The execution phase (sometimes also referred to as the 'server process' or 'server side', or simply 'service' – lets hear it for MSDN documentation consistency!) is carried out in a completely different process (or processes). This is pretty easy to see for yourself – write a custom action that pops up a message box with the current process ID and run it in three different contexts – UI (Immediate), Execute (Immediate), and Execute (msidbCustomActionTypeNoImpersonate + msidbCustomActionTypeInScript). If you are an administrator, you will notice that the UI action runs in one process and the execute actions run in a different process – all owned by the interactive user. If you are a non-admin user, you will note that each of the three actions run in their own separate process, with the difference being the "NoImpersonate" action, which runs in the SYSTEM context.

Back to the property discussion – Private properties have lower case letters as stated earlier. They cannot be passed into an installation via the command line method or modified by transforms. Predefined Private properties may be set by the MSI engine – see "Property Reference" in the MSI docs for a list of properties set by the MSI engine automatically. Private properties can be changed by Custom Actions, although you likely do not want to change one of the predefined private properties. One last important distinction is that changes to private properties are NEVER passed from the UI phase to the Execution phase. Although there may be a reason to use a Private Property for something, I have never created a private property for use in an installation.

Public Properties are a bit more useful. There is a slight difference between Public and Restricted which I will cover next. For the purposes of this paragraph, treat them as synonymous. Public Properties must contain all uppercase letters. They can be set via the command line and modified by transforms. Public properties CAN be passed into the execution phase, and the key word here is CAN (more on this later). Also, values of properties are NEVER passed from the execution phase back to the UI phase when the execution phase is done processing – so if the value of a property is changed in the execution phase, it is not reflected in the UI phase afterwards.

Restricted, or Restricted Public Properties, are Public properties with the distinction being purely based on system or user state. Looking at an out-of-the-box Windows installation and a generic template MSI installation the following statements apply: If you are an administrator running an installation, properties WILL be passed to the execution phase (Restricted public property behavior). If you are not an admin user, most public properties WILL NOT be passed to the execution phase (normal public property behavior). If you want ALL properties set in the UI phase to pass to the execute phase (i.e. you want all public properties to be restricted), enter a property into the property table "EnableUserControl" and set it to "1". This setting can also be set as a system group policy by a network administrator. Alternatively, each property that you want to allow to be passed into the execution phase (made Restricted) can be specified in another entry in the property table called "SecureCustomProperties" which is a semicolon delimited list of public properties. By default, some properties are set to be restricted, see the "Restricted Public Properties" list in MSDN. This concept is a bit confusing, as the "Restricted" properties are the ones allowed to transition from UI to execute phases, even though you may think the opposite when first hearing the term.

The concept of "Restricted Public Properties" is rather important for your installation to work if installed by a non-admin user via group policy style deployments. It is highly advisable to test your installation for this deployment type by creating a local admin user and setting both HKLM and HKCU Software\Policies\Microsoft\Windows\Installer "AlwaysInstallElevated" (DWORD) to 1. Then take the user out of the admin group. This will have the effect described above. Test your installation in this configuration to make sure it functions correctly.

There are more fun tidbits about properties…

First, all entries in the directory table are accessible as properties. Therefore, be sure not to run into naming clashes when determining your property names. Be sure not to rely on the directory properties until after CostFinalize has been run.

Some properties, if authored into the Property table, result in an ICE validation warning. The documentation for ICE 87 explains some of them. Other properties in this table are validated with ICE 05, ICE 16, ICE 24, ICE 74, ICE 80, ICE 86, ICE 90, and ICE 99. I found it useful to review all the ICE's when learning MSI, since it locks in the "don't do this" mentality before you try something and it later fails...

You can set the "MsiHiddenProperties" Property to a list of semicolon delimited properties that should not be placed into the install log. This only works on MSI 2.0 or greater schemas, and is really not a good means to secure vital information, such as passwords or product codes.

Many Properties (and several Windows Installer API's) are not available to a custom action running deferred. To pass a property to a deferred custom action, use a type 51 custom action to set a property with the name of the deferred custom action you want to pass data into, sequenced prior to the deferred action in the execute sequence. In the deferred custom action, you can access this property by getting a property called "CustomActionData". Since you typically need to pass more than one property to a custom action, the technique of stuffing a bunch of properties together and later separating them is commonly used.

Any property value that is changed during the installation process is not preserved or persisted – thus, properties that were set during installation are not present when uninstallation occurs. IMHO, not providing a built-in persistence mechanism is a serious oversight made by the MSI team.

Speaking of persistence, the "AdminProperties" property is one way to persist a property – albeit only during an administrative installation. To allow this behavior, add the property you wish to set into a property called "AdminProperties" in the usual semicolon delimited list manner. When a user runs an installation after it was deployed to an administrative installation point, these properties are loaded with their saved values – a good easy way to provide default values specific to an enterprise without developing a transform.

The last important thing to realize about properties is their "Order of Precedence". Essentially, this describes when a property is set. I'm going to list these in the reverse order as MSDN does, as it makes more sense to do so. A property can potentially start its life as an entry in the Property table. If a transform was applied to the MSI, this will change what was described in the Property table. Next, the saved properties from an administrative installation that were listed in the "AdminProperties" property are restored. If anything was specified on the command line, those properties are used. Finally, operating system properties are set. To illustrate by example, if you declare property FOO to be "prop table" in the property table, then run the installation from the command line by "msiexec /I test.msi FOO=cmdline" FOO will be set to "cmdline" since the property is set by the command line AFTER it was set by reading the property table.

My next blog entry will discuss some techniques to persist properties and their data across installation sessions.