CustomActionData

December 18, 2008

This topic is one which is a little overdue, I started something and never finished it. The last couple of posts were a lead up to this.
 
I discussed a little about the client / server side of the Windows Installer service and the related security concepts around the Immediate / Deferred phases. I bring this up as time and time again I see Installers which blatently ignore these issues. I see packages which don’t take into account the security concepts of the Installer service. More often than not this is due to a complete lack of clear and readable information about the topic.
 
I am going to attempt to resolve that issue here and now but bear with me there is alot happening and it can be a little difficult to grasp.
 
One of the key points I mentioned in the previous post was that you should only modify the system using a Deferred Custom Action. This is what I like to teach as the golden rule of packaging. If your going to write registry, edit copy delete files you need to do this during the deferred phase. Because this is the only time you have access to the elevated server side portion of the Windows Installer service. This is highly important if you even intend to deploy your packages to a locked down environment or a Windows Vista or later OS.
 
Lets run through a few examples of good and bad configuration.
 
1) Editing an XML that exists prior to installation.
 
Lets assume we already have a file installed on a machine such as:
 
c:\program files\testapplication\myXmlFile.xml
 
We now want to edit this xml file and for the sake of this demonstration we will have a simple vb script to do this job. (yes there are better ways but I want to keep this simple for the demonstration).
 
Our VB script my be something very simple such are editing an attribute in the xml such as a server name.
 
set objNode = objXmlDocument.SelectSingleNode("//Environment/ServerDetails")
set objAttribute = objNode.SetAttribute("ServerName", session.property("ServerName"))
 
We pop in a Windows Installer property of [ServerName]
 
Now as this file already exists on the machine some people may argue an Immediate CustomAction would suffice to edit this file. Interestingly enough this run as an immediate CustomAction may work in many cases. Here’s why.
 
a) the file exists already so no issues with the file not being present during installation
b) vb script is ok to edit the file
c) ServerName property is present during immediate phase
 
Ok so looking at this chances are it could work ok. Running a test installation potentially works as well. So whats the issue you ask ?
 
Ok now lets throw a little complexity into this cycle. Now try to install this on a user account with limited access, in particular no access to edit c:\program files\*. We run this same successful installation under a locked down user account the result is. FAIL
 
The locked down user no longer has access to edit the file and as such security permissions on the machine deny access to the file causing the CustomAction to fail. Initiating a rollback of the installation and resulting in a failed installation.
 
So what do we do now ?
 
Ok lets try the same scenario in deferred phase using the elevated CustomAction.
 
a) the file exists already so no issues with the file not being present during installation
b) vb script is ok to edit the file
c) user has access to file as running in local system elevated context
d) ServerName property is not present during deferred phase
 
The result being the file is edited successfully dropping a blank value into the ServerName attribute of the xml.
 
So whats the go now ? Neither solutions work ?
 
Immediate phase fails due to access rights.
Deferred phase fails due to properties not being available.
 
So now we are in a catch 22 situation, how do we work around this. Remember earlier I stated the golden rule as editing the system must be done during the deferred phase ? Was I wrong about this or is there something missing from the equation ?
 
The solution is a concept referred to as CustomActionData. CustomActionData is a special property used to retain property values within the deferred phase. The idea being a simple throw and catch scenario. Where the data you need to use from the Immediate phase is thrown across into the Deferred phase. Initially this process seems a little complicated but once you get your head around it like everything it becomes very simple.
 
The requirements are as follows.
 
1) need to edit the system only during the deferred phase
2) need properties which are only available during the immediate phase but run during the deferred phase.
 
So how do we achieve this ???
 
The process is like this.
 
1) Collect  properties required during the immediate phase
2) Throw those properties across into the deferred phase
3) Catch the properties in the deferred phase
4) Run our CustomAction to edit XML using the catch results from previous steps
 
Seems pretty simple when you put it like that huh.
 
Technical Implementation
 
1 & 2)  Use a Set PROPERTY CustomAction to set a property that will be access during the deferred phase.
 
For example
 
Create a PROPERTY called SERVERNAME with a value of TEST
Set Property called DEFERREDVALUE = [SERVERNAME]
 
The above CA would create a new Property called DEFERREDVALUE with a value of [SERVERNAME] which has a value of TEST. The net result being
 
DEFERREDVALUE=TEST
 
Now we have completed the first portion of throwing values across into the deferred phase so how do we catch those values on the other side. The answer is.
 
We now need to access the CustomActionData property. This is a special property which gains its value from the name of the CustomAction in the deferred phase.
 
To access the CustomActionData property we do this.
 
strServerName = session.property("CustomActionData")
msgbox strServerName 
 
This took me a little while to come to grips with as the documentation in the SDK is pretty light. your probably wondering at this point how does CustomActionData contain the correct property. There are plenty of properties in default packages so how does CustomActionData access the correct one. The trick to this is the name of your CustomAction.
 
If the customAction we setup in the Deferred phase is called
 
DEFERREDVALUE then the CustomActionData property will contain the value of the property DEFERREDVALUE which in this case = TEST.
 
If the name of the CustomAction is called SERVERNAME then the CustomActionData property will = the value of SERVERNAME.
 
I know this seems like a multitude of additional steps when one could argue that an immediate CustomAction after InstallFinalize would suffice. But this is the only way to obtain access to the elevated context of the Windows Installer Server process. This in turn means it is the only way to successfully deploy to a locked down environment.
 
So to cut a long story short if your currently writing CA’s to edit the system during the immediate phase you need to change your practice and implement the CustomActionData solution.
 
Yeah sure its alot more difficult, it involves a few more steps and is a little fiddly but the results are your installation should work in any state of lock down.
 
This is quite a bit to chew over so have a read let me know if this makes any sense at all and I will follow up with some real examples of how this can be implemented. (I dont have an editor with me atm to create some samples for you).
 
Please give me some feedback on this one as its hard to know if I covered it off clearly its a pretty muddy topic to cover without a whiteboard.
 
 
 
 
 
 
 

8 Responses to “CustomActionData”

  1. Phil Says:

    Hi John,the reason why allot of packagers add all their CA\’s in the immediate seq. is the ability to access all of the properties, which of course is not possible in the deferred seq. And of course the "un-knowledge" of the MSI technologie as a whole.Have you had a look at the XML dll of Wix to edit existing xml files? The documentation is a bit confusing, but it can be added to any installe project…CheersPhil

  2. Bruce Says:

    Thanks for the post Johnny, just had a quick glance at this and it made more sense than what was described on the MS site :-)

  3. John Says:

    hi Phil, I am aware of the xml edit capabilities of WiX and I use it regularly. This is more so a demonstration of how to use CustomActionData opposed to a demonstration of how to edit XML files. I just couldnt think of a good example at the time so this is what I decided to run with. I haven\’t yet reverse engineered the CA\’s yet I expect it will show some interesting items. Cheers, John

  4. Owen Says:

    lack of property availability is the main reason I have avoided Deferred phase custom actions. CustomActionData is a pain to work with. I\’ll have a look though next time this comes up…thanks!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.