Change install path of MSI setup while repairing - wix

I am trying to repair an installed msi setup with below argument:
msiexec /f "msipath"
It is repairing properly. But while repairing i need to change its install path too. I tried this argument msiexec /f "msipath" INSTALLDIR="path"
But this is not working.
Whether it is possible to change the install path of an msi while repairing it?. If possible means, please share the exact argument.

It is not possible. For a component to be moved, it must be uninstalled and then reinstalled. (Repair just replaces resources in their original locations.) Consider this note on MsiSetTargetPath:
Do not attempt to configure the target path if the components using those paths are already installed for the current user or for a different user. Check the ProductState property before calling MsiSetTargetPath to determine if the product containing this component is installed.
Thus you typically have to remove and reinstall the entire package. A major upgrade can be a good way to accomplish that, depending on your other needs.

Related

Making changes to installed MSI

I will try to explain the issue by example. I have mypackage-v1.0.msi and mypackage-v1.1.msi. Both packages when installed silently expecting PASSWORD parameter:
msiexec /i mypackage-v1.0.msi /qb PASSWORD=SomeThing1
mypackage-v1.0.msi is already installed and mypackage-v1.1.msi should upgrade mypackage-v1.0.msi. There is a custom action in both packages that depends on this parameter but because of the issue with conditioning this custom action in mypackage-v1.0.msi, during upgrade it is executed but the PASSWORD parameter is not transferred to it.
I wonder if there is a way to patch mypackage-v1.0.msi before upgrading to mypackage-v1.1.msi. But the patch is not changing any contents of installation but the package itself. Is it possible?
Edit:
More focused input - is it possible with the patch to replace a condition for InstallExecuteSequence custom actions?
Yes. Patches include transforms, which modify packages. In fact, patches always modify tables in the package, even when they don't change content of the payload files.
The comments above became too messy. Here is a quick re-write as a regular answer:
Minor Upgrade: A minor upgrade can change most things in an installed MSI package before its uninstall or upgrade sequence is called. It can hence fix problems relating to major upgrades or failed uninstalls among other things (you fix the uninstall sequence before it is invoked).
Sample: Here is the simplest sample of a minor upgrade I could find at the moment (another sample from FireGiant's documentation).
For the simple sample: open the CreatePatch.cmd and update path to WiX binaries (likely ending in v3.11 at this point in time: set wixDir="C:\Program Files (x86)\WiX Toolset v3.11\bin\").
Keep in mind that a minor upgrade has many limitations. Keep things simple and change only what you need to fix your problem.
Minor Upgrade Details: The table at the bottom here shows what needs to change for a minor upgrade. Essentially package code and product version + plus whatever change you want to implement. The above link is to InstallShield's documentation (a different MSI tool), but this is a generic MSI technology concept - it is not vendor specific.
You can deliver the minor upgrade as a new MSI or as a patch file (*.msp). For an MSI you need to use a special command line to install. Something like this:
msiexec.exe /i MySetup.msi REINSTALLMODE=vomus REINSTALL=ALL
The v tells msiexec to re-cache the MSI so that it updates the existing cached one "in-place".
REINSTALLMODE documentation.
Applying Small Updates by Reinstalling the Product.
Links:
https://support.firegiant.com/hc/en-us/articles/230912367-Upgrade-options
https://www.firegiant.com/wix/tutorial/upgrades-and-modularization/

Uninstall msi with full ui mode condition (wix toolset)

I've added the following to my WIX template to prevent installation without entering values in a custom dialog i've made.
<Condition Message='This installation can only run in full UI mode.'>
<![CDATA[UILevel = 5]]>
</Condition>
When I try to uninstall the application I get this message, and I'm unable to proceed.
How do I fix this so that it does not apply on uninstall?
How can I forcibly uninstall this application?
Question 1: LaunchCondition
LaunchConditions must always evaluate to true for the setup to be able to install / run. There are some further details here: Failing condition wix (recommended for more context). When you invoke uninstall via Add / Remove Programs it will run the installer in silent mode (I believe UILevel = 2 or UILevel = 3), which fails your LaunchCondition since UILevel is not equal to 5.
OR Installed: A common technique to prevent LaunchConditions to trigger problems in other installation modes than fresh install, is to add OR Installed to the LaunchCondition in question. This will force the LaunchCondition to be true for all situations and modes where the product is already installed (modify, uninstall, repair, etc...).
So something like this could probably work as an updated condition:
Installed OR UILevel = 5
Wrong Approach?: With that said I would rather implement a check to determine if the value you need specified has been set on the command line via PUBLIC properties for a silent install, instead of that rather strange LaunchCondition checking the setup's GUI level. You can still implement this as a LaunchCondition - or use a custom action for more flexibility. The LaunchCondition would check for values for all critical setup parameters, and you would prevent them from running on uninstall and other modes with the OR Installed mechanism. Here is an answer on the topic of silent installation, transforms and public properties: How to make better use of MSI files (silent deployment is crucial for corporate deployment and software acceptance).
Question 2: Forcibly Uninstall
UPDATE: A couple of additional options listed towards the bottom for completeness.
2.1 - ARP Modify: I want to run the simplest option by you before going into too much crazy detail. Is the Modify option available for your setup in Add / Remove Programs? If so, please click it and see if you then can select remove from the setup's Modify dialogs. This should work (since you are generally not running the setup in silent mode when choosing Modify).
2.2 - Interactive msiexec.exe Uninstall Command: I forgot to add that you should be able to kick off an interactive uninstall via command line as follows: msiexec.exe /x {PRODUCT-GUID} /qf. Here is how you can find the product GUID: How can I find the product GUID of an installed MSI setup? So in summmary: you find the product GUID as explained in the link, and then you open a cmd.exe window and fire off the uninstall command indicated above.
2.3 - Microsoft FixIt: If the first option above is not available, there are several other options that could work, but before trying them I would recommend giving the Microsoft FixIt tool for installation / uninstallation problems a chance to see if this does the trick for you. Run it, select your installation and see if some auto-magic is there for you to get it uninstalled.
2.4 - Advanced (avoid if you can) - hack system-cached MSI: This answer will be the next step, if the above fails: I screwed up, how can I uninstall my program? Please let us know if the above does not work, and we will check the options here. I would just zip up the cached MSI and disable the launch condition, but this is way too hacky for comfort if you can avoid it.
UPDATE: The below was added, but not needed to solve the problem. It is not recommended, it is the last resort. Leaving the content in.
Finding Cached MSI: you can find the system cached MSI using Powershell as explained here. I will inline the Powershell command here:
gwmi -Query "SELECT Name,LocalPackage FROM Win32_Product WHERE
IdentifyingNumber='{PRODUCT-GUID}'" | Format-Table Name,
LocalPackage
You then open the cached file (make a backup of it first, or zip it) with Orca or an equivalent tool, and you make whatever change needed to get the uninstall to function correctly. This is not generally considered a sane approach - it is the last resort. And what you change in the MSI is different depending on what is wrong with it. This requires specialist MSI knowledge. It is easy to mess things up so uninstall becomes even more difficult.
I just saw you got the product uninstalled whilst writing this. Puh! Be glad you don't need this latter approach. I think I will commit it and set it to strikeout so it is visible but not recommended (if only for myself to reuse if needed).
UPDATE, some additional alternatives (not always applicable, included for reference and potential re-use): 1) If you have access to the original MSI used to install your software (it must be the exact copy of the MSI used to install), then you can try to double click it and this should take you into modify directly. 2) You can also double click the file in the system cache folder if you no longer have the original installation MSI. 3) It might be you can hotfix the uninstall string in the registry as well to force a non-silent uninstall:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
There are probably further ways. For example 4) hack a transform to apply during uninstall, 5) patch the installed MSI (if it is in the wild with lots of installs everywhere), etc...

WiX repair from managed bootstrapper fails to fix some corrupted DLLs

I have a WiX Managed Bootstrapper Application that installs some MSIs. I also have a series of tests that exercise the various functions of the installer. The problem I'm having is with the repair test. The test purposely corrupts all the DLLs we install then calls the EXE installer with "/repair /passive" flags. Once completed around 80% of the DLLs are repaired but the remaining ones are untouched and therefore still corrupted after the repair.
If I manually run msiexec on an individual MSI with the command line args "/fa" which instructs the MSI to forcibly replace all the files it installed, it fixes 100% of the DLLs.
My question is how can I force the MBA to instruct each MSI to repair in this way? I've tried setting the REINSTALLMODE property to 'amus' on the individual MSIs in their .wxs files but the MBA overwrites them at run time as is evident in the log via this line:
PROPERTY CHANGE: Modifying REINSTALLMODE property. Its current value is 'amus'. Its new value: 'cmuse'.
I've also tried to set the properties in the MBA to pass through to each MSI but it doesn't appear to pass them and instead uses it's default values.
I see many similar questions here but none actually address this specific issue. Any help would be greatly appreciated. Rob save me!
Here's your problem right here:
[12:25:25:874]: File: C:****\estimator.dll; Won't Overwrite; Won't patch; Existing file is unversioned but modified
The installer doesn't want to overwrite a file that has changed since it was installed if it cannot verify the version or language (and maybe some other properties?). Without these properties, it decides to look at the modified date. If it is newer than when it was first installed then it won't touch it assuming instead that something changed for a reason and reverting it will cause something to fail. (You can read more here)
One thing you can do in this case is use a Companion File
Set this attribute to make this file a companion child of another file. The installation state of a companion file depends not on its own file versioning information, but on the versioning of its companion parent. A file that is the key path for its component can not be a companion file (that means this attribute cannot be set if KeyPath="yes" for this file). The Version attribute cannot be set along with this attribute since companion files are not installed based on their own version.
Basically you will set the logic for installing/uninstalling this component to be the same as the "FileID" of another component in the install. In the estimator.dll component, in the File tag, remove KeyPath="yes" and instead replace that with CompanionFile="<NameOfAnotherFileID>".
The issue with this approach is that you may have a corrupted DLL but the companionFile it was linked to was fine so it is not reinstalled.
If this is a dll you do own, I would highly suggest versioning the file! Give it any version you want and this issue should go away.
Another thing you can try, although I don't know how it works really, is giving the file a DefaultVersion
This is the default version of this file. The linker will replace this value from the value in the file if the suppress files option is not used.
This would be the quickest solution to verify. Just build a new installer with DefaultVersion="1.0" in the estimator.dll's <File> and see if it gets replaced. I think this will have the installer think the file is versioned 1.0 but the installed file is not versioned so it will replace it (see here)

How to determine the folder that a previous WIX Install installed a program in

The existing installer for our product does not write any information to the registry, nor does it write any custom environment variables. The user is allowed to change the install directory in the installer's UI. When I'm doing an upgrade, how do I find out what folder the previous version was installed into?
I need to know the folder so I can find the previous configuration file & copy values from it. The new version's configuration file has new tags and a new structure, so I can't just keep the previous file & reuse it.
Tony
MSI doesn't have that information directly. (MSI packages can have multiple "root" directories, so there's no telling which one a developer might want.) If you have the directory in the registry, use RegistrySearch. Otherwise, you can use MsiGetComponentPath in a custom action.
I've done some research into this and here's the solution that I came up with:
When the installer finishes installing, it creates a node in the registry under the path
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\<Product ID>
for 32 bit installs on 32 bit OS or 64 bit installs on 64 bit OS, or
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\<Product ID>
for 32 bit installs on 64 bit OS.
This node contains a value called InstallLocation which gives you the path to where the executables are installed.
Unfortunately, the previous version of our installer did not set this property, so I can't use it. BUT our installer creates a Service. I have found the path to the node in the registry for that service. From there, I can retrieve the value of the ImagePath value and extract the path from the service's .EXE file name.
So my solution is to:
Fix the new installer so it does set the InstallLocation value.
When upgrading from the previous version only, it will retrieve the registry node for the service & use the service's ImagePath key.
If upgrading from any later version, we'll retrieve the Uninstall node and use the InstallLocation key.
Tony
msiexec keeps a copy of the msi from the last install so it will handle uninstalling the previous version you will need to just include the InstallExecuteSequence section
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate" />
</InstallExecuteSequence>
This will only work if you are using the same UpgradeCode attribute in your Product Element.
Good Luck!

Always update files in minor upgrade (how to)

I am creating an install package using InstallShield Pro X. The upgrade works properly. However, the product manager wants the upgrade to replace all files on an upgrade even if the create date != modify date on the file.
I see that to do this I need to set REINSTALLMODE=vamus rather than vomus. However, I don't see how to tell InstallShield that I want it to use that setting. By default setup.exe always passes vomus to windows installer.
There is a property in the InstallShield project named ReinstallModeText that I changed from omus to amus but that seemed to have no effect.
So, how what do I set in the install project so that when setup.exe detects to run an upgrade it sends REINSTALLMODE=vamus? Thanks.
Update: Tried adding the following to the MSI Command Line value in the Release section:
REINSTALLMODE=vamus
This did not work. Setup.exe didn't set REINSTALL=ALL on the command line what I did this. I added that to the MSI Command line and the upgrade worked as expected. But, not the problem is if it is a NEW install those properties are still being set and the installer fails.
In investigating this further and testing more options I think the best answer is to modify the product code in addition to the product version and author it as a major upgrade which removes the previous version first and then installs the new files.
The main problem with this is that it takes alot longer for the installer to run. I also think that you can not issue this as a patch, but I could be wrong on that count.
Don't set the REINSTALLMODE to amus or vamus (force overwrite files). These settings apply to all components in the MSI, and could hence in theory downgrade system files or at least shared files - this typically involves files included via merge modules. It is normally safe to set REINSTALLMODE to emus (replace files with lower or equal version number). Even this can trigger a file replacement error if you try to overwrite a system protected file on newer versions of Windows featuring Windows Resource Protection (wikipedia) (Windows Server 2008 and Vista onwards). On older Windows versions the file would likely be overwritten and then restored in its right version from the dllcache via the Windows File Protection feature provided that feature had a good day. There was (and is) an associated tool for system file checking: System File Checker.
If you have issues with files that should be replaced even if they have been edited, you can use the RemoveFile table to schedule the file for removal during install (and then it will be reinstalled).
The real solution is to consider the installation folder in %ProgramFiles% as read only, and not have the application save ANY settings or change any files. All config files should go to the user profile or the alluser profile and the application EXE file should be responsible for the copy to the profile locations.
See my answer here.
I don't have IS X handy, but in later versions of InstallShield you would go to "Releases", highlight your release, go to the "Setup.exe" section and there's a field called "MSI Command Line Arguments". There you would indicate any command-line arguments that you want Setup.exe to pass to Windows Installer. E.g. REINSTALLMODE=vamus
You mentioned you used ReinstallModeText with "amus". Have you tried ReinstallModeText equal to "vamus". The "v" causes the installer to run off the source package, not the cached package, and that may be your problem.