Windows Installer Useful Advice

VBScript Custom Actions are Not Windows Script Host
It's a common assumption that VBScript CAs can use WSH constructs based on the WScript object model. But you cannot use script code such as WScript.CreateObject or WScript.Quit or WScript.Echo. The WSH environment provides the WScript object model, just as VBScript in a Web page uses an IE object model. Windows Installer scripting supplies objects such as the Session object for interacting with the install. You don't need WScript.CreateObject anyway—VBScript has a CreateObject method that does the same thing.

Msiexec Command Line is Picky
When you're sure that the syntax of your command line is correct, but you still keep getting errors saying that the command line is incorrect, watch out for extra spaces that cause this error.

Public properties cause the most trouble. In a command line such as one of these, the extra space between the "=" and the value of the property causes the command line to fail:

Msiexec /I my.msi TARGETDIR= c:\MyPath
Msiexec /I my.msi TRANSFORMS= c:\trans.mst

Services and Environment Variables
The mechanism that distributes changes to environment variables doesn't work for Services because the Service Control Manager (SCM) doesn't respond to the notification messages that Windows broadcasts. Services pick up their environment variables from the SCM, which means that if you install a Windows Service that expects to see newly installed environment variables, it won't see them. The only way to make them visible is to restart the SCM, which means rebooting the system. Consequently, you shouldn't design Services that require environment variables to be assigned in the same install.

Changing the Product's Uninstall Behavior
You might have noticed Registry entries under the HKLM\Software\Microsoft\ Windows\CurrentVersion\Installer\UserData\Products key with an Msiexec command string associated with the name UninstallString. You might have tried to update this string to make your product behave differently during the product's uninstall, only to find it makes no difference to the behavior. You can't make a difference to the Add/Remove Programs behavior by altering this Registry string because the uninstall is initiated internally by calling APIs that are passed the ProductCode GUID, not by reading this UninstallString. If you look carefully at the Registry entries in this region, you'll notice that some products don't even have an UninstallString; that's because it isn't a requirement. In effect, you can't alter this behavior and neither should you try to; users expect common behavior from all uninstalls.

Services and Remote Computers
If you're installing Services on Windows NT 4.0, note that NT 4.0 Services that run with the LocalSystem account have restricted access to network shares and other resources on remote computers. This account has less access than the Guest account. It seems to be a common design practice to develop a piece of code that accesses remote computers, and then, when it works, to embed it in a Service only to discover it no longer works. The install process might get involved at this point because an obvious solution is to install the Service with a user account and password that does have access to the remote computer.

ResolveSource and the Original Install Package
The ResolveSource action determines where the package is running from (and accesses it), and sets the SourceDir property, the path to the package. This is useful when you have a CA that needs to find files in the same folder as the package being installed. If you add a ResolveSource action to your install sequence, be sure to condition it on Not Installed. If ResolveSource is unconditional, it will get called every time the sequence is processed. The most inconvenient example of this is if you're trying to uninstall a product and it asks you to insert the product CD or otherwise locate the original package.

There's an alternative to the SourceDir property. The OriginalDatabase property contains the path to the package being installed, including the name of the actual MSI file, and is always available. However, this is useful at install time but not in subsequent maintenance installs because OriginalDatabase often points to the cached MSI file, not the original installation path.

Your Custom Action Won't Run as System Account
You can run deferred CAs with no impersonation by using the msidbCustomActionTypeNoImpersonate bit in the CA Type. Sometimes you'll find that CAs that were intended to run with no impersonation will run with the installing user's account and behave unexpectedly. This can happen if the install isn't managed. The UI is typically where the user gets to choose between a per-machine and a per-user install, and this UI choice sets the value of the ALLUSERS property. But if there's no UI there's nowhere to set per-user or per-machine, and the default Windows Installer setting is per-user, so you need to be careful that your installs don't become per-user and unmanaged when you install them silently.

The way to ensure that your install defaults to the required behavior is to hard-code the value of ALLUSERS in the Property table, giving it a value of 1 if you want the default to be a per-machine install.

Bootstrappers and Temp Folders
Many install development tools let you build a bootstrap executable that first makes sure the Windows Installer engine is on the system (the Windows 9x or NT versions) and then extracts the embedded package—the MSI file—and installs it. One of the problems with this scheme is that the MSI file sometimes gets unpacked to the system's Temp folder where it can be removed all too easily. If the file is needed for repair or modification of the product, it's gone, and you might see error 1706 and dialogs asking you for the location. The moral of this story is to try to control where the unpacked MSI package is stored, and don't use the Temp folder.

Raising Privileges During Custom Actions
A process can normally raise its privileges to perform actions that require those privileges. The Windows security model doesn't automatically assign all allowed privileges to a process. Instead, the process is allowed to assign them to itself if necessary. The API that does this is AdjustTokenPrivileges.

If you do this during a CA in the InstallExecuteSequence (such as a deferred CA DLL call from a VS setup project), it doesn't work. You won't necessarily see any failures reported from the security APIs, but the action requiring the privilege returns error 1300, meaning that "Not all privileges referenced are assigned to the caller." However, you can make this work by having the CA run deferred in the system context, so a Type 3073 CA DLL call succeeds (a Type 1 call to a CA DLL function + 3072, msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate).

The issue is related to the local DCOM calls that are occurring internally within the installation processes. Your deferred CA running as the installing user is being called via a local DCOM call from the installer's Service process. DCOM removes disabled privileges during this call sequence, so your CA code is running in an environment where the only privileges you can use are those that are already enabled. You don't have access to the disabled ones that you want to enable. You can make AdjustTokenPrivileges calls during the UI sequence because your immediate CA code is running from the calling Msiexec user process (or from the program invoking your install through an API call) and no DCOM calls are involved.

Use Unique Property Names
When you choose names for your custom properties, be careful that you don't inadvertently choose an identifier name that's the same as a standard but perhaps undocumented property. For example, Windows Installer uses the DATABASE property to name the working package file name. Not only do you need to avoid these kinds of names, you also need to avoid any properties that the development tool added to your package. So, for example, you see property names that VS created, which are usefully prefixed with VS in all the cases I could find.

Perhaps the best place to see these properties, apart from the documentation, is in a log of the installation.

Source of Information : Apress The Definitive Guide to Windows Installer


Subscribe to Developer Techno ?
Enter your email address:

Delivered by FeedBurner