Add file to Wix installer if it exists - wix

I am trying to add a file to the installer like this in my main wxs file.
<ComponentGroup Id="Files" Directory="Bin">
<?if $(var.FILE_EXISTS) = "true"?>
<Component>
<Condition>$(var.FILE_EXISTS) = "true"</Condition>
<File Source="$(var.SourceDir)/file.txt"/>
</Component>
</ComponentGroup>
I'm passing FILE_EXISTS through candle.exe with the -d option
But its not taking effect. Its not getting added. It works when I don't have the conditions (just the File element). Any ideas?

As far as I understand, the condition you are talking about is a build-time condition. Basically, you would like to control whether the file in question gets into the MSI package.
If that's correct, then one mistake is the <Condition> element under <Component>. That's install-time condition, and only influences then the file is installed.
The other one is a pure syntax issue. The <?if?> directive must have the closing element.
Taking the above into account, your snippet might look like this:
<ComponentGroup Id="Files" Directory="Bin">
<?if $(var.FILE_EXISTS) = "true"?>
<Component>
<File Source="$(var.SourceDir)/file.txt"/>
</Component>
<?endif?>
</ComponentGroup>

Related

SourceProperty as Nested Directory in CopyFile

I want to copy two file from existing location to new location using WIX Installer.
INSTALLDIR and Destination Directory are already defined. And In SourceProperty for first I want to use INSTALLDIR\P\X\Y and In second I want to use INSTALLDIR\Q\X\Y
<ComponentGroup Id="aYML" Directory="INSTALLDIR">
<Component Id="CopyaYML" Guid="" Transitive="yes">
<CopyFile Id ="aYMLcopy" SourceProperty="INSTALLDIR\P\X\Y" SourceName="A.yml" DestinationProperty="Destination"/>
<CreateFolder/>
</Component>
</ComponentGroup>
<ComponentGroup Id="bYML" Directory="INSTALLDIR">
<Component Id="CopybYML" Guid="" Transitive="yes">
<CopyFile Id ="bYMLcopy" SourceProperty="INSTALLDIR\Q\X\Y" SourceName="B.yml" DestinationProperty="Destination"/>
<CreateFolder/>
</Component>
</ComponentGroup>
As \ is not allowed in WIX how to achieve this?
It has to be a property name, which has a limited character set of letters, numbers, and underscores. You could use a SetProperty custom action (type 19) to format a value using the directory ID and the file name, or even the [#fileId] property format, though that's not reliable in older versions of Windows Installer.
Before InstallFiles but after CostFinalize, you could do something like this:
<SetProperty Id="AYMLPATH" Before="InstallFiles" Sequence="execute" value="[ParentDirectoryId]A.yml" />
Though, it may be easier to just use the SourceDirectory attribute and specify the directory ID.
Copying files, though, can cause issues for some servicing scenarios. For example, if you copy files in a patch, the changes can't be rolled back. If the files are small, just duplicate the files. There are even tricks to duplicating the file records, but keeping a single file blob in a CAB, but is outside the scope of this answer.

WIX — Add files to both GAC and INSTALLFOLDER without changing the name

Despite the different Ids and GUIDs the following code refused to compile because the following components have the same name. Setting the Name attribute does the trick, but I don't want libraries to have different names in GAC and install folder.
So far I have circumvented the issue by creating a CustomAction that renames one of the components on install, but this clearly isn't optimal. Is there an out of the box solution?
<ComponentGroup Id="HistoryGroup" Directory="INSTALLFOLDER">
<Component Id="History" Guid="*">
<File Source="$(var.ProjectName.TargetPath)" KeyPath="yes"/>
</Component>
<Component Id="HistoryGAC" Guid="*">
<File Source="$(var.ProjectName.TargetPath)" KeyPath="yes" Assembly=".net"/>
</Component>
</ComponentGroup>
Give both file elements explicit unique Id attributes. For the one going to the GAC install it to another dummy folder that already exists. (Don't worry it won't get installed there, it'll go to the GAC.)

WIX one or more Conditional Component with predefined Variables

Hi based on Environments(UAT,TEST,DEV,PROD) and Server Specific(Server1,Server2..) I am filtering the config files.
<Component Id="cmp39F4D3AA1248B5FE5EB2F92D189B27E1" Directory="dirCFCE6D07D3330FE628276777F0488B18" Guid="{56788F77-A729-47CE-BBA4-9D7D7F175536}">
<File Id="fil10B3B7732D0DDBD4AA773E0B7F34D092" KeyPath="yes" Source="$(var.SDirect.B2CWeb.ProjectDir)Web.ProdBuild.Web1.config.xml" >
<CopyFile Id="SCopy_ConfigPROD1" DestinationProperty="DestFilesWebsiteFolder" DestinationName="Web.config" />
</File>
<Condition> <![CDATA[ENVPROPERTY~="PROD"]]></Condition>
</Component>
The Above component works fine; the ENVPROPERTY Property value is set through command line when Installing by MSIEXEC.
But When I change the above statement as below doesn't work where the Installer need to detect the computername or Servername where it gets installed and based on that the installer must make sure to deploy the above component or not.
<Component Id="cmp39F4D3AA1248B5FE5EB2F92D189B27E1" Directory="dirCFCE6D07D3330FE628276777F0488B18" Guid="{56788F77-A729-47CE-BBA4-9D7D7F175536}">
<File Id="fil10B3B7732D0DDBD4AA773E0B7F34D092" KeyPath="yes" Source="$(var.SDirect.B2CWeb.ProjectDir)Web.ProdBuild.Web1.config.xml" >
<CopyFile Id="SCopy_ConfigPROD1" DestinationProperty="DestFilesWebsiteFolder" DestinationName="Web.config" />
</File>
<Condition> <![CDATA[ENVPROPERTY~="PROD" AND ComputerName~="Server1"]]></Condition>
</Component>
Can any one help in setting the conditional statement which satisfies ENVPROPERTY="PROD" and ComputerName="Server1" ie the servername(Machine) the MSI package gets installed. So that above components gets deployed and not skipped when package gets deployed.
Thanks in advance
Public Properties only can be used in command line. All letters should be in upper case for public properties. Use ComputerName property as COMPUTERNAME like the other one.

WiX: Define a File component that may not exist

I need to define a Wix file component that may not exist in certain circumstances. Is there any way to do this? Condition elements in Wix all seem to work at install time, and I need something that'll detect at compile time if a file is present and build the installer accordingly.
It seems you need to check out the wix preprocessor. Check out wix documentation on the topic:
wix preprocessor
for example, suppose you have an environment variable called APPTYPE. If its value is set to 'Full', then MyApp_Full.exe will be included and processed by the wix compiler (candle).
<Component Id='MyComponent1' Guid='fff60f72-5553-4e6b-9bf0-ad62ab9a90b1'>
<?if $(env.APPTYPE) = Full?>
<File Name='MyApp_Full.exe' DiskId='1' Source='..\MyApp_Full.exe' Vital='yes' />
<?endif?>
...
</Component>
There is more! Variables, defines, conditionals. Check out that doc page.
As iwo said, preprocessor variables are your friend! However the example from iwo can (and will) violate component rules, as the component isn't 'stable'. Better to condition an entire component (or component group)...
<?if $(var.releasetype)=full ?>
<ComponentRef Id="Somefile.dll" />
<?elseif $(var.releasetype)=enterprise ?>
<ComponentGroupRef Id="SomethingElse" />
<?endif?>
And then include the Component and ComponentGroups in separate Fragment tags so that they will only be compiled when referenced :)
<Fragment>
<Component Id="Somefile.dll" Guid="*">
<File Id="Somefile.dll" KeyPath="yes" Source="SourceDir\Somefile.dll" />
</Component>
</Fragment>
<Fragment>
<ComponentGroup Id="SomethingElse">
<ComponentRef Id="Somefile.dll" />
<Component Id="AnotherFile.dll>
<File Id="AnotherFile.dll" KeyPath="yes" Source="SourceDir\AnotherFile.dll" />
</Component>
</ComponentGroup>
</Fragment>
Personally I use nant to call candle and light targets, defining different variables for various different builds and products, effective use of fragments and preprocessor variables provides a great opportunity for code re-use between projects, or various releases of the same project.
In your case, to check if a file exists... then you'd just use the internal functions to define, or redefine a variable that is later passed to WiX. e.g.:
<if test="${not file::exists('something.dll')}">
<property name="releasetype" value="blahblahblah" />
</if>

How do you copy a set of files to multiple places using Wix?

I'm trying to make an install that puts a copy of the same files in multiple places...
is there a simple way to do this?
eg. if I wanted to put a.txt b.txt c.txt into all of the following directories :-
.\Blah\
.\Txts\
.\Examples\
Simply create multiple components which reference the same file, but install it to different locations. The only gotcha is that you cannot use two <File Source="somefile"/> elements referencing the same file because they will get the same auto-generated ID. Explicitly give the file elements different IDs to avoid that problem.
<DirectoryRef Id="directory1">
<Component Id="somefile-component1">
<File Id="somefile-id1" Source="/path/to/somefile"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="directory2">
<Component Id="somefile-component2">
<File Id="somefile-id2" Source="/path/to/somefile"/>
</Component>
</DirectoryRef>
Duplicate Files: Windows Installer has its own concept for this called "DuplicateFiles". It only works if the files are actually identical, but it sounds like that's what you want.
CopyFile Element: In WIX you implement this via the CopyFile element:
http://wix.sourceforge.net/manual-wix2/wix_xsd_copyfile.htm
I haven't actually tried it, but it should look something like this
<Component Id='Manual' Guid='*' >
<File Id='Manual' Name='Manual.pdf' Source='Manual.pdf' KeyPath='yes'>
<CopyFile Id='MyDuplicateFile1' DestinationProperty ='DesktopFolder'/>
</File>
</Component>