Elevated Immediate Custom Actions - wix

I have a request that I know many will shout about but I don't have any other way around it. In my WIX setup I have a dialog that uses the properties set in the setup to determine a product name(with version type etc) that ties in with our algorithm and a lock code that needs to be produced. Based on these the user enters their unlock key and the custom action pulls the details from all three text boxes to ensure it is correct. I did not write the algorithm for creating these and unfortunately can't change it.
My issue is that I need to be able to create a product key in the registry before this dialog so that my lock code algorithm can read from it. So basically I need my custom actions to be elevated. I read somewhere that someone implemented a custom action to call msiexec but now I cannot find it and don't know how to go about creating this. Has anyone ever had the same issues? I have been reading that people have but I can't seem to find their solution or even if there is one. Thanks in advance

Immediate custom actions CANNOT be elevated. Period, end of story. #FACT
What can you do?
1) Use a setup.exe bootstrapper that is manifested to require admin and a Launch Condition in the MSI that enforces it was launched by the bootstrapper. ( Bootstrapper passes a property to the MSI SETUPEXEDRIVEN=1 is what InstallShield calls it. ) This ensures that the entire UI sequence is elevated. (Not a best practice but I'm putting it out there for you.)
2) Write to HKCU instead of HKLM ( will likely require license code to be refactored but hey it was a broken design anyways. )
3) Refactor the installers interface to the license API. I've done this before. I once worked for a company that expected the installer to call an EXE to validate a license. One big problem is the EXE is out of process and cannot communicate back to the installer. So they started writing "ISVALID" to the registry and I was then expected to write a VBScript around the EXE to flush the value, call the exe and then check the value and set the MSI property. Ummmm can you say #FAIL? The optimal solution was to force the dev team to create an API for the license code that I could call directly from a standard MSI custom action that didn't require elevated permissions or any other hackery.

Related

How we can store values of variables across Bootstrapper and MSIs getting called from that Bootstrapper

I have created a Wix Installer which has following structure
It has Bootstrapper
It has MSI1
It has MSI2
The task of Bootstrapper is to provide options to user as which
application he wants to install. Based on his selection MSI1 or MSI2
will be launched.
Now both MSIs need to collect information of Database.
My requirement is that if I collect DB information from MSI1, I want to pass that information to MSI2 from Bootstrapper(as after MSI1 user will choose MSI2 from Bootstrapper)
We don't want the end user to provide this database information again and again.
Please note that we cannot collect the database information from Bootstrapper itself, as the user may go to installer source and execute MSI1 or MSI2 directly.
Any one has idea how we can store values of variables across Bootstrapper and MSIs getting called from that Bootstrapper?
Write that information to a well-known registry location during the installation.
Here's a resource to the "remember me pattern" blog post that Rob has written. I know it's bad practice to just link a blog post that may not exist in the future but I also don't want to just copy most of it.
The basic idea is to save properties that may be defined by the user at run-time into the registry. When you run the installer again, you can try to read that registry location and load up the properties from a previous run of the installer so you already know what the user is going to write.
In this case, your 2nd installer will know about the well know registry location that the first installer will write the db information to. Now the 2nd installer can read this information when it is run afterwards and use it during hte installation which means the customer doesn't have to re-enter the same information for both installs.
You can combine this with custom actions to encode sensitive information and decode it at run time. This is also a very commonly used technique for remembering the install directory of a product as this is something that is commonly changed by the user at run-time.
I reread the question and realized that getting the information from the bootstrapper is not something you can do but I'll leave this part of my answer here anyways. [I think you could gather the information in the bootstrapper and pass it to the MSIs. Just write that information during the install to a registry location and you can read it if it exists when installing if the user runs just from the MSI]
Alternatively you can update your bootstrapper's UI to gather this information and pass it in to both installers. This requires a bit of research into how the bootstrapper application works and how it generates its UI and stores properties. And again, you should use the remember me technique to read the already entered properties from the registry if they exist so you can pre-populate fields with the previous values on subsequent runs of your installation.

Uninstall from Control Panel is different from Remove from .msi

Is there a difference between uninstalling an application with WiX based .msi from Control Panel and from the .msi itself?
If there is what is it?
I am asking because of the following reason:
The difference is the following: my .msi stores some files in %PROGRAMDATA%. If i uninstall from Control Panel the files there get uninstalled (it seems that the .msi keeps track of those (they are defined as components)), but when I open my .msi and try to uninstall (I have a maintenance dialog) those files don't get deleted.
Another difference is: I also have a Custom Action to stop my Application if it is running which is being called After="AppSearch" in the InstallUISequence and Before="CostFinalize" in the InstallExecuteSequence but when removing from the .msi it isn't being called. Only a dialog shows that says that there are files to be deleted but are being usedbut some processes and when I tell it to stop them it doesn't do so.
The following "discussion" got a little out of hand. But I will leave it here as an explanation for people who research differences experienced between silent mode and interactive mode installs.
Yes, the short answer is that you can indeed see different installation or uninstallation behavior depending on how you invoke the (un)install.
This has mostly to do with how an MSI can run with different user interface levels, and this causes the entire user interface sequence (InstallUISequence) in the MSI to either be run or skipped entirely (silent installation). Once skipped, all custom actions defined only in the InstallUISequence will not run at all. If the MSI is well-designed, this is not a problem since user interface custom actions run in immediate mode and should never make changes to the system - they should just inquire for user data and settings, system state or help the user enter proper data for the installation. If the MSI is not well designed and changes are made to the system in the user interface, the installation will be incomplete when running in silent mode. This is a serious MSI design error which becomes all the more serious when you realized that all major corporations deploy software silently. I have seen such errors many times when doing corporate application repackaging. It is not a vote of confidence for the software, no matter how good it is. Weird and unpredictable problems are bound to surface.
Accordingly, the InstallExecuteSequence (which is the only one that runs when the setup is installed silently) should have all required custom actions that make system changes inserted there for an MSI to be correctly designed. As already stated, custom actions existing only in the user interface sequence should deal with getting values and settings from the user, whereas these values should be set and defined by command line or defined in transforms for a silent install.
Certain odd and erroneous combinations of custom action conditions can also cause differences between interactive and silent installs in special circumstances. And finally putting custom actions after InstallFinalize in the InstallExecuteSequence can cause actions to fail when run silently. There are certainly other potential problems as well.
In summary, if you do see a difference in installation behavior based on the user interface level, your MSI contains a serious design-flaw. You should always ensure that your MSI can be run silently with the equivalent result as interactively. And as already stated large corporations never run installations interactively since they push out software via software management systems such as SCCM.
There are 4 MSI UI levels ranging from fully silent to fully interactive:
INSTALLUILEVEL_NONE = 2, (totally silent)
INSTALLUILEVEL_BASIC = 3, (progress bars and simple error handling)
INSTALLUILEVEL_REDUCED = 4, (authored UI, no wizards)
INSTALLUILEVEL_FULL = 5 (full UI)
The important point is that for UILevel 2 and 3 the InstallUISequence is skipped.
There is an MSI property UILevel holding the GUI level value 2, 3, 4 or 5. Check this property if your custom action must take the user interface type into account. This is obviously most important for totally silent installs that should never show any dialogs.
When you right click an MSI and select uninstall you are generally running UILevel 3 (Basic UI with progress bar). This means the InstallUISequence is skipped.
When you uninstall from Add/Remove programs the normal UILevel is also 3 - basic user interface. This means the InstallUISequence is also skipped.
If you double-click the MSI and run uninstall, your GUI level is 5 - full GUI. The same happens if you select "Change" in add/remove programs.
In summary, it is possible for bugs to occur in only one of the modes (silent / non-silent) because the MSI's user interface sequence is skipped along with all its custom actions for certain user interface levels. In other words, a product could work when installed interactively and fail when installing silently (or vice versa), if the MSI is badly designed.
It is also possible to condition custom actions in the main MSI installation sequence erronously based on this UILevel feature so that results differ based on installation mode. I have seen people spawn dialogs from code in custom actions placed in the main installation sequence (where no interactivity is allowed) and then use UILevel checks to suppress the dialog in silent installation mode (or they forget that as well, triggering a hidden modal dialog that stops the install dead when running in silent mode). These weird design constructs cause unexpected installation behavior based on how the install is triggered and run.
Though this is sort of not an answer to what you asked, a final conclusion from all of this is that if your software is intended for large corporations you should not waste your design efforts on an advanced GUI for your setup as it is likely never to be used for large-scale deployment scenarios. Rather you should parameterize your installer with public properties that can be set at the command line or via a transform so that your installer can be controlled easily without running it interactively. See this post: How to make better use of MSI files.
Since I have gone so far beyond your question, I should also note that some advanced installers intended for server installations may (with moderation) benefit from a good GUI to help people quickly get your server software installed and tested. These installers tend to meddle with very advanced features such as IIS, MS SQL, AD, etc... and some interactivity could be desired for knowledgeable system administrators. But as the saying goes "most things can default" and good default settings are generally easier for people to get installed and tested whether knowledgeable or not. Many large companies run large farms of server virtuals these days (one virtual server per use case), so even server installs tend to get automated for large-scale rollout and then a good parameterized installer with public properties to set is appreciated. Smaller companies may also have server virtuals (making testing easy), but they are likely to install your setup interactively accepting whatever defaults are there - at least that is my impression.
Links:
Is it possible to passively install an .EXE but still show the GUI using Powershell?
There is no practical difference between right-clicking an MSI to uninstall it, and using Control panel to uninstall it. Both result in a minimal UI (not totally silent, shows progress bar) uninstall, and will ask for elevation if required.
If you have a maintenance mode dialog in your setup then you may have a slightly different path - you may show a dialog that offers to change features, repair, or uninstall. That might result in a difference somewhere.
If there is some code somewhere that alters something, then who knows? An uninstall from a dialog might choose to suppress the Cancel button, as a random example.

Wix custom action is failed to load the dll file?

I am trying to do a custom action at the time of msi installation. But the dll required for my custom action is depends on other dlls. At the time of installtion it is giving the error like "a dll required for this install to complete could not run".How can I load the dependent dll files for this custom action to run properly.
The code that I am using is
<CustomAction Id='CheckingPID' BinaryKey='CheckPID' DllEntry='ValidateKey' />
<Binary Id ='CheckPID' SourceFile='$(sys.CURRENTDIR)\LicenseKeyClient_32d.dll'/>
<Binary Id ='CheckPID2' SourceFile='$(sys.CURRENTDIR)\curllib.dll'/>
<Binary Id ='CheckPID3' SourceFile='$(sys.CURRENTDIR)\libsasl.dll'/>
<Binary Id ='CheckPID4' SourceFile='$(sys.CURRENTDIR)\openldap.dll'/>
The files that you add in binary table usually get extracted with temporary names during the installation, so your DLL will not be able to locate the other DLLs you add next to it.
A workaround is to add those DLLs as normal files in the Temp system folder and delete them when the installation ends. This has the limitation that you need to set your custom action as deferred, so it executes after the files are installed, thus your DLLs get copied to Temp folder.
I don't know if wix has a support for temporary files, similar with the one present in Advanced Installer, but if not you could try to write a custom action to simulate it. Basically what Advanced Installer does is to extract those files in the Temp folder the moment the MSI is launched, and also deletes them when the installation is complete. This has the advantage that you can use the temporary files and in immediate custom actions, i.e. well before the files from your package are installed.
Despite Bogdan's excellent answer, allow me to add my 2 cents:
It looks like you are dealing with some form of license key validation? The best way is generally to deal with your license keys in the application itself, unless you want it written to HKLM instead of HKCU - in which case you might need the temporary admin rights generally acquired during installation.
You can also open a HKLM key for writing during setup, and write it from the application though this is generally frowned upon security-wise. This allows you to write a single license key for all users directly from the application.
The application features more flexibility and control of the process of registering your license key, and crucially an easy way to run the process again. From my perspective this is almost always needed for a serious application - often due to trial versions with the eventual need to register the license key at the end of the trial period from within the application itself - instead of uninstalling the application and reinstalling, or running the setup in repair / maintenance mode - which seems extremely clunky.
I have described this issue previously in some more detail: Reasons to deal with licensing in the application rather than the setup.
I'll also add that WiX DTF .NET custom actions really simplify this problem by allowing you to embed content into the self extracting custom action package and make them available in the current directory at runtime. Very easy.
But yes, Glytzhkof is correct. Any licensing / DRM done inside of an MSI is easily defeated. It's best to do this in the app or both. For example I've worked at companies where it's a share responsibility. You can enter one now or later. I've also worked at companies where the license key had bits embedded in it that drove feature selection. It gets complicated fast so try not to have to go down that road.

At what step of MSI (InstallExecuteSequence) UAC is prompted?

When I execute my MSI with UAC ON the UAC is not prompted for some time. I am trying to read some registry entry in a custom action before "CostFinalize". My Registry read function will consider a default value if registry entry is not found. But in my case the registry entry is there but it fails to read because the key doesn't have read permission for "User". Although Admin have full permission.
Registry read seems to be happening before UAC prompt. How can i make sure UAC is prompted at start only so that registry read can be successful.
Issue explanation
We have an old installer written in WIX. Where we are writing a registry entry for install location something like this
HKLM\Software\CompanyName\Product\Install\CompInstallDir = [InstallDir]\Product\Component.
This registry entry does have permission for Admin only even user doesnt have read permission I dont know why (i didnt write that code). there are some other entries under HKLM\Software\CompanyName\Product\Install
Now I have to make changes in the installer code for upgrade. In which i have to read this install location i.e., [InstallDir]Product\Component and trim it to [InstallDir]. So I already have an existing custom action (from previous installer code only) which reads the registry and sets Property INSTALLDIR, also some other properties and do backup of some config files. This custom action is under "InstallExecuteSequence" which as per my understanding should prompt for UAC if required. This custom action is called before "CostFinalize".
The thing which should have been there in old installer is Writing a registry entry containing only [InstallDir] which wasn't in place. Due to which that custom action is in place which is not a good way of doing, but being legacy code have to maintain it :(
Hope I am able to explain my problem :)
In this SO thread I explain how UAC prompts are triggered.. Basically, you need a bootstrapper, and in its manifest set the execution level accordingly.
Regarding the custom action to read the registry. Why don't you use the built in support from Windows Installer to make a registry search, using AppSearch and RegLocator tables? As a general rule, its not recommended to reinvent the wheel. A default value for the search can be specified by simply defining the property (name of the search) in Property table.
The normal best practice is for the Install UI sequence to run as standard user and for the Install Execute sequence to elevate if the MSI is built to require it. ( For example a per-user install writing to per-user locations might not ever need elevation ).
The other best practice is to use AppSearch to read registry values into properties. The AppSearch also runs in the InstallUI sequence so normally the expectation is that these reads can be performed using standard user permissions.
In your case, you require admin to do the read. In all my years writing hundreds of installers I've never had that requirement. To give you better advice I'd have to ask what is the nature of this registry value and why is it only readable by administrators? After you read it, what do you intend to do with it?
Options include a bootstrapper to elevate the entire installer including UI sequence but that's usually not advised. Otherwise you need a deferred custom action running without impersonation (SYSTEM context) to do the read but at that point you can't set a property so you'd have to use the registry value right there for whatever purpose is intended.
Very strange requirement... I'm detecting a code smell.

BURN (WIX bootstrapper) - files in use dialog not being shown

I have created a WIX msi for one of our products which works really well. The product is a Word addin and at upgrade/uninstall the msi automatically checks if Word is open (ie. my assemblies are currently locked in execution) and if it is, then it comes up with the Files In Use dialog.
The only improvement I would like to make is at installation time. I would like to check whether word is open and force close before install. It would be great to do so, using the same Files In Use UI. Is there an easy way to do this?
I have also created a custom bootstrapper (unmanaged), using the sample code from the toolset. Overall this is really good too, however I have real problems when upgrading/uninstalling. Ideally, I don’t want to DisplayInternalUI but I would like the Files In Use to pop up when necessary. Is this possible?
The feature request 4382 was implemented and is available in v3.10.0.1726. Set ShowFilesInUse to yes in the WixStandardBootstrapperApplication element.