The "PropertyCa" Command |
This command is used to create or update the value of a Windows Installer property (or directory key).
This command differs from the "Property" command in that the property assignment is scheduled as a custom action type 51 (or 35 for directories). This allows you to "capture" the current value of properties at runtime.
This command takes these parameters:
You should use "*VALUE" if you have a VBSCRIPT expression which resolves to a string (use "cstr()" if you get a type mismatch).
Any MSI formatting will be replaced which is a major difference from the "Property" command.
This should be Y/N, "Y" indicates that the "property" is a directory key in the ("Directory" table).
If you want to set the location of a directory then you you need to look at where you wish to sequence it, if this is after "CostFinalize" then pass "Y" to this parameter else pass "N" ("CostFinalize" will apply the property of the same name to the directory).
There will typically be a lot of standard actions at known fixed locations (which may however differ in sequence number or even order relative to one another with different templates). Click here for the default "InstallExecuteSequence" and "InstallUISequence" sequencing details.
Normally you try not to duplicate sequence numbers but it is probably OK to do so as long as you don't care which one executes first! One possible exception would be deferred custom actions where the custom action data needs to be setup before execution. You should get a validation message to indicate a duplicated number (note that validation can't know whether custom action conditions are mutually exclusive etc).
The sequencing information (see some default sequencing) can be supplied in a number of formats:
Basically you describe a range of valid values and whether you prefer the value to be chosen from the lower (default) or higher end.
The range should be specified in the format "lower - higher". Either value can be omitted, be specified as an integer such as "1000" or the name of an action such as "InstallFiles". The default value for the lower end is "1" and for the higher "32767" and leading and trailing spaces for each are stripped. The minimum and maximum values can be returned as the range is inclusive.
By default MAKEMSI will choose a number as close as possible to the lower end, if you wish it to be as high as possible then begin the specification string with "<".
Some Examples:
You should of course be aware of what your script does, for example if it moves a custom action that you have already sequenced other actions relative to then that would probably be "bad"!
I have captured a large number of "sample properties" which could be used in any conditions. Note that the values of some properties may not be available at all times and in some cases are modified during processing.
You can also use any of the following predefined conditions:
#define? CONDITION_ALREADY_INSTALLED Installed ;;Repair, uninstall etc. #define? CONDITION_INSTALL_ONLY not Installed ;;Doesn't include a repair, uninstall etc! #define? CONDITION_UNINSTALL_ONLY Installed and REMOVE~="ALL" ;;Complete uninstall - HIGHLY RECOMMENDED at you read the "REMOVE" properties MAKEMSI doco! #define? CONDITION_EXCEPT_UNINSTALL not (<$CONDITION_UNINSTALL_ONLY>) ;;Install, Repair etc (all but complete uninstall) #define? CONDITION_IS_WIN2000 VersionNT = "500" ;;Is OS WIN2000? #define? CONDITION_IS_WINXP VersionNT = "501" ;;Is OS WINXP? #define? CONDITION_IS_VISTA VersionNT = "600" ;;Is OS WINDOWS Vista? #define? CONDITION_IS_WINDOWS_7 VersionNT = "601" ;;Is OS WINDOWS Windows7 #define? CONDITION_UI_NONE UILevel = 2 ;;Silent Install #define? CONDITION_UI_BASIC UILevel = 3 #define? CONDITION_UI_REDUCED UILevel = 4 #define? CONDITION_UI_FULL UILevel = 5 ;;"Normal" #define? CONDITION_UI_NO_DIALOGS UILevel <> 5 ;;Don't bother user with popup dialogs, opening readme files etc. #define CONDITION_PER_MACHINE Version9X or (ALLUSERS = 1) ;;True if per-machine install. #define CONDITION_PER_USER not (<$CONDITION_PER_MACHINE>) ;;True if per-user (not per-machine) install.
This parameter accepts one or more space separated attributes which are processed in left to right order. Available attributes are (not all may apply):
A deferred (in-script) custom action must be sequenced between the "InstallInitialize" and "InstallFinalize" actions (or you will get a 2762 error) and data is passed via the "CustomActionData" property.
All deferred actions are executed in a single pass by the server "MSIEXEC.EXE" service (a separate process) after being combined in a "script".
All immediate custom actions scheduled between the "InstallInitialize" and "InstallFinalize" actions (regardless of their sequence number) are executed before deferred ones.
This should only be used as a last resort when executing some poorly written piece of "cr*p" (or perhaps if it's success is not critical to the install).
Rollback custom actions (and so also the "worker" custom action) must be "deferred" and sequenced between "InstallInitialize" and "InstallFinalize".
There are circumstances where a custom action may still run with system privileges.
Lack of this attribute on deferred custom actions is a common reason for failures on Vista.
The CustomActionData property is also not logged when the installer executes the custom action.
Because the installer sets the value of CustomActionData from a property with the same name as the custom action, that property must be listed in the "MsiHiddenProperties" property to prevent its value from appearing in the log.
If the number begins with "0x" (case insensitive) then the number is being supplied as a hexadecimal value otherwise its interpreted as being in decimal.
You may need to supply a numeric value such as "+0x0001" if I haven't provided a suitable alias above...
EXAMPLE |
This example show how the "CustomActionData" property is set up prior to calling a deferred custom action. Note that to do this I set the "key" on the "VbsCaSetup" command so I knew exactly what the key was, I then created a property of the same name, Windows Installer will do the rest.
In this case I am passing two properties, the custom action will need to separate these values, painful but required.
<$PropertyCa "MyCa_Install" Value="[INSTALLDIR];[SecondProperty]" Seq="InstallFiles-"> <$VbsCaSetup Key="MyCa_Install" Binary="MyCa.vbs" Entry="Install" Seq="InstallFiles-" CONDITION=^<$VBSCA_CONDITION_INSTALL_ONLY>^>
EXAMPLE - Overriding Installation Directory |
The following is an example where the installation directory is specified by an environment variable but it could just as easily have been created via an immediate "VbsCa" custom action.
Note that Windows Installer remembers the location for repair and uninstall (at least where at least one file is installed there).
#define ENVVAR_INSTALLDIR SOME_ENV_VAR ;;Name of environment variable containing a path... <$DirectoryTree Key="INSTALLDIR" Dir="C:\DummyLocation" CHANGE="\" PrimaryFolder="Y"> #( ;--- Check that the environment variable holding the install dir exists! --- <$AbortIf Condition=^%<$ENVVAR_INSTALLDIR> = "" and <$CONDITION_INSTALL_ONLY>^ Seq=^CostFinalize-^ SeqTable="InstallUISequence InstallExecuteSequence" Message=^The "<$ENVVAR_INSTALLDIR>" environment variable doesn't exist. We can't determine the installation directory.^ > ;--- Set the installation directory to the value of the environment variable --- <$PropertyCa "INSTALLDIR" Value="[%<$ENVVAR_INSTALLDIR>]" DIR="Y" Condition=^<$CONDITION_INSTALL_ONLY>^ Seq=^CostFinalize-^ SeqTable="InstallUISequence InstallExecuteSequence" > #) ;--- Install files ---------------------------------------------------------- <$Files "TryMe.*" DestDir="INSTALLDIR">
EXAMPLE - Macro to Find "WSCRIPT.EXE" |
;################################################################################## ;### Note that I have now created a "FileFindInListedDirs" command ;### which simplifies this and makes it more generic: ;### <$FileFindInListedDirs File="wscript.exe" DIRS="System64Folder;SystemFolder;WindowsFolder"> ;################################################################################## ;---------------------------------------------------------------------------- ;--- Macro to find "WSCRIPT.EXE" ;--- MS stupidly places this file in logically different locations ;--- ("C:\windows" in WIN98). Also just to make it more difficult it is not ;--- possible to search by attribute, or search path and thus not possible ;--- to avoid possible incorrect matches in fixpack backup directories. ;--- All in all nearly a handful of reasons to swear at MS in one go.... ;---------------------------------------------------------------------------- #( #define WSCRIPT.EXE ;--- Can't do this! Can find files in "$NtServicePackUninstall" type directories --- ;<$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE" PATH="[WindowsFolder]" Depth="1"> ;;Danger, Danger... ;--- Thanks MS... ------------------------------------------------------- <$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE.WF" PATH="[WindowsFolder]" Depth="0" Default=""> <$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE.SF" PATH="[SystemFolder]" Depth="0" Default=""> <$PropertyCa "WSCRIPT.EXE" Value="[WSCRIPT.EXE.WF]" Seq="AppSearch-" Condition="WSCRIPT.EXE.WF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence"> <$PropertyCa "WSCRIPT.EXE" Value="[WSCRIPT.EXE.SF]" Seq="AppSearch-" Condition="WSCRIPT.EXE.SF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence"> <$AbortIf Condition="not WSCRIPT.EXE and (<$CONDITION_EXCEPT_UNINSTALL>)" Message=^The file "WSCRIPT.EXE" was not found in the "[WindowsFolder]" or "[SystemFolder]" directories!^ SeqTable="InstallUISequence InstallExecuteSequence" Seq="AppSearch-" > <$PropertyList "SecureCustomProperties" Value="WSCRIPT.EXE"> #)
EXAMPLE - "*VALUE" Parameter |
The following shows the the "*value" parameter being used:
<$PropertyCa "CompileTimeBuild1" Value="<?CompileTime>" Seq="CostFinalize-"> ;;Date/Time of build start from PPWIZARD standard definition <$PropertyCa "CompileTimeBuild2" *Value="cstr( time() )" Seq="CostFinalize-"> ;;Time from VBSCRIPT expression (executed later during pass #1)