We use the wix 3.9 to create an msi for our product. Our Target: We want to deliver a config file (.txt-file) via the msi. When an config file already exists in the installation folder, the file should not be overwritten by an upgrade. Unfortunately, on an upgrade, Wix removes the configuration file.
The Product Element:
<Product Id="*" Name="$(var.AppName) V$(var.Version) $(var.TargetBuild)" Language="1033" Version="$(var.Version)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
The $(var.UpgradeCode) is static and will never be changed.
The Upgrade Tags:
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.AppName) is already installed." AllowSameVersionUpgrades="yes" />
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="1.0.0"
IncludeMinimum="yes"
OnlyDetect="yes"
Maximum="$(var.Version)"
IncludeMaximum="yes"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
Here is the config file:
<Component Id="ConfigComponent" NeverOverwrite="yes" Guid="GUID-HERE">
<File Id="ConfigOutput" KeyPath="yes" Name="MyConfig.config" Source="MyConfig.config.bak"/>
</Component>
In Addition, I use RemoveFolderEx to remove generated files by the Application itself. But when I commented out this block, the problem still occurs. But I want to show the codeblock for the completeness:
<Component Id="RemoveAll" Guid="MYGUID">
<RemoveFile Id="RemoveAllFilesOnUninstall" Directory="APPLICATIONFOLDER" Name="*.*" On="uninstall" />
<RemoveFolder Id="RemoveAllFoldersOnUninstall" Directory="APPLICATIONFOLDER" On="uninstall" />
<RegistryValue Root="HKLM" Key="SOFTWARE\$(var.Manufacturer)\$(var.AppName)" Name="Path" Type="string" Value="[APPLICATIONFOLDER]" KeyPath="yes" />
<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
</Component>
Repro: At first, we install the Software and the file 'MyConfig.config' appears in the application folder as expected. After that, we make changes inside of this config file. At next, we build a second .msi and execute it. When the update is made, all files are overwritten as expected. But we are missing the file 'MyConfig.config' in the installation folder now.
UPDATE:
The attribute Permanent="yes" does also not work as expected. The config File is still removed on an upgrade:
<Component Id="ConfigComponent" Permanent="yes" NeverOverwrite="yes" Guid="GUID-HERE">
<File Id="ConfigOutput" KeyPath="yes" Name="MyConfig.config" Source="MyConfig.config.bak"/>
</Component>
What's happening during your Major Upgrade:
The CostInitialize/CostFinalize actions determine what components in the new MSI should install. The ConfigComponent decides 'not' to install because it's marked as NeverOverwrite="yes".
The old MSI is removed during the RemoveExistingProducts action. The previous config file is removed.
The new MSI is installed. The ConfigComponent does not get installed based on the check from step 1.
A quick solution (although I'm sure there are better approaches out there):
Going forward, mark your ConfigComponent with Permanent="yes" so that MSI never removes it. You'll need to add a custom action that removes the file, and condition it on "$ConfigComponent=2 And Not UPGRADINGPRODUCTCODE" so that it only executes when the component is set to be deleted through a modify or full-uninstall, but not an upgrade.
If your MSI is already shipped to the world and you need to fix the upgrade scenario you'll need to write a custom action that copies the config file to a backup location before the old MSI removes it. Then another custom action to copy the config file back into the correct directory.
Related
After installing osquery with an MSI made with WiXToolSet (Using the script provided by osquery), I tried uninstalling it which failed.
Also it didn't show as a program in the appwiz.
(Link to the script - https://github.com/osquery/osquery/blob/master/tools/deployment/make_windows_package.ps1)
I've tried using both the MSI itself - osquery.msi /uninstall and the unsintall string - msiexec /I{'uninstallstring'}.
I also tried repairing using the /fv option.
The code the script used with WiX to create the MSI:
#'
<?xml version='1.0' encoding='windows-1252'?>
<?define OsqueryVersion = 'OSQUERY_VERSION'?>
<?define OsqueryUpgradeCode = 'ea6c7327-461e-4033-847c-acdf2b85dede'?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product
Name='osquery'
Manufacturer='Facebook'
'#
$wix += "`n Id='$(New-Guid)'`n"
$wix +=
#'
UpgradeCode='$(var.OsqueryUpgradeCode)'
Language='1033'
Codepage='1252'
Version='$(var.OsqueryVersion)'>
<Package Id='*'
Keywords='Installer'
Description='osquery standalone installer'
Comments='Facebooks opensource host intrusion detection agent'
Manufacturer='Facebook'
InstallerVersion='200'
Platform='x64'
Languages='1033'
Compressed='yes'
SummaryCodepage='1252' />
<MediaTemplate EmbedCab="yes" />
<MajorUpgrade
DowngradeErrorMessage="A later version of osquery is already installed. Setup will now exit." />
<Condition Message='A newer version of osquery is already installed.'>
NOT NEWERVERSIONDETECTED
</Condition>
<Condition Message="You need to be an administrator to install this product.">
Privileged
</Condition>
<Property Id='SOURCEDIRECTORY' Value='packs'/>
<PropertyRef Id="WIX_ACCOUNT_LOCALSYSTEM" />
<PropertyRef Id="WIX_ACCOUNT_USERS" />
<PropertyRef Id="WIX_ACCOUNT_ADMINISTRATORS" />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFiles64Folder'>
<Directory Id='INSTALLFOLDER' Name='osquery'>
<Directory Id='DaemonFolder' Name='osqueryd'>
<Component Id='osqueryd'
Guid='41c9910d-bded-45dc-8f82-3cd00a24fa2f'>
<CreateFolder>
<Permission User="[WIX_ACCOUNT_USERS]" Read="yes"
ReadExtendedAttributes="yes" Traverse="yes"
ReadAttributes="yes" ReadPermission="yes" Synchronize="yes"
GenericWrite="no" WriteAttributes="no"/>
<Permission User="[WIX_ACCOUNT_ADMINISTRATORS]" GenericAll="yes"/>
<Permission User="[WIX_ACCOUNT_LOCALSYSTEM]" GenericAll="yes"/>
</CreateFolder>
<File Id='osqueryd'
Name='osqueryd.exe'
Source='OSQUERY_DAEMON_PATH'
KeyPath='yes'/>
<ServiceInstall Id='osqueryd'
Name='osqueryd'
Account='NT AUTHORITY\SYSTEM'
Arguments='--flagfile="C:\Program Files\osquery\osquery.flags"'
Start='auto'
Type='ownProcess'
Vital='yes'
ErrorControl='normal'/>
<ServiceControl Id='osqueryd'
Name='osqueryd'
Stop='both'
Start='install'
Remove='uninstall'
Wait='no'/>
</Component>
</Directory>
<Component Id='osqueryi' Guid='6a49524e-52b0-4e99-876f-ec50c0082a04'>
<File Id='osqueryi'
Name='osqueryi.exe'
Source='OSQUERY_SHELL_PATH'
KeyPath='yes'/>
</Component>
<Component Id='extras' Guid='3f435561-8fe7-4725-975a-95930c44d063'>
<File Id='osquery.conf'
Name='osquery.conf'
Source='OSQUERY_CONF_PATH'
KeyPath='yes'/>
<File Id='osquery.flags'
Name='osquery.flags'
Source='OSQUERY_FLAGS_PATH'/>
<File Id='osquery.man'
Name='osquery.man'
Source='OSQUERY_MAN_PATH'/>
<File Id='osquery_utils.ps1'
Name='osquery_utils.ps1'
Source='OSQUERY_UTILS_PATH'/>
<File Id='manage_osqueryd.ps1'
Name='manage-osqueryd.ps1'
Source='OSQUERY_MGMT_PATH'/>
'#
When trying to use the MSI to uninstall I saw the following message :
This patch package could not be opened. Verify that the patch package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer patch package
When trying to use the uninstall string I see this message:
This action is only valid for products that are currently installed
Upgrade Code Retrieval: How can I find the Upgrade Code for an
installed MSI file? (if you want to test the below with another package family, find upgrade code via methods described here).
Debugging: To find the product code (provided it is actually defined), maybe try to run this code:
Set installer = CreateObject("WindowsInstaller.Installer")
Set upgrades = installer.RelatedProducts("ea6c7327-461e-4033-847c-acdf2b85dede")
For Each u In upgrades
MsgBox u, vbOKOnly, "Product Code: "
Next
Procedure: 1) copy & paste the script into notepad, 2) save as ANSI file: "Find Related Products.vbs" on desktop, 3) double click script file to run. Make a note of the product codes shown by the message boxes (if any). Hit CTRL + C to copy content of the actual VBScript dialog.
Uninstall: From the cmd.exe using the product code you found by running the script above:
msiexec.exe /x {Product-Code}
Alternative: Browse through %SystemRoot%\Installer manually if you can't get the above to work, and follow the advice in section 4 here. Locate the right MSI, right click and go "Uninstall".
Links:
Powershell: Uninstall application by UpgradeCode
I've followed the official Major Upgrade guide and I seem to be missing something.
Here is my MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Disallow="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes"
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="tenlira.ini" Guid="*">
<File Id="tenlira.ini" Source="..\ConfigurationFile\x64\tenlira.ini" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="tenlira.ini" />
</Feature>
</Product>
</Wix>
All it does is simply installing a single file as an example. So far, so good. Now, all I do is add another Component and File and off course the corresponding ComponentRef in Feature. I specifically leave the Version as is: 31.00.0000. What I expected is that the new installer will not perform a Major Upgrade, but it does. Why? Also, there is now 2 entries in Add/Remove Programs.
Please help me find out what am I missing here. Thanks. Refael.
UPDATE:
Posting the question got me to reread the documentation again and I discovered that the AllowSameVersionUpgrades thingy in the MajorUpgrade element should be set to yes. This time there is only one entree in the Add/Remove Programs, but it still performs Major Upgrade. Why?
UPDATE: Here is a list to help debug failing major upgrades by identifying the most common problems: Common causes of failed major upgrades
Major Upgrade - "The Old, Manual Way"
I guess you are hitting an oddity that may not be handled entirely as expected by the WiX MajorUpgrade element by combining the auto-generated product GUID, the AllowSameVersionUpgrades set to yes and keeping the version number the same.
I can't see any obvious way to set the MinInclusive attribute in WiX's MajorUpgrade element - I could be mistaken, there might be a way I am unaware of. For what it is worth, I am not too keen on allowing "same version upgrades".
However, you could try to "use the old way" to author the Upgrade table using the "older elements" Upgrade and UpgradeVersion. The MajorUpgrade element is essentially a "convenience" feature to set up your major upgrades easily, and I believe it works for most users. Bob Arnson has a blog explaining the introduction of the MajorUpgrade element. This blog also shows a sample of how to do things "manually" with the "older elements" Upgrade and UpgradeVersion (do check it out).
I made a quick mock-up that might do what you want, it is just a "rough draft" - can't make any guarantees. I use preprocessor defines to set some variables that can be referenced in the WiX source file - as a C++ developer this is a piece of cake for you so I won't waste time explaining it - the source should make sense:
<?define MyProductVersion = "31.00.0000" ?>
<?define MyProductCode = "PUT-GUID-HERE" ?>
<?define MyUpgradeCode = "PUT-GUID-HERE" ?>
<!--Recommendation: set a path variable that you can redirect at will to a new release folder (new build output folder): -->
<!-- <?define MyBasePath = "C:\Projects\MyApp\Release\31.00.0000\" ?> -->
<!-- SAMPLE:
<Component Win64="yes" Feature="MainApplication">
<File Source="$(var.MyBasePath)\myapp.exe" />
</Component> -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="$(var.MyProductCode)" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="$(var.MyUpgradeCode)" Version="$(var.MyProductVersion)">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<!-- Major upgrade -->
<Upgrade Id="$(var.MyUpgradeCode)">
<!-- Downgrade Protection -->
<UpgradeVersion Minimum="$(var.MyProductVersion)" OnlyDetect="yes" IncludeMinimum="yes" Property="DOWNGRADE_DETECTED" />
<!-- Major Upgrade Configuration -->
<UpgradeVersion IncludeMinimum="no" Maximum="$(var.MyProductVersion)" IncludeMaximum="no" MigrateFeatures="yes" Property="UPGRADE_DETECTED" />
</Upgrade>
<!-- Major Upgrade: Schedule RemoveExistingProducts -->
<InstallExecuteSequence>
<!-- Potential scheduling (after): InstallValidate, InstallInitialize, InstallExecute, InstallExecuteAgain, InstallFinalize -->
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
<!--Launch Condition: Abort setup if higher version found-->
<Condition Message="!(loc.NewerVersionDetected)">
NOT DOWNGRADE_DETECTED
</Condition>
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<!--<ComponentRef Id="tenlira.ini" />-->
</Feature>
</Product>
</Wix>
Now the !(loc.NewerVersionDetected) has to be explained. This is a localized string (for delivering your setup in different languages). To use it, right click your WiX project in Visual Studio and go: Add New Item... => Localization File => Add. As the localization file is added, your output MSI will also now go into a en-us folder under your main output location (Debug or Release).
In the localization file, add:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="NewerVersionDetected">A later version of [ProductName] is already installed.</String>
</WixLocalization>
And you should now be able to add new strings to this file and easily translate your whole setup using such language files.
Also add the WiX GUI extension. Right click "References". Add Reference... => Browse to WixUIExtension.dll => Double click this file, and press OK. Normal folder to find the file is: C:\Program Files (x86)\WiX Toolset v3.11\bin.
INI-Files
I just want to mention that INI files should ideally be installed via the IniFile table (entries are treated as atomic key-value pairs allowing advanced merging of keys and values for existing INI files), and not via the File table (the file is treated as a regular file either overwriting the whole existing file or leaving it in place - not enforcing any new values). The WiX element corresponding to the MSI IniFile table is naturally the IniFile element.
An ad-hoc sample:
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
Links:
Adding entries to MSI UpgradeTable to remove related products
It does a major upgrade because both MSIs have the same UpgradeCode and you have now specified AllowSameVersionUpgrades, so it does the upgrade where it didn't before.
Your build generates a new ProductCode every time, so each MSI is a new product, so you will get it installed twice if it doesn't do an upgrade and once if it does. You may have some assumption about the way upgrades work that you haven't spelled out.
I had the same problem where Version is same, but the Id is different creating multiple entries in Add/Remove programs.
My simple fix was to set AllowSameVersionUpgrades="yes".
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ServiceName) is already installed." />
I have the below Wix XML code that I have written for Single Package Authoring. The problem is when "Install for all unders of this machine" mode is selected in the UI(WixUI_Advanced), the default location that shows up in the UI is "C:\Users\XXXX\AppData\Local\Programs\MyApp\ ". How can I change this, so that the default location is ..\Program Files (x86)\MyApp....
If I change <Property Id="MSIINSTALLPERUSER" Value=" "/>,
then the default location is ..\Program Files(x86).., but the per user does not work due to lack of admin privileges.
Much appreciated.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<!--Product Information-->
<Product Id="*"
Name="$(var.ApplicationName)"
Language="1033" Version="!(bind.FileVersion.$(var.ExecutableName))" Manufacturer="$(var.ManufacturerName)"
UpgradeCode="33bc2348-****-****-****-ebcde0d14afe">
<!--MSI Package Information-->
<Package InstallerVersion="500"
Compressed="yes" />
<!--Single Package Authoring-->
<Property Id="MSIINSTALLPERUSER" Value="1"/>
<Property Id="ALLUSERS" Value="2"/>
<!--Upgrade Information-->
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.ApplicationName) is already installed." />
<MediaTemplate EmbedCab="yes" />
<!--Application Features-->
<Feature Id="CoreFeature" Title="$(var.ApplicationName)" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id="ApplicationShortcut" />
<ComponentRef Id="RegisterApplicationAutoStart" />
</Feature>
<!--Required .NET Framework for the Application-->
<PropertyRef Id="NETFRAMEWORK35" />
<Condition Message="This application requires Microsoft .NET Framework 3.5 or greater. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR NETFRAMEWORK35]]>
</Condition>
<!--Advanced UI-->
<Property Id="ApplicationFolderName" Value="$(var.ApplicationName)" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<UIRef Id="WixUI_Advanced"/>
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<!-- Define the Target Directory. The individual files will be filled in via a Heat generated fragment. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<!--Define the directory when the application will be installed-->
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="$(var.ApplicationName)" />
</Directory>
</Fragment>
<Fragment>
<Component Id="RegisterApplicationAutoStart" Directory="ApplicationProgramsFolder" Guid="*">
<RegistryValue Root="HKMU"
Key="Software\Microsoft\Windows\CurrentVersion\Run"
Name="$(var.ApplicationName)"
Type="string"
Value="[APPLICATIONFOLDER]$(var.ExecutableName)"
KeyPath="yes" />
</Component>
</Fragment>
</Wix>
The OP described it perfectly. With single authoring enabled in the following way, there seems to be no way to obtain to "actual" ProgramFilesFolder at C:\Program Files (x86)\.
<Package InstallerVersion="200" ... /> <!-- do not specify InstallScope or InstallPrivileges! -->
<Property Id="ALLUSERS" Value="2" />
<Property Id="MSIINSTALLPERUSER" Value="1" />
Even if MSIINSTALLPERUSER is reset, this does not change the value of ProgramFilesFolder, it's still C:\Users\XXX\AppData\Local\Programs (I assume the folder is initialised through SHGetFolderPath at installer startup, and doesn't change thereafter).
Setting the ProgramFilesFolderexplicitly like the OP showed in his answer would work I guess, but it's an ugly hack. What worked for me in the end was to start out in 'perMachine'-Mode:
<Property Id="ALLUSERS" Value="2" />
<Property Id="MSIINSTALLPERUSER" />
Afterwards, if the installer chooses the 'perUser'-Mode, I set the variables accordingly:
<Publish Dialog="MyWelcomeDlg" Control="Next" Property="MSIINSTALLPERUSER" Value="1">1</Publish>
<Publish Dialog="MyWelcomeDlg" Control="Next" Property="ALLUSERS" Value="{}">1</Publish>
This way, the folders will be correctly set.
I consider the underlying problem to be that ProgramFilesFolder would ever get set to something in AppData, that makes little to no sense.
If you want to install to the Program Files folder then you are required to be administrator. Limited users cannot create or update files in that folder, and running an MSI install does not break security just because it's an install. So the answer is that you cannot install to ProgramFiles unless you cause the MSI to ask for elevated privileges. Your question is essentially "how can a limited user break security by adding or replacing files in the Program Files folder", and there's no way to answer that.
Does your app require elevated privileges to run? Does it have an elevation manifest? If the answer is yes, then I suspect you're stuck with the requirement that elevated privileges are also needed to install it.
I included the below line in the WiX installer that fixed my issue.
<SetDirectory Id="ProgramFilesFolder" Value="C:\Program Files (x86)\"></SetDirectory>
This changed the value of ProgramFilesFolder that was being set to C:\Users\XXX\AppData\Local..... to C:\Program Files (x86) for per machine installation.
Also the above line of code does not make any difference to per user installation and installation happens at that user folder only (as desired.)
Please follow the link below
http://wixtoolset.org/documentation/manual/v3/wixui/dialog_reference/wixui_advanced.html
For a per-machine installation, the default installation location will be
[ProgramFilesFolder][ApplicationFolderName]
and the user will be able to change it in the setup UI.
For a per-user installation, the default installation location will be
[LocalAppDataFolder]Apps[ApplicationFolderName]
and the user will not be able to change it in the setup UI.
you can set the per user to 0 to enforce installation per machine - or in Program files
<WixVariable Id="WixUISupportPerUser" Value="0" />
For per-machine installation you will need admin privileges, if the user will not have admin privileges, he only has access to his local app data folder, hence that location cannot be changed.
Hi I've seen other questions on this topic, but nothing I try seems to work.
On uninstall of my product I get many messages in my log file like this:
Disallowing uninstallation of component: {895A2232-90E3-417B-AF3D-A4F5A8D1C225} since another client exists
This post...
Wix does not remove service and files on uninstall
... prompted me to run MsiInv, which logged this a few times: 'Component x has no parent product'
This post: http://www.itninja.com/question/disallowing-uninstallation-of-component-xxx prompted me to find and delete the orphan entries... I've even tried running AVG registry cleaner.
However the files are still not removed on an uninstall. So I've been testing the solutions above (e.g. removing orphan registry entries) by uninstalling, then manually removing the files, then updating the product version and reinstalling.
Relevant code snippets:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="My Product Name"
Language="1033"
Version="1.0.118.0"
Manufacturer="My Company Name"
UpgradeCode="DEA53C73-EE29-4D5E-A3FF-0A09D0F50AF3">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<!--<UIRef Id="WixUI_Minimal" />-->
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<!-- Force administrator-->
<Property Id="MSIUSEREALADMINDETECTION" Value="1" />
<Feature Id="ProductFeature" Title="My Installer Name" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
...
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="CMP_INSTALL_FOLDER" Guid="DA711C12-A960-421F-A6A9-5ECF0DEEE2BC" Permanent ="no">
<RemoveFolder Id='RemovInstallFolder' Directory='INSTALLFOLDER' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]\InstallFolder' Type='string' Value='' KeyPath='yes' />
</Component>
<Component Id="exampleComponent"
Guid="A0AFBE29-6962-4491-9D2F-D08E0B31C6BA" Permanent ="no">
<File Id="exampleComponentName"
Source="exampleSource"
KeyPath="yes" />
</Component>
</ComponentGroup>
Thanks to Chris for suggesting testing on a fresh image. That led me to the answer.
My problem was that a custom action (which was running an executable) was failing. Once I put a condition of 'NOT installed' to prevent that custom action running on uninstall it started to work
<InstallExecuteSequence>
<Custom Action="CA_RunRegisterDLLScript" After="InstallFiles" >
NOT Installed
</Custom>
</InstallExecuteSequence>
It still doesn't work on the dev machine - I'm giving up on that...
One other tip that I learned along the way was how to find root cause problems in a verbose MSI log file. Short answer - Look for "return value = 3" - the problem's almost always just above it
I found this tip here: http://blogs.msdn.com/b/astebner/archive/2005/08/01/446328.aspx
Hi I am installing files into a directory using WIX with the code below.
<Directory Id="CMSICONSDIR" Name="CMSIcons">
<Component Id="CMSICONSDIR_C" Guid="B0328FBF-D9F7-4278-B16C-28650016FF86" SharedDllRefCount="no" KeyPath="no" NeverOverwrite="no" Permanent="no" Transitive="no" Location="either">
<CreateFolder/>
<File Id="AddCamera.png" Name="AddCamera.png" DiskId="1" Source="..\..\OrionVEWorld\bin\Release\CMSICons\AddCamera.png" KeyPath="no" />
<File Id="aldownloadsmall.png" Name="al-download-small.png" DiskId="1" Source="..\..\OrionVEWorld\bin\Release\CMSICons\al-download-small.png" KeyPath="no" />
They way my application works is that a user can copy their own files in that directory overriding with what they prefer.
The problem is when I do my next install for an update, its overrides those files with the files stipulated in the install.
How do I ensure that when I run my install it does not override the existing files that are there and only adds new ones.
Unfortunately in other case I do need files that override what is there.
I do have an upgrade script section which can affect this as below
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)" OnlyDetect="no" Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="1.0.0.0"
IncludeMinimum="yes"
OnlyDetect="no"
Maximum="$(var.ProductVersion)"
IncludeMaximum="no"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
Any suggestions is appreciated.
You could try changing the upgrade order by modifing the sequence of RemoveExistingProducts action. You could place it after InstallFinalize (no 4 option in the link article).
Also this article explains how windows installer handles the whole file overwrite logic.
EDIT: Also add the "Never overwrite" attribute to the components.
Try adding NeverOverwrite attribute to your components. It should do the trick.