1
votes

I'm working on adding a feature to our WIX-based installer. It's my first time working with WIX so it's all quite new to me.

What I'm trying to do is allow users to pass an auth token command line argument when using msiexec.

The installer will then make an API call with the auth token. If the auth fails, the installer will terminate. Otherwise, the installer will download a file using the API and copy it over to the install directory (most likely under Program Files).

I've managed to read in the command line arguments as properties in WIX and have created a CustomAction in C# to handle the authentication / downloading the file.

The part I'm struggling with is getting the CustomAction to copy the file into the install location, as it doesn't have privileges to write to the location.

I can have it run with elevated privileges by setting execute="deffered" and "impersonate=no however that prevents me from reading in properties from the session object.

Another possible option is to save the file to a temp location in the CustomAction (which works without elevated privileges) and set a new property. Then I can use the CopyFile component with SourceProperty to copy that file to the target location.

I'm unable to figure out, however, how to get the CustomAction to run before the CopyFile component, as the property wouldn't be set until after the CustomAction has been run. Is it as simple as simply running running the CustomAction before a specific part of the install, or is there more to it?

1
It should be as easy as scheduling it before "MoveFiles" (wixtoolset.org/documentation/manual/v3/xsd/wix/copyfile.html mentions the DuplicateFiles and MoveFiles tables and I assume it uses the MoveFiles table when you define a CopyFile that doesnt reference a File element's ID) but I am adding an answer that should let you run your customaction deferred and download the files to the install directory.Brian Sutherland

1 Answers

1
votes

You can still read properties from the session object during a deferred custom action you just need to define your public property passed in on the command line as Secure="yes" and then make a second custom action that runs before your deferred custom action to set the CustomActionData property for your deferred action so that it can read the value of the public property during execution.

You'll need to define something like this

<Property Id="AUTHTOKEN" Secure="yes" Hidden="yes" />

<CustomAction Id="AuthenticateDownload" BinaryKey="CustomActionsDLL" DllEntry="Download" Execute="Deferred" Impersonate="no" />
<CustomAction Id="SetAuthenticateDownload" Property="AuthenticateDownload" Value="AUTHTOKEN=[AUTHTOKEN];INSTALLDIR=[INSTALLDIR]" />

<InstallExecuteSequence>
    <Custom Action="SetAuthenticateDownload" Before="AuthenticateDownload">NOT Installed AND NOT UPGRADINGPRODUCTCODE AND NOT REMOVE~="ALL"</Custom>
    <Custom Action="AuthenticateDownload" Before="InstallFiles">NOT Installed AND NOT UPGRADINGPRODUCTCODE AND NOT REMOVE~="ALL"</Custom>
</InstallExecuteSequence>

And to access your passed in property values inside the custom action you now need to use

string AuthToken = session.CustomActionData["AUTHTOKEN"];
string InstallDir = session.CustomActionData["INSTALLDIR"];

... try download to installdir ...

A few things you need to consider for passing properties to a deferred action is that you must use a "Set" action which sets a property with the EXACT name of the CustomAction's Id that you want to use it in. Then you use a comma-separated list of PropertyName=PropertyValue which is formatted meaning you can use installer properties in []'s as values.

The conditions on the custom actions will let this custom action run only when you are installing a new product on the machine (not uprgrades or removal). If you only ever want the action to run on the first install and not on upgrades just throw a AND NOT WIX_UPGRADE_DETECTED in there.

Don't forget to add an opposite custom action to remove these files on uninstall so that you don't leave things behind.