Using WiX to target specific folder - wix

I'm using Wix to create an installer that will search for a directory on the user's PC and install a related application to that directory. For example, I need to install to the folder ProductA\Utilities, the location of which is outside of my control.
To accomplish this, I have tried the following:
<Property Id="UTILITIES_DIR">
<DirectorySearch Id="FindUtilsDir" Path="ProductA\Utilities"/>
</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<!-- WiX requires me to use a special folder at some point -->
<Directory Id="ProgramFilesFolder" Name="ProgramFiles">
<Directory Id="UTILITIES_DIR">
<Directory Id="INSTALLFOLDER" Name="MyUtility"/>
</Directory>
</Directory>
</Directory>
This all works well when I'm running the installer by double clicking, however, when I run the installer through msiexec.exe, the UTILITIES_DIR is found, but overwritten immediately after:
From log file:
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Adding TARGETDIR property. Its value is 'F:\'.
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Modifying ProgramFilesFolder property.
Its current value is 'C:\Program Files (x86)\'. Its new value: 'F:\ProgramFiles\'.
MSI (c) (C0:0C) [16:49:34:064]:
PROPERTY CHANGE: Modifying UTILITIES_DIR property.
Its current value is 'C:\ProductA\Utilities'. Its new value: 'F:\ProgramFiles\'.
It's worth noting that F:\ on my machine is a network share to parts of C:\ and it reports the exact same free space as C:\, so it seems that I'm getting lucky when running the .msi directly and TARGETDIR is set to C:\, but when running from msiexec, TARGETDIR is getting set to F:.
Is there a way to accomplish finding a specific directory that may be in any root?

You can set the SourceDir to WindowsVolume. So it will not change anymore.
<SetDirectory Id="SourceDir " Value="[WindowsVolume]" />

Related

How can I create a folder (at Runtime) during installation via msiexec.exe?

I am deploying one MSI via msiexec.exe, but when I specify the path=D:\folder_name, the folder is not created.
Code:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" Name="bin" />
</Directory>
</Fragment>
From the above code, I can achieve folder "bin" but I want that "bin" should go into the folder which will get created via msiexec.exe i.e
msiexec.exe /i /path/to/msi /quiet PATH=Drive/Folder_name
Can we have a workaround so that if the folder is not present then it should create it and should put the "bin" in that folder?
You need to specify the TARGETDIR and not PATH. Try the following:
msiexec.exe /i /path/to/msi TARGETDIR="DRIVE/Folder_name" /qb
It's not clear what you're asking because:
Why is PATH in your msiexec command line? If you want to specify the actual directory you should perhaps be using INSTALLDIR=....
The Directory element seems incomplete. Typically you'd have something like:
Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MyName">
<Directory Id="MYDIR" Name="Fred" />
</Directory>
</Directory>
</Directory>
and use INSTALLDIR in the command line to specify the name within ProgramFiles or TARGETDIR to customize the entire path, or MYDIR to change the name "Fred".
To get to the question: a folder is created by specifying that files will be installed there. Maybe more of your source would show that.
If you want to create an empty directory it's done with a CreateFolder element inside a component, as here in the WiX docs:
Creating an empty folder
This is not in your question, but silent installs that require elevation will fail because silent means that the UAC elevation prompt will not be shown, and the install will proceed with limited privileges and fail.

Deploy BizTalk application msi (created with BTDF) via msiexec

We are setting up deployment automation for our BizTalk MSIs that were created with BTDF.
Currently the approach we're working on is by calling msiexec from our deployment toolset. However, we need to install the application in a different folder than the MSI is set to propose.
The BTSF WiX default to C:-drive, whereas we must install to the E: drive. I have tried changing that in the msiexec call, but when passing INSTALLDIR or TARGETDIR, it just throws the msiexec help dialog in my face.
So I figured I should try and take a look at WiX, so that we could build the MSI to default to E: (if available), which would ultimately have the same end result, but WiX is a bit of mystery to me and it seems to have a lot of 'magic' for my understanding at this point.
BTDF by default uses the below structure (and mainly the lower portion of it), and I figure I would have to do something with the TARGETDIR and/or SourceDir. But I can't put my finger on which part is just some kind of variable that can be set.
<Directory Id="TARGETDIR" Name="SourceDir">
<?if $(var.CreateStartMenuShortcuts) ~= True?>
<Directory Id="ProgramMenuFolder">
<Directory Id="BizShortCuts" Name="$(var.ProductName) $(var.ProjectVersion)">
<Directory Id="BizShortCutsTools" Name="Deployment Tools" />
</Directory>
</Directory>
<?endif?>
<Directory Id="ProgramFilesFolder" Name="ProgramFiles">
<Directory Id="ProductDir" Name="$(var.ProductName)">
<Directory Id="INSTALLDIR" Name="$(var.ProjectVersion)"/>
</Directory>
</Directory>
</Directory>
Edit 20180129
Note that this problem occurs in a server environment, with restricted security for my logged in user. We are permitted to run msi installers (right click, custom option 'Run as [authorized user name]', with the msi UI.
In order to accomplish this via command line, I've launched as PS terminal under that other account, which works up until the point where I add the INSTALLDIR parameter. Then it simply displays msiexec help.
I doubt it makes a difference, but local version of msiexec (which works) is 5.0.7601.23593, and serverside (which doesn't work) is 5.0.9600.18333 (i.e. more recent).
First, upgrade to the Deployment Framework for BizTalk v5.6 or newer.
Second, in your .btdfproj, add DefaultInstallDir:
<PropertyGroup>
<!-- existing MSI properties -->
<ProductUpgradeCode>GUID-HERE</ProductUpgradeCode>
<!-- add DefaultInstallDir -->
<DefaultInstallDir>E:\MyCustomPath</DefaultInstallDir>
</PropertyGroup>
The MSI will now default to E:\MyCustomPath.

Install a folder to ALLUSERS (not a shortcut!) using WiX

I have an MSI file that is installing a folder with a bunch of files inside it. I have a location that I am putting the files in:
Windows XP:
C:\Documents and Settings\All Users\Documents\MyFolder
Windows 7:
C:\Users\Public\Documents\MyFolder
The issue is that I do not want to hardcode these paths, but no matter where I look I cannot find out how to do this, because everywhere I look they are talking about making shortcuts for all users and that is not what I am trying to do. How can one install a folder to an "All Users" location?
Something like this:
<PropertyRef Id="WIX_DIR_COMMON_DOCUMENTS" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WIX_DIR_COMMON_DOCUMENTS">
<Directory Id="MyFolder" Name="MyFolder">
Windows Installer does not have a property for that folder, but a WiX-provided custom action does.
Per the documentation on the OSInfo custom actions:
Reference the WixUtilExtension extension for the linker.
Define the property via a reference:
<PropertyRef Id="WIX_DIR_COMMON_DOCUMENTS" />
Then, define the directory somewhere under the TARGETDIR directory. For example:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WIX_DIR_COMMON_DOCUMENTS">`
<Directory Id="MyFolder" Name="MyFolder" />`
</Directory>`
</Directory>`

WIX installer root directory and versioning

I have created a silent installer Using WIX for my application. I want it to install my application to C:\MyApps folder but its Directory Id='TARGETDIR' Name='SourceDir' tag randomly picks C or D drive. I want to enforce my installation to C drive only. Also in case, I provide version number greater than 4.0.5, I am geting an error during installation saying "This installation package cannot be installed by the Windows Installer Service. You must install a newer version of the Window Installer service." I am having Windows XP professional SP3 Version 2002.
To begin with, I think you should start your WiX journey with the tutorial available here. It contains the answers to the most of basic questions you'll face with the first thing. You should also be aware that understanding WiX means understanding the concepts of Windows Installer first - otherwise some points will seem a weird magic to you.
When you create a new WiX setup project in Visual Studio, it generates a template with some placeholders. It is recommended to start modifying this template. For instance, the directory structure:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="SetupProject1">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent" Guid="ba7d579f-5234-4448-b880-109f589d58e5"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
</Directory>
</Directory>
</Directory>
This snippet defines the INSTALLLOCATION folder under the ProgramFileFolder, and this is a better approach than to place it under the C:\ root. You can still change the installation location by modifying the INSTALLLOCATION property at install time (for instance, base on user's input).
The quick answer to your questions are:
...randomly picks C or D drive...
That's expected - it picks the drive with the most free space by the time of installation. If you stick to the way WiX template defines by default, it will fall under C: (actually, under Program Files folder).
...You must install a newer version of the Window Installer service...
Basically, it means what it says - the version Windows Installer on your machine is lower than the one you require in your package. If you try to solve the above problems with this change, then it has nothing to do with the Windows Installer version. You should require higher version than it is specified by default only in case you are going to use new features of Windows Installer.
Hope you'll make right conclusion out of this brief intro - start with the tutorial. :-)
The problem with your versions is you're changing the Windows Installer version when you change your Product version.
<Package
Id='*'
InstallerVersion='406'
Compressed='yes'
Description="Installer Number 406" />
The InstallerVersion attribute should be the minimum required version of Windows Installer required to install this package. You have Windows Installer v4.5 installed. When this is set to 406, it looks for Windows Installer v4.6 which frankly, doesn't exist. Setting this to 301 (version 3.1) is usually sufficient.
InstallerVersion='301'
While your description attribute is fine, I would find the following more meaningful:
Description="My Product v4.0.6 Installer"
Try this:
<Fragment>
<Property Id="_BrowseProperty" Value="INSTALLDIR" Secure="yes"/>
<CustomAction Id="SetDataLocationDefault" Property="INSTALLDIR" Value="[WindowsVolume]$(var.Title)\" />
<InstallUISequence>
<Custom Action="SetDataLocationDefault" After="CostFinalize" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="SetDataLocationDefault" After="CostFinalize" />
</InstallExecuteSequence>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" Name="$(var.Title)">
<!-- TODO: Insert your components here. -->
</Directory>
</Directory>
</Fragment>
I think this should work!
Do not rely on TARGETDIR, and use the custom property, like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLLOCATION" Name="SetupProject1">
<!-- TODO: Insert your components here. -->
</Directory>
</Directory>
The template is taken from Yan's answer. Set INSTALLLOCATION to the desired folder C:\MyApps, that should do the trick.

Changing installation location based on condition

I am making installer for a utility that can be installed as part of a main program or independently. The location of the main program in present in a registry key. If the main program is installed, the utility should be installed in a "Utilities" sub-directory. e.g. D:\Program Files(x86)\MainProgram\Utilities. If the main program is not installed, then it should default to root drive folder e.g. C:\Program Files(x86)\MainProgram\Utilities.
Installation should get the registry key (e.g. HKLM\Software\MainProgram\ Key:"Install_location"). This will give a path till d:\Program File(x86)\MainProgram. The utility should be installed in its sub-directly. If the key is not present, it should default to the standard location.
Read the registry value from custom action using C# or some other language and check if key exists or else you can use WIX to find if registry key exists.
RegistryKey regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"Software\MainProgram\Key");
if ((string)Registry.GetValue(regKey, "Install_location", "0") != "0")
{
session["Somevariable"] = (string)Registry.GetValue(regKey, "Install_location")
}
using WIX
<Property Id="INSTALLLOCATION">
<RegistrySearch Id="INSTALLLOCATION"
Name="Install_location"
Root="HKLM"
Key="Software\MainProgram\Key"
Type="raw" />
</Property>
On the basis of the value of WIX session variable you can decide the install location and install the utility at the desired path.
Read the MainProgram location into a property:
<Property Id="MainProgramDir">
<RegistrySearch Id="FindMainProgramDir"
Root="HKLM"
Key="Software\MainProgram"
Name="Install_location"
Type="directory" />
</Property>
And set up your directory structure for the default behavior:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="MainProgramDir" Name="MainProgram">
<Directory Id="INSTALLDIR" Name="Utilities"/>
</Directory>
</Directory>
</Directory>
Directory elements are like properties, and will be overridden if there is a property with the same Id. If the property is not set (because the RegistrySearch fails) then it will be as it was defined in the directory structure you set up.