Not able to update XML value in Change mode (without admin rights) - wix

I have written following code in my wix installer for updating the language in an XML file and this works fine in following conditions:
1) fresh install
2) upgrade by using admin rights (I am using msiexec /I "Tools.msi" /l*v D:\InstallLog.txt).
However, when I run/execute the msi without admin rights (This is where "Change" mode is being used....what am I missing) the values are not updating always set to the default value :
<Property Id="LANGUAGE" Value="en-US" />
The code:
<util:XmlFile Id="LanguageConfig"
Value="[LANGUAGE]"
ElementPath="/configuration/appSettings/add[\[]#key='Language'[\]]"
Action="setValue"
File="$(var.ConfigFile)"
Name="value" Sequence="1" />
<util:XmlFile Id="MappingLanguageXML"
Value="[LANGUAGE]"
ElementPath="/MappedUsers/UsersList/UserID/LanguageCode"
Action="setValue"
File="$(var.UserMappingFile)" Sequence="1" />
Any help is much appreciated.

The fact that it's being changed implies it may not be a privilege issue. I suspect that the scenario is that a different language was entered at install time, but you did not preserve its value anywhere so Change just uses the default value. Properties aren't remembered automatically, that's what the WiX "remember property" pattern is for. That's likely to be the solution - preserve the install time value of LANGUAGE. It's no different from running any program - the fact that the user may have entered something that went into a variable doesn't mean that the variable will have that same value next time you run the program unless you save it.

Based on PhilDw pointer I solved the issue by modifying my property
<Property Id="LANGUAGE" Value="en-US" />
as follows:
<Property Id="LANGUAGE" Secure="yes" Value="en-US">
<RegistrySearch Id="RememberLanguage" Root="HKLM"
Key="$(var.RegistryLoc)"
Name="Language" Type="raw" />
</Property>
By preserving the value in the registry I was able to modify the value during "Change" operation.

Related

WiX Toolset: ICE03 Invalid identifier with RemoveFolderEx

I'm trying to create a .msi installer for a Node.js project using the WiX Toolset. I want to remove the node_modules folder during uninstall. This is the relevant excerpt from my .wxs file:
<Property Id='APPLICATIONFOLDER'>
<RegistrySearch Id='ApplicationFolder' Root='HKLM' Key='Software\[ProductName]' Name='InstallDir' Type='raw'/>
</Property>
<DirectoryRef Id='TARGETDIR'>
<Component Id='RemoveFolder' Guid='3e2231d9-61b3-41a2-b407-8df015be537e'>
<util:RemoveFolderEx Property='[APPLICATIONFOLDER]\node_modules' On='uninstall'/>
<RegistryValue Root='HKLM' Key='Software\[ProductName]' Name='InstallDir' Type='string' Value='INSTALLDIR' KeyPath='yes'/>
</Component>
</DirectoryRef>
I thought this would read the value from the registry, assign it to the property APPLICATIONFOLDER, and then in the RemoveFolderEx tag append the string \node_modules to that property's value.
But when I try to run this through light.exe, I get ICE03: Invalid identifier; Table: WixRemoveFolderEx, Column: Property, Key(s): wrf1A1445CB13E8BF98989EA24E3514470A.
Clearly, it is unhappy with my Property attribute, but what do I need to fix it? I've seen plenty of guides using this general pattern, but they always read the install dir value from the registry and then nuke that entire folder. That seems a little crass - if the user has added files to the directory I don't want to delete them. How can I specify a subfolder to delete?
I've solved the problem. Because I personally had a hard time figuring it out - the guides I've seen on RemoveFolderEx only all cover the same use case of nuking a folder saved to the registry, not a subfolder; and I find the WiX documentation to be less than beginner-friendly in most cases -, I am recording the solution here in case someone else should ever stumble upon the same problem.
As was pointed out already, Property does not work in the way I presumed in my question - it really does just accept the id of a property holding the path to the directory to delete. So you will definitely need to set a property in some way. (Some guides on the internet do not make this very clear.)
The next obvious path to investigate would be to assign the property a modified result of the registry search. However, this is impossible with WiX (to the best of my knowledge).
The answer lies in SetProperty. This, finally, allows to set a new property based on the one read from the registry.
It is worth noting that doing this still prevents the installation folder from being deleted, even if it empty. This, however, can easily be remedied by adding a RemoveFolder (without the Ex). This will delete the folder, but only if it is empty.
The relevant code that got it working for me is below.
<!-- Read the InstallDir from the registry and assign it to property APPLICATIONFOLDER -->
<Property Id='APPLICATIONFOLDER'>
<RegistrySearch
Id='ApplicationFolder'
Root='HKLM'
Key='Software\[ProductName]'
Name='InstallDir'
Type='directory'
Win64='yes'/>
</Property>
<!-- Set new property NODE_MODULES_FOLDER by appending node_modules\ to APPLICATIONFOLDER -->
<SetProperty
Id='NODE_MODULES_FOLDER'
Value='[APPLICATIONFOLDER]node_modules\'
Before='CostInitialize'/>
<Component Id='RemoveFolders' Guid='...'>
<!-- Remove the node_modules subfolder, using the property we created above -->
<util:RemoveFolderEx Property='NODE_MODULES_FOLDER' On='uninstall'/>
<!-- Remove main installation directory now, but only if it is empty. -->
<!-- That's why we're using RemoveFolder instead of RemoveFolderEx here. -->
<RemoveFolder Id='RemoveMainFolder' Property='APPLICATIONFOLDER' On='uninstall'/>
<RegistryValue
Root='HKLM'
Key='Software\[ProductName]'
Name='InstallDir'
Type='string'
Value='[INSTALLDIR]'
KeyPath='yes'/>
</Component>
I thought this would read the value from the registry, assign it to the property APPLICATIONFOLDER, and then in the RemoveFolderEx tag append the string \node_modules to that property's value.
It won't. As the doc says, Property is:
The id of a property that resolves to the full path of the source directory.
The easiest way to make that happen is to write the exact path you want to nuke to the registry.

Wix SetProperty if Property does not have a value

I have the following code in my WiX installer:
<Property Id="CONFIGPATH" />
<SetProperty Id="CONFIGPATH" After="AppSearch" Value="[INSTALLFOLDER]servers.cfg">NOT CONFIGPATH</SetProperty>
The intention is that the user may pass a custom CONFIGPATH to the installer. If they do not pass a custom path, a default path targetting the installation folder is used. However, this code does not work. SetProperty never fires.
If instead I write:
<Property Id="CONFIGPATH" />
<SetProperty Id="CONFIGPATH" After="AppSearch" Value="[INSTALLFOLDER]servers.cfg"></SetProperty>
The property is updated to (the calculated value of) [INSTALLFOLDER]servers.cfg correctly.
Why might this be?
For some reason, AppSearch is too early in the install sequence. It was necessary to change the code to a later point in the sequence:
<Property Id="CONFIGPATH" />
<SetProperty Id="CONFIGPATH" Sequence="execute"
Before="InstallFiles"
Value="[INSTALLFOLDER]servers.cfg">NOT CONFIGPATH</SetProperty>

Disable password in WIx Installer

I have a installer project which is developed in Wix.
I have the below code with util:xmlconfig
<util:XmlConfig
Id="xml.SetMYPassword"
Action="create"
ElementPath="/configuration/DataReport/Password"
Node="value"
Value="[MY_PASSWORD]"
File="[#MyService]"
On="install"
PreserveModifiedDate="yes"
Sequence="1" />
Now the issue is, when I am installing the package the password is shown like "myPassword" instead of ******. How can we change the above code such that the password should not be displayed.
If you are trying to stop the MY_PASSWORD property from appearing in the log you should set the hidden attribute to yes in its declaration.
<Property Id="MY_PASSWORD" Hidden="yes" Secure="yes" />
Note that the util:XmlConfig custom action may still display this in its own internal logging.

Wix Toolset - Setting a Property to User Profile Folder path and Program Files

I am using Properties to set the values of Registry entries. This is so that on install the first time I have a default value and then on upgrade the current registry value is used.
I need to have a property that sets the path to the user's local folder and to the programs folder. I know the below code is wrong but how do I do it. I think at least I want to do a Type 51 custom action but don't understand the documentation.
I believe there are three relevant parts
<InstallExecuteSequence>
<Custom Action="SetUserFolder" Before="InstallInitialize"/>
<Custom Action="SetInstallFolder" Before="InstallInitialize"/>
</InstallExecuteSequence>
Custom Action
<CustomAction Id="SetUserFolder" Property="UserFolder" Value="[%USERPROFILE]" />
<CustomAction Id="SetInstallFolder" Property="P_InstallFolder" Value="[%PROGRAMFILES]" />
The property.
<Property Id="P_MyAPPPATH" Value="[P_InstallFolder]MyApp\">
<RegistrySearch Id="S_MyAppPath" Type="raw" Root="HKCU" Key="Software\MyApp\Settings" Name="MyAppPath"/>
</Property>
<Property Id="P_MyAPPDB" Value="[UserFolder]\MyApp\MyAppData\">
<RegistrySearch Id="S_MyAPPDB" Type="raw" Root="HKCU" Key="Software\MyApp\Settings" Name="MyAppdb"/>
</Property>
As an alternative to using the properties you're defining, you might be able to use some built-in properties to better effect.
Instead of %USERPROFILE, consider LocalAppDataFolder. This will avoid your data from being copied between machines as a user roams between machines on a network domain. I'm guessing you don't need that but, if you do, use AppDataFolder and beware of the latencies involved.
Instead of %PROGRAMFILES, consider ProgramFilesFolder. This seems to be what you intend.

Running a Custom Action on conditions issue

Can anyone tell me why this is not working please?
I have two registry checks to check if Visual C++ Redistributables are installed:
<Property Id="REGDBKEYEXISTX64">
<RegistrySearch Id="REGDBKEYEXISTX64" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\{837b34e3-7c30-493c-8f6a-2b0f04e2912c}" Name="Version" Type="raw" Win64="yes" />
</Property>
<!--Checking if Microsoft Visual C++ Redistributables are installed on a 32-bit system-->
<Property Id="REGDBKEYEXIST">
<RegistrySearch Id="REGDBKEYEXIST" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\{837b34e3-7c30-493c-8f6a-2b0f04e2912c}" Name="Version" Type="raw" Win64="no" />
</Property>
I then run a custom action if they are not installed:
<Custom Action="InstallRedistributables" After="GetVariantName">Installed OR REGDBKEYEXISTX64 OR REGDBKEYEXIST</Custom>
However when the redistributables are installed it still runs the custom action which is what i do not want. I know it detects it as this is my log file:
Property: REGDBKEYEXIST, Signature: REGDBKEYEXIST
MSI (c) (4C:44) [12:19:04:989]: PROPERTY CHANGE: Adding REGDBKEYEXIST property. Its value is '#134276921'.
So what could be the problem? I have this done on another custom action and it works perfectly so i really don't know the solution.
It appears your condition is reversed. The REGDBKEYEXIST properties will be set if the registry key exists, and thus true when the search indicates the redistributable is present. So what you probably want is more like NOT REGDBKEYEXIST You also probably only want to run this on first time install (hence your reference to Installed). So I would suggest changing your condition to something more like the following:
NOT(Installed or REGDBKEYEXIST or REGDBKEYEXISTX64)