I'm trying to create an installer that supports perUser and perMachine installations dependent on a selection of setup types on the UI.
The perUser setup type installs the application into "WIX_DIR_COMMON_DOCUMENTS" and shall require no admin permissions.
The perMachine setup type install the application into "ProgramFilesFolder" and shall request an UAC dialog.
My attempt was to initially set the Package/#InstallScope to perUser and then modify the ALLUSERS property later on.
If the user selects the perMachine setup type I'm trying to set the ALLUSERS property to 1 doing the following:
<Publish Property="ALLUSERS" Value="1">1</Publish>
The "Install" buttons gets an UAC icon, but no UAC dialog appears after I pressed it!
Instead I get an error message that I obviously have no privileges to install the application for all users of the machine.
Is it a bug that no UAC dialog appears or intended? Am I missing something?
Someone from the WiX Mailing list pointed me to the Single Package Authoring article on msdn.
I had to initialize the following properties:
<Property Id='ALLUSERS' Value='2' />
<Property Id='MSIINSTALLPERUSER' Value='1' />
and set the 'MSIINSTALLPERUSER' property to an empty string for a per-Machine installation.
<Publish Property="MSIINSTALLPERUSER" Value="{}">1</Publish>
Be aware that this only works for Windows Installer 5 and higher!
Related
I have an installer and I have a feature that I can turn on or off if I pass on the msiexec.exe commandline a property named FEATUREX to be 0 or 1. If the value is zero, the feature is not installed. If the value is 1, then the feature is installed. It's a COM component. Part of the install always installs the COM component so that it can be enabled later by changing some registry values in the system. The part of installing the COM component is not FEATUREX since the COM component is always installed. Enabling the COM component to the system is FEATUREX and it adds a CLSID to a subkey in Windows and the system starts using the COM component.
If the software is not installed or has been uninstalled, then my logic works. The problem occurs when I want to install over the top of a previous installation. I do not want to require that the previous installation be uninstalled. I just want to install over the top, and if a sysadmin installs over the top and enables or disables FEATUREX, then FEATUREX should be installed or not installed depending on the value of FEATUREX on the command line.
Usually customers might want to install with FEATUREX disabled, then enable FEATUREX (independent of the installer), but setting the registry key.
However, when installing over the top, the system ignores FEATUREX property on the command line and the real Feature X is enabled or disabled depending on whether it was originally enabled or disabled.
I tried changing the GUID of the Component, and that didn't work...IDK...I was just guessing.
If I change the Feature ID from ActivateFeatureX to ActivateFeatureX2 then the command line property FEATUREX works...but then, if the property is not passed on the command line, Feature X is not installed if it was previously installed.
I was wondering what the solution might be? I have thoughts of a simple checkbox tied to a registry DWORD value such that the COM component would fail to be created if the DWORD value is 0... but IDK.
<Feature Id='ActivateFeatureX' Title='Feature X' Description='If this dropdown is changed from the red "X" to the grey disk icon, then Feature X will be enabled'
Level='2' AllowAdvertise='no' InstallDefault="local" Display="3">
<Condition Level="1">FEATUREX=1</Condition>
<Condition Level="0">FEATUREX=0</Condition>
<ComponentRef Id='ActivateFeatureX' />
</Feature>
<Component Id="ActivateFeatureX" Location="local" Guid="4c0d547f-d9ae-4c5f-bd21-d8360c00dd46">
<RegistryValue Root='HKLM' Key='SOFTWARE\Microsoft\Windows\CurrentVersion\SOMEWHERE\SOMEHOW\{$(var.FeatureXRegistryGUID)}' Type='string' Value='$(var.TheProject.TargetName)' KeyPath='yes' />
</Component>
Instead of trying to use a Condition to control the state of ActivateFeatureX (which has limitations during repair and upgrade), consider using the ADDLOCAL and REMOVE properties to change the state of the Feature directly.
I have a WiX Bootstrapper that invokes MSI. If I launch it as:
setup.exe
It will show a UI and user must process with the installation manually. However, if user passes passive property, the installation will begin automatically. Uninstallation can also be done silently (no UI interaction required) with:
setup.exe -uninstall -passive
What I want is to enable passive-ness by default. I have tried using Variable in Bundle as:
<Variable Name="passive" Type="string" Value="true"/>
But doesn't have any effect (even with value set to "1", or "yes").
Further, I have tried to set MSI property in Chain->MsiPackage:
<MsiProperty Name="passive" Value="1"/>
It doesn't make the installation passive by default.
What could be done?
I am using WixStandardBootstrapperApplication.RtfLicense UI mode.
passive isn't a property; it's a switch. WixStandardBootstrapperApplication does not support passive UI by default. You'd have to write your own bootstrapper application to do that.
I have written an msi which deals with registry. So, i have to run the msi as admin.
when i directly click and launch the Msi,I get the following error to modify the ini file "Access to the path is denied"
It works fine if i launch the msi from command prompt(Right click as administrator.)
I tried all the below suggestions but none of them is working. please assist how to run msi as admin.
Package Id="*" InstallerVersion="200" Compressed="yes" Platform="$(var.Platform)" InstallPrivileges="elevated" AdminImage="yes" InstallScope="perMachine"
CustomAction Id="UpgradeSelectedVersion" BinaryKey="CustomAction" DllEntry="UpgradeSelectedVersion" Execute="deferred" Impersonate="no"
Property Id="ALLUSERS" Value ="1"
or
Property Id="ALLUSERS" Value ="2"
Try the following:
<Property Id="MSIUSEREALADMINDETECTION" Value="1" />
Otherwise, you could wrap your installer in a wix managed bootstrapper application, a bit more work though. Then you add settings to your manifest file.
That custom action is deferred, which means it must be running in the InstallExecuteSequence, which should be elevated and running with the system account if you have InstallScope per machine and elevated privileges.
Don't mess with the ALLUSERS property because WiX just does the right thing. InstallScope per machine and elevated privileges will make it work. If you accidentally turn it into a per user install by messing with ALLUSERS then it will not be elevated and it will fail.
You should be seeing a UAC elevation dialog after the UI sequence. If you are not seeing this dialog then the install will not be elevated. Again, that might be related to you changing ALLUSERS. If you are installing this in silent mode then it will also fail because silent really does mean silent, and it will not show the elevation dialog and your CA will not run elevated.
It's possible that your failing custom action is not the one you posted, which is deferred and therefore after the elevation prompt. If you have a custom action in the UI sequence then it will not be elevated (unless you run the MSI from an elevated prompt) so that may explain the issue you are seeing.
Our application writes some settings to the registry into the HKCU hive during runtime. I want to delete this settings during uninstall. Here is code:
<Fragment>
<DirectoryRef Id="INSTALLLOCATION" DiskId="1" FileSource="$(var.SourceDirProject)\">
<Component Id="DeleteHkcuManufacturerHive" Guid="GUID">
<Condition>REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE</Condition>
<CreateFolder/>
<RemoveRegistryKey Action="removeOnUninstall"
Id="HKCUkey" Root="HKCU" Key="Software\$(var.Manufacturer)"/>
</Component>
</DirectoryRef>
</Fragment>
ICE57: Component 'DeleteHkcuManufacturerHive' has both per-user and per-machine data with a per-machine KeyPath.
Why I'm getting ICE57? Installation is per-User. Thank's in advance.
UPD: Where is here the per-machine element? May be it is an INSTALLLOCATION=Program Files\ManufacturerDirectory?
You are operating on the HKCU hive which is only available to the current user.
MSDN states:
ICE57 validates that individual components do not mix per-machine and
per-user data. This ICE custom action checks registry entries, files,
directory key paths, and non-advertised shortcuts. Mixing per-user and
per-machine data in the same component could result in only partial
installation of the component for some users in a multi-user
environment.
The ICEs are validations on your installation package. As stated above, ICE57 is to make sure you don't mix up per-machine and per-user constructs. If you must remove entries to HKCU during uninstall (and the software is installed per-machine) then you can turn off that specific validation in Visual Studio in Properties > Tool Settings as shown in the screenshot below:
However, you may want to think about the root cause of your issue. If you are doing a per-machine install, your installer or application should probably not be writing to HKCU as it is only available to the current user, whereas your app is installed for all users.
I've got an answer on wix-users mailing list. Here is Peter Shirtcliffe's answer:
ProgramFiles is a per-machine location. You can only access it when elevated. If you want to install program code in a per-user installation, you should install to %LocalAppData%\Programs.
Remove the condition entirely. The component will be installed but will have no effect until you uninstall the application. At that point, when the component is removed, the registrykey will be removed also.
I've struggled through building a new WiX installer, and I'm really happy with it, except that I also need to install a device driver.
Ideally, I'd like to be able to detect the presence of this driver by using RegistrySearch, e.g.
<Property Id="DRIVERINSTALLED">
<RegistrySearch Id="DriverInstalledSearch" Root="HKLM" Key="SOFTWARE\DriverCompany\Settings" Name="InstallPath" Type="raw" />
</Property>
If there is a value for the InstallPath registry key, then I'd like to move ahead with the device driver installation. I haven't figured that part out yet, but that is secondary right now, because I can't even get the device driver to install every time.
There are various examples floating around on the web, and the one corresponding to WiX v3.5 seems to follow this pattern:
<CustomAction Id="InstallDeviceDrivers" Execute="deferred" Directory="INSTALLLOCATION" ExeCommand="setup.exe" Return="check" />
.
.
.
<InstallExecuteSequence>
<Custom Action="InstallDeviceDrivers" After="InstallFiles" />
</InstallExecuteSequence>
Whenever I run my msi, I get the error "a program required for this install to complete could not be run".
setup.exe is copied to my INSTALLLOCATION, and I have verified this by looking in that folder when my msi fails.
I played with the value of the After attribute, but InstallFiles seems to be the right one since it maintains elevated user privileges. I had originally tried InstallFinalize, but that failed and I figured that it wasn't running with elevated privileges. The problem is, none of the other Actions I have tried work.
I then ran my installer with msiexec /i installer.msi /l*v install.log and looked over the output file. That's where I saw a slightly more specific error:
MSI (s) (74:CC) [14:06:10:098]: Executing op: ActionStart(Name=InstallDeviceDrivers,,)
Action 14:06:10: InstallDeviceDrivers.
MSI (s) (74:CC) [14:06:10:098]: Executing op: CustomActionSchedule(Action=InstallDeviceDrivers,ActionType=1058,Source=C:\Program Files\MyCompany\MyProduct\,Target=setup.exe,)
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 1721 2: InstallDeviceDrivers 3: C:\Program Files\MyCompany\MyProduct\ 4: setup.exe
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 2205 2: 3: Error
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1721
Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: InstallDeviceDrivers, location: C:\Program Files\MyCompany\MyProduct\, command: setup.exe
MSI (s) (74:CC) [14:06:11:800]: Note: 1: 2205 2: 3: Error
MSI (s) (74:CC) [14:06:11:800]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709
MSI (s) (74:CC) [14:06:11:800]: Product: Installer -- Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: InstallDeviceDrivers, location: C:\Program Files\MyCompany\MyProduct\, command: setup.exe
Based off of some searching, it sounded like I just needed to run as admin, but my installer already triggers UAC... and sure enough, running the installer from an elevated command prompt didn't help.
Can anyone recommend a next course of action for me to debug this? If you additionally have information on how to conditionally install based on the presence of a registry key, that would be really great, too. Thank you!
EDIT -- I have run my installer on Windows XP 32bit and Windows 7 32bit, and it fails on both. Yet another reason to believe it's not permissions-related.
EDIT #2 -- I don't know why I didn't try this before, but I changed from setup.exe to notepad.exe, and Notepad launched. So obviously the CustomAction works. I'll try again with Process Monitor to see where it's looking for setup.exe... or perhaps I just can't run an installer from within another installer?
I'd like to revise my answer to cover what I have learned that is relevant to what I think is a typical scenario:
You want to customize the bitmaps in the dialogs
You also might want to skip the licensing agreement.
You want to detect presence of some prerequisite, like the .NET Framework 4.0.
You want to write an installer that can install some other software, like a device driver, at the end of the installation process.
You want to use the presence of a registry key to make the previously-mentioned checkbox invisible
You might need to include a merge module, like the VC++ 2010 redistributable
First things first:
All of the information is on the Internet. I just spent hours wading through info and trying stuff.
Be patient, and don't give up!
Don't just rely on Google. The WiX documentation (in the .chm) has an enormous wealth of information. I suggest that you search there as well, if not first.
Did I say it already, "be patient, and don't give up!"
Skeleton WXS
Each of the sections below only have the information directly related to themselves. At the very end of the answer, I will post a skeleton (partially complete) .wxs.
Detecting the .NET Framework 4.0
First, you'll need to add a project reference to WixNetFxExtension. Then add this XML to your <Product> node: (search .chm for ".NET")
<PropertyRef Id="NETFRAMEWORK40FULL" />
<Condition Message ="This application requires .NET Framework 4.0. Please install the .NET Framework and then run this installer again.">
<![CDATA[Installed OR NETFRAMEWORK40FULL]]>
</Condition>
Customizing the Bitmaps
Found in Customizing Build-in WixUI Dialog Sets in the .chm. I only changed the following:
WixUIBannerBmp
WixUIDialogBmp
Just set them under the <Product> element:
<WixVariable Id="WixUIBannerBmp" Value="$(var.ProjectDir)\Bitmaps\mybanner.bmp"/>
<WixVariable Id="WixUIDialogBmp" Value="$(var.ProjectDir)\Bitmaps\mydialog.bmp"/>
I just create a Bitmaps folder in my WiX installer project in Visual Studio 2010.
Skipping the EULA Dialog & Setting the Installation Location
There are several built-in ways to define your installer's look and flow, but for those of us that are lazy, you'll only care about WIXUI_MINIMAL and WIXUI_INSTALLDIR. The former is only for the extremely lazy (this is what I originally sent to people!), but it doesn't allow the user to do anything but click Yes to install the program. It won't tell you that the installation is complete, either. WIXUI_INSTALLDIR strikes a nice balance, IMO. You get the typical welcome dialog, click Next through more typical dialogs, and get a Finish button at the end of the process.
Add a project reference to WixUIExtension, then use the following XML:
Creating an installer using Wix v3.0, Votive, and Visual Studio 2005/2008 - Part 2, the GUI (The Code Project)
How to build a minimal WiX Installer UI without a license page? (Stack Overflow)
WiX installer guidance (Stack Overflow)
1
1
Installing Device Driver at the End
If you want to install a device driver at the end of your installation, I think the easiest way is to just ensure that the driver's setup.exe is copied to your installation location and then executed from there. At least, that's what I did. Then you just need to use a CustomAction:
Custom Action Types (MSDN)
How To: Run the Installed Application After Setup (WiX on SourceForge)
But what if you want to allow the user to decide whether or not to install the driver? Then you do this:
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Install device drivers when the installer exits." />
and your <UI> node will now look like this:
<UI>
<UIRef Id="WixUI_InstallDir" />
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">1</Publish>
<Publish Dialog="ExitDialog" Control="Finish" Order="1" Event="DoAction" Value="InstallDeviceDrivers">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />
</UI>
The logic added above just checks to see if the checkbox is checked, and the "and NOT Installed" is there to ensure that this operation only runs when the installer is installing your application, not uninstalling.
Using a Registry Key to Control Availability of the Checkbox
Just add the following XML to Product:
<Property Id="DRIVERINSTALLED">
<RegistrySearch Id="DriverInstalledSearch" Root="HKLM" Key="SOFTWARE\DriverCompany\Settings" Name="SomeRegistryKeyThatMustBePresentIfInstalled" Type="raw" />
</Property>
and then use <SetProperty> instead of <Property>, as previously shown:
How do I create a conditional property in WiX? (Almost like an If-Then)
<SetProperty Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Install device drivers when the installer exits." After="CostFinalize">
<![CDATA[NOT DRIVERINSTALLED]]>
</SetProperty>
Merge Module
Finally, what if you need to add the VC++ 2010 Redistributable package? I wasn't sure of the best way to do this, and although my application worked when I did this (where it didn't before), I found it strange that Add/Remove Programs didn't mention anything about it actually being installed. So for this part, YMMV.
Since I run a continuous integration (CI) server that doesn't necessarily have Visual Studio 2010 installed, I put the merge module file into my WiX installer project. I made a folder called MergeModules and put it there. The file is located in Program Files\Common Files\Merge Modules, and is called Microsoft_VC100_CRT_x86.msm. Now put the following line in your <Directory> node:
How To: Install the Visual C++ Redistributable with your installer (WiX on SourceForge)
<Merge Id="VCRedist" SourceFile="$(var.ProjectDir)\MergeModules\Microsoft_VC100_CRT_x86.msm" DiskId="1" Language="0"/>
and the following line in your <Feature> node:
<Feature Id="VCRedist" Title="Visual C++ 10.0 Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<MergeRef Id="VCRedist"/>
</Feature>
Skeleton WXS
I'm providing an incomplete skeleton .wxs below. It's incomplete because I'm only providing the element names for the stuff that isn't directly associated with this post. The missing information is easy to find.
May I suggest a different approach. Use a bootstrapper such as WiX Burn to check if the driver is installed and if not, install it as a prerequisite. Then launch your MSI installer. The WiX bundle would look something like:
<Fragment>
<util:RegistrySearch
Variable="DriverInstalled"
Root="HKLM,SOFTWARE\Microsoft\MyProduct\[UniqueId]\Setup"
Key="InstallPath"
Result="Exists" />
<PackageGroup Id="DriverPackage">
<ExePackage
SourceFile="Path_To_Driver\Setup.exe"
InstallCondition="InstallPath" />
</PackageGroup>
<PackageGroup Id="MainMsi">
<MsiPackage
SourceFile="Path_To_Msi\Installer.msi"
After="DriverPackage" />
</PackageGroup>
</Fragment>
Note: I did not test the above, but that should get you started if you go that route. If you're interested I would recommend looking up WiX bootstrapper bundles and Define Searches Using Variables explains how you can use the util extension to search the registry in your bootstrapper, similar to how you do it in the installer. This approach has the benefit of not mucking up your installer with custom actions.