Ensure Administrator privileges for Modifying/Changing an already installed MSI? - wix

I have a Wix project I'm modifying. It has to be installed for All Users and write to HKLM. So, in the Package I have:
<Package Id="*" InstallerVersion="405" Compressed="yes" InstallScope="perMachine"
InstallPrivileges="elevated"
Manufacturer="$(var.Publisher)"
Description="$(var.ProductName) $(var.Version) Setup" />
I also have other checks that may be working or not...
Stuff like:
<CustomAction Id='IsPrivileged' Error='You must be an admin to install this product' />
<InstallExecuteSequence>
<Custom Action='IsPrivileged' Before='AppSearch'>Not Privileged</Custom>
</InstallExecuteSequence>
What little I had, ensure that when installing or uninstalling, it would need to elevate. However, people also want to modify ... and that's when it I encountered problems.
WHen I took over, the installer had the ARPNOMODIFY set to disable modifying. Since it would be nice to be able to modify, I commented out that line:
<!--<Property Id="ARPNOMODIFY" Value="yes" Secure="yes" />-->
So, now I can "Modify" or "Change" it depending on whether it's done from the Remove Programs UI in Windows or by running the installer again.
However, it doesn't work at all. Registry entries get erased, and when run that way I never get a UAC prompt. It just tries to run the installer.
I've been at it a long time and can't figure a way to get the Modify/Change to elevate. It just goes ahead and tries to run and messes everything up. ISTM that it should ask to elevate before beginning the InstallExecute sequence, but it never does.
How can I get it to elevate or require admin privileges?
I'd prefer to find a way to elevate, but in lieu of that, I'd be happy if it was blocked from continuing. But it just wants to run and hose my installation.

You can block a repair/modify from the ARP by conditioning off the MSI property RestrictedUserControl=1. If this property is set, it means that the installer is being executed 'without' admin privileges.

Related

How to restrict user to change feature in case modify and upgrade in installer?

I have a installer which asks the user to select feature. Whatever user selects, it will never be changed in case of modify and upgrade the installation. For example:
There are three features in my installer which are below:
<Feature Id="Standalone" Title="Standalone" Level="2">
</Feature>
<Feature Id="CentralCase" Title="Central case" Level="2" >
</Feature>
<Feature Id="MiddleEF" Title="Middle Ef" Level="2" Display="expand">
<Feature Id="GUI" Title="Client" Level="3"></Feature>
<Feature Id="AppServer" Title="Application Server" Level="3">
</Feature>
</Feature>
Now suppose user starts the installation and select the first feature which is standalone and install it. Now if user wants to modify, he should not allowed to change feature or even if user wants to upgrade, user should also not allowed to change feature. He can only upgrade what he selected at first time. Is there any way to do this?
ARPNOMODIFY: I guess it depends how critical it is that these features never change. You can set the ARPNOMODIFY in the MSI to
1 and there will be no button to invoke Modify from:
<Property Id="ARPNOMODIFY" Value="1" Secure="yes" />
Disclaimer below. Here be dragons.
msiexec.exe: However, you can still invoke modify by launching the MSI file itself (the default dialog sets should correctly disable the modify button though), but worse: you can go via the msiexec.exe command line and change anything you want:
msiexec /i "MySetup.msi" ADDLOCAL=MyFeature
This might be OK since it would appear to be seldomly used. However, you should be aware that remote management systems often rely on the msiexec.exe command line to handle MSI deployment, and as such the deployment system could be used to change feature state easily (via the deployment tool GUI, no command lines to deal with).
Custom Action: I don't know of an auto-magic way to abort setup if the user tries to modify the feature structure invoked via the msiexec.exe command line, but I suppose you can use a custom action maybe right before InstallInitialize in the InstallExecuteSequence to abort the installation if ADDLOCAL, REMOVE or ADVERTISE are set? If you do not condition this custom action properly, it could cause a package that won't uninstall at all or upgrade properly.
Some unverified conditioning suggestions: How to execute conditional custom action on install and modify only?
MigrateFeatureStates: For a major upgrade the GUI will not run as if it is running modify, but a fresh installation (since the product GUID is new). Hence the original installation GUI is shown and not the modify one. Accordingly you might need to disable some GUI controls or hide whole dialogs to prevent feature selection (not sure in WiX default dialogs). Added a link for that below. The standard action MigrateFeatureStates will take care of preserving the feature installation states between versions, provided you haven't done anything drastic to the feature structure. You enable this standard action to run in the Upgrade table. Should be default to run in WiX MSIs I think.
UPDATE:
Preselected Property: There is a special property called Preselected that is to automatically hide feature selection. You can try to set it or check whether it is set automatically by WiX to see if it hides feature selection. I have honestly never tried it.
Some Further Resources:
Hiding whole dialogs: Wix, custom dialog when previous version exists

Cannot run msi as administartor

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.

Wix Installer - create installer that always re-installs over tself

I am trying to create an installer that doesn't "carry" any files but does set a registry key and create a small folder structure (if not present)
The script does use CopyFile to copy files from a network location to a folder on the c-drive.
The idea is to create an installer that can be re-run whenever the network files are updated so that they are brought local for the user.
The CopyFile code has a RemoveFile line just ahead of it (in same component) so the file should always be copied "fresh"
The folder structure and registry key don't really need to be repeated but won't matter if they are.
I am also not worried about an uninstall (nor what it does as this install is always needed) but I can't create install after install in the system so I do need to be upgrading somehow.
I have (currently got) these bits of script in my wxs file
http://schemas.microsoft.com/wix/2006/wi'>
<Product
Id='*'
Name='Eclipse Template Installer'
UpgradeCode='$(var.ProductUpgradeCode)'
Version='$(var.ProductVersion)'
Manufacturer='Article 10'
Language='1033'>
<Package InstallerVersion='200' Compressed='yes' Comments='Windows Installer Package' />
<Media Id='1' Cabinet='product.cab' EmbedCab='yes' />
<Upgrade Id="$(var.ProductUpgradeCode)">
<UpgradeVersion Minimum="$(var.ProductVersion)" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
<UpgradeVersion Minimum="0.0.0" Maximum="$(var.ProductVersion)" IncludeMinimum="yes" IncludeMaximum="yes"
Property="OLDERVERSIONBEINGUPGRADED"/>
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize"/>
</InstallExecuteSequence>
When I run the Installer for the first time, it works. Files are copied and all good.
I then tweak one of my copied files to force a new date/time on it and re-run the installer. It pops up indicating it is gathering info but doesn't then replace the file with the older version so I think the installer has concluded it needn't do anything as the current "latest version" is already installed?
If I choose Repair in Programs and Features the file does get updated.
I tried setting the IncludeMaximum to a yes but that doesn't seem to help. Same result.
I have also tried the MajorUpgrade command instead of the InstallExecuteSequence but I get the same end result. Maybe for different reasons but not really sure. Maybe not using it right.
Can anyone tell me how to force my installer to redo everything it originally did even if the version matches?
My client can't make new MSI files so updating the version and rebuilding isn't an option. They just want to update the network files (templates) and rerun the MSI to get the files local.
The first run of the MSI also configures their machine for the templates so it is all very simple, which is what they wanted.
Thanks
Simon
Might be a bad idea (I'm not sure what else this product/tool is supposed to do), but you could condition the MSI standard action "PublishProduct" to '0' so that it never runs. This way, your MSI will install and never register itself on the machine. You can continue to run your installer over and over, and it will never detect that an older version is installed.
This is, of course, not the 'correct' way to go about things, but it works.

How to modify xml on wix repair

I have an installer that is created with WIX and modifies a config via XmlFile, however I believe that the Wix Util Extension does not perform these actions on repair. This is causing problems when trying to perform a self-healing installer. Is there any way to accomplish what I am looking for
By piecing together a bunch of sources I came up with the following:
<Property Id="REINSTALLMODE" Value="amus"/>
<SetProperty Id="REINSTALL" Value="ALL" After="AppSearch">
<![CDATA[Installed AND REMOVE<>"ALL"]]>
</SetProperty>
Which forces a REINSTALL = ALL if it is not a remove or install
I have a similar scenario. Properties can be edited by the user through the UI, which are stored/loaded via the Registry and written to configuration files. Beyond Justin's answer, Secure="yes" must be set on each property, or MSI will ignore it (the log will show "Ignoring disallowed property").

How do I detect an application was installed via ClickOnce, using WiX?

I'm writing a WiX installer for an application which was deployed previously using ClickOnce.
I would like to detect if the application was installed on the client computer and abort the MSI installation. I searched similar questions on Stack Overflow, but I couldn't find a way to do that.
If I can find a path or some registry key that tells me where the application was installed, I can abort the MSI installation via a Condition.
Using the answer for this question, I was able to get somewhere. The ClickOnce shortcuts are files with the .appref-ms extension. This is the code I use:
<Property Id="APP_CLICKONCE_INSTALLED">
<DirectorySearch Id="dirSearch.APP.CLICKONCE" AssignToProperty="yes" Path="[StartMenuFolder]" Depth="2">
<FileSearch Id="fileSearch.APP.CLICKONCE" Name="APP.appref-ms" />
</DirectorySearch>
</Property>
<Condition Message="App is already installed. Please uninstall it then re-run this setup.">
<![CDATA[APP_CLICKONCE_INSTALLED = "" OR INSTALLED]]>
</Condition>
However, StartMenuFolder gives the location for AllUsers profile, whereas the click once application is installed for the current user. I am still digging.
Using perUser installation the StartMenuFolder gives the current user location (I was using perMachine):
<Package InstallerVersion="200" Compressed="yes" InstallScope="perUser" />
All is good now.
I don't know anything about WiX, but another way to tell if a ClickOnce application is installed is to iterate through the uninstall strings in the registry, which are here:
HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
You'll want to search for one where the product name of your application matches the Display Name for that set of keys.