How to ensure a feature is installed during a Windows Installer AdminInstall - wix

I am using WiX to create a moderately complex installer. I have a Level 0 Feature that I would like to install conditionally, but also always during an Admin install, to make patching through admin images easier. I've tried several things:
Setting a property before the AdminUISequence's CostFinalize action (which is when msdn claims the Condition table is evaluated). The condition in that case looks like:
<Condition Level="1">( VersionNT >= 601 AND NOT FASTINSTALL = "1" ) OR INSTALLCONDFEATURE = "1"</Condition>
where FASTINSTALL and INSTALLCONDFEATURE are both Secure and Admin.
Using the Windows Installer ACTION or EXECUTEACTION properties. In this case the condition is something like:
<Condition Level="1">( VersionNT >= 601 AND NOT FASTINSTALL = "1" ) OR ACTION = "ADMIN"</Condition>
Neither of these seem to work. Am I just missing something here, or is there a different, better way to do this?

A feature with Feature/#Level="0" will never be installed in an admin install, per the MSI SDK:
During an administrative installation,
the installer creates a source image
for all features in the product except
those feature with 0 in the Level
column of the Feature table.
So you need to reverse your logic; set the feature level to something greater than zero and use Conditions to set it to zero for non-admin installs.

Related

WIX MSI conditions

In the Zabbix Agent MSI, there is the following line, when one opens MSI:
<Condition Message="Please enter the name or IP address in the Zabbix server IP/DNS field !">NOT (NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)) OR ((NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)) AND ((UILevel<5 AND SERVER) OR UILevel=5))</Condition>
Can someone explain the logic? When one rewrites the condition in a more sensible way:
NOT (
NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)
) OR (
(NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED))
AND ((UILevel<5 AND SERVER) OR UILevel=5)
)
So if Installed=1 then the condition is satisfied due to the double NOT (which it should not be, since the message should only appear if the software is not installed and thus, there is an error in the MSI). The double NOT makes no sense.
Or is there some other interpretation of the condition above?
This is all governed by Windows Installer's Conditional Statement Syntax
https://learn.microsoft.com/en-us/windows/win32/msi/conditional-statement-syntax
It appears your trying to do custom UI work but I don't know how all of that relates to a server name IP address.
In these scenarios I have a custom action that implements business rule checks (reach out and touch a server or validate FQDN/IP ) and set a property to 1 or 0. Then I use mutually exclusive control events (Publish elements with Condition in the inner text ) to either Spawn a dialog that says there is a problem or NewDialog the next dialog of the wizard loop.

wix unable to use string in detect condition

I am using WIX installer to genrate exe, till now everything is working fine but now i need to add one detect condition in exe package as given below.
<ExePackage
Id="AccessRuntime2013"
DetectCondition="((MsAccessInstalled = Outlook.Application.15) AND (MSOffice2013RuntimeInstalled = 0))" >
MsAccessInstalled is a variable which stores version of outlook installed and MSOffice2013RuntimeInstalled is a variable which checks whether access runtime is installed or not. Both variables are setting properly.
I have to run this exe only when MsAccessInstalled = "Outlook.Application.15" and MSOffice2013RuntimeInstalled is not installed. If i run both condition separate then it works but if i clubbed both it doesn't works. It gives error message as Failed to parse condition "((MsAccessInstalled = Outlook.Application.15) AND (MSOffice2013RuntimeInstalled = 0))". Unexpected character at position. Please help.
What happens when you change the DetectCondition to
<ExePackage
Id="AccessRuntime2013"
DetectCondition="MsAccessInstalled ~= "Outlook.Application.15" AND MSOffice2013RuntimeInstalled = 0"
... />
You can also test your conditions by making some test util:Condition tags in your bootstrapper.
<util:Condition Message="MSAccessInstalled condition failed">MsAccessInstalled ~= "Outlook.Application.15"</Condition>
<util:Condition Message="MSOffice2013RuntimeInstalled condition failed">MSOffice2013RuntimeInstalled = 0</Condition>
Run your bootstrapper and see if either condition fails. Do remember to remove these conditions once you're done testing as they will cause issues if put into production.

WIX condition only on Install not working

I have the following within the Product Tag:
<Property Id="LICENSEKEY" Admin="yes" Hidden="no">
<RegistrySearch Id="RememberLicenseKey" Root="HKLM" Key="SOFTWARE\MyApp\key1\Settings" Name="LICENSEKEY" Type="raw"></RegistrySearch>
</Property>
<Condition Message="License key is required to proceed">LICENSEKEY AND NOT Installed</Condition>
What I want to do is pass the License key as a command line argument to msiexec, and then set it in the registry. If the key is not passed I want to cancel the installation. Therefore, this check only needs to be run at install time. However, the condition that I have added causes a popup both at install and uninstall time. Can't seem to figure out what I am doing wrong.
EDIT:
I tested with the following condition and it seems to show the message both on install and uninstall:
<Condition Message="License key is required to proceed">NOT Installed</Condition>
The Message for a Condition element will be displayed when the condition evaluates to false, meaning the condition was not met.
This is noted in the Message attribute description in the WiX Condition documentation:
Set the value to the text to display when the condition fails and the installation must be terminated.
To resolve this issue, the logical operators in the Condition just need to be changed to LICENSEKEY OR Installed
This is a late answer, but, hopefully, this will help any future visitors that find this question.
You may need to clarify your requirement. That WiX source does a search for the key, so does it need to be passed on command line or you'll cancel the install (as your post says), or can it be used if it's found in the registry by that registry search? Currently it appears that your registry search is overwriting anything you pass on the command line, including setting it to null, so check that with a verbose log.
Also, all the launch condition examples I've seen or used have a CDATA around the text of the actual condition - that may be part of the problem.
I'll assume you allow the key on the command line or in the registry. So your registry search should be for another property name, let's call it REGKEY, so it doesn't set your passed LICENSEKEY to null. Then you have a set property (type 51) custom action immediately after the search that sets LICENSEKEY to REGKEY with a condition of -Not LICENSEKEY- so it will set LICENSEKEY to REGKEY only if LICENSEKEY was not passed on the command line. So if you pass it on the command line it will be used, otherwise the registry one will be used. At that point, a condition of LICENSEKEY should work ok as a launch condition. Internally, the AppSearch that finds the registry item is typically immediately followed by the launch condition check in a WiX MSI, so you need to set LICENSEKEY before the launch condition check.

How to change ProductCode using Microsoft.Deployment.WindowsInstaller?

In a deployment scenario we had the idea to allow an administrator to change properties in a installer and the ProductCode. The administrator should then push out the newer msi using a GPO policy. Since this now would be a MajorUpgrade the old version, with the old properties, should be uninstalled and the new one, with the new properties, should be installed.
However updating the ProductCode doesn't work.
When executing
db.Execute("UPDATE Property SET Value = '{30571D61-8994-449B-9725-90760DFE0467}' WHERE Property = 'ProductCode'")
an exception is thrown.
[Microsoft.Deployment.WindowsInstaller.InstallerException] = {"Function failed during execution. Database: C:\..\MyInstaller.msi Table(s) Update failed."}
What should I do to upgrade the ProductCode?
(Is it even possible?)
Edit:
If the table is opened as ReadOnly, it will show error.
Which was the case here.
The SDK documentation states that ExecuteScalar can only be used for a SELECT statement that returns a single result. Instead you should use the Execute method.
using (Database database = new Database(#"C:\MSM\ISWIX.MSI", DatabaseOpenMode.Direct))
{
database.Execute("UPDATE Property SET Value = '{00000000-0000-0000-0000-000000000000}' WHERE Property = 'ProductCode'");
}
Also realize this cannot be done as a custom action during the installation as ProductCode is immutable. Typically in a MajorUpgrade scenario you assign a new ProductCode at build/compile time.

WiX Custom Action - MSI copy itself

Can someone help me to build a custom action in MSI which will copy itself after successful installation to some X location.
I have already seen it can be done using .exe but I want to do it only with CA.DLL (C#) as this exe will be an overhead.
Here's an example VB script that will find an installed product by name and copy the cached copy of the MSI. This will work on Windows 7 and later, as the full MSI is cached and any embedded cab files remain in the MSI. You just get the MSI without the payload on older systems.
Dim installer, products, product, productCode
Set installer = Wscript.CreateObject("WindowsInstaller.Installer")
For Each productCode In installer.Products
If InStr(1, LCase(installer.ProductInfo(productCode, "ProductName")), LCase("My Product Name")) Then Exit For
Next
If IsEmpty(productCode) Then Wscript.Quit 2
Set products = installer.ProductsEx(productCode, "", 7)
filesys.copyFile products(0).InstallProperty("LocalPackage"), "c:\path\to\newcopy.msi"