How to include inherited permissions when specifying permissions for a file installed by Wix / Windows Installer? - wix

The Wix source code that I feed to the Wix compiler to build an MSI package for my application, contains the following PermissionEx directive, part of a file component which Windows Installer should install with additional (to those that should be inherited by default) permissions:
<PermissionEx Sddl="D:AR(A;;FW;;;BU)" />
As you can surmise, I intend to install the file with inherited permissions ("AR") included in its ACL and on top of that allow members of the Built-in Users group ("BU") to be allowed ("A") to write to the file ("FW").
The code above does not have the desired effect -- the file is installed, but only that single explicit ACE is listed, none of the ACEs that are supposed to be inherited from parent folder.
In contrast, if I subsequently remove all permissions from the file and run cacls file /S:D:AR(A;;FW;;;BU), i.e. specify exactly the same SDDL string, it does work as intended -- the permissions from parent are inherited and form part of the ACL, together with the explicit non-inherited ACE.
I am using Wix 3.11.1.2318 and the Windows Installer version is 5.0.16299.611, all running on Windows 10 Enterprise 64-bit. Orca tells me the MsiLockPermissionsEx table embedded in my built MSI file is populated with the intended SDDL record. So why is the file created without inheriting permissions from its containing folder?
I tried to use "AI" in place of "AR", and both strings together, but none of it had any effect either.
Is this some known limitation or a quirk with Windows Installer? I know that people were talking a while back how the old LockPermissions table (the one specified for Windows Installer versions earlier than 5) was inadequate in this specific regard -- inherited permissions, namely -- but they also said Microsoft was out to address this very issue with the new table feature.
Otherwise what am I doing wrong?

Given your knowledge in this field, you probably have already tried this. It would also be much better to eliminate the need for permissioning, but two snippets for you - notice the Append attribute:
Create a WiX project in Visual Studio. Add the Util namespace to the WiX element:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
In Visual Studio project, right click References and add reference to "%ProgramFiles(x86)%\WiX Toolset v3.11\bin\WixUtilExtension.dll".
Permission Folder:
<Component Feature="ProductFeature" Id="Test.exe" Guid="PUT-GUID-HERE">
<File Source="C:\Test.exe" />
<CreateFolder>
<util:PermissionEx User="Power Users" GenericWrite="yes" />
</CreateFolder>
</Component>
Permission File:
<Component>
<File Source="C:\Test2.exe">
<util:PermissionEx Append="yes" User="Users" GenericWrite="yes" />
</File>
</Component>

Take a look at WiX's custom PermissionEx in the Util extension.
http://wixtoolset.org/documentation/manual/v3/xsd/util/permissionex.html

Related

Make Wix to not uninstall common dll

I have Wix project in which I need a common used dll library to be installed if it's absent.
If this dll exists I should not overwrite it.
So, when I set DefaultVersion="0.0.0.0" this dll is not overwritten if it exists, its ok. But when I delete app, the dll is beeing removed. How do I prevent removing dll in the case when it existed before installation?
I don't want to make it permanent because it should be removed if it didn't exist before installation.
<Component Id="myLib.dll" Permanent="no" Directory="Shared_Dir">
<File Name="myLib.dll" KeyPath="yes"
Source="mySource\myLib.dll"
DefaultVersion="0.0.0.0"
/>
Add reference to WixUtilExtension and xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" attribute to Wix element in your code.
Define <Property Id="Dll_Installed" Value="false"/> in Product element.
Add child <Condition>NOT Dll_Installed</Condition> to component myLib.dll.
Add that somewhere in your code:
<Fragment>
<util:FileSearch
Id="Dll_Installed"
Variable="Dll_Installed"
Path="[Shared_Dir]myLib.dll"
Result="exists"/>
</Fragment>
DefaultVersion attribute is not necessary.
The feature you are describing is reference counting. The Windows Installer reference counts with Components. Components are identified by their GUID.
So the normal way to address this requirement is to put the File in a Component and make sure the GUID of the Component is stable. The WiX Toolset should do exactly that automatically if if you do not specify the Component/#Guid attribute.
So the default behavior should just work for you.
The only other piece of the puzzle is the Windows Installer will install the latest version of a file. If the file version is the same or less the file will not be installed but will be reference counted.
Based on the details in the question it seems like you should be just fine with:
<Component Directory="Shared_Dir">
<File Source="mySource\myLib.dll" />
</Component>
One might ask why the Windows Installer use Components to reference count files. We'll, it allows you to group other resources, like registry keys, together and control their install as a unit. Much more important if you are installing COM servers than plain old files.

How do I stop removal of files during uninstallation using Wix

When uninstalling my application, I'd like to configure the Wix setup to NOT to remove few files that were added as part of the installation. It seems like the uninstaller removes all the files that were originally installed from the MSI file. How do I do that?
Here are my files which I wish to keep it forever
<Binary Id="RootCABinary" SourceFile="Assets\Certificates\RootCA.cer" />
<Binary Id="SubCABinary" SourceFile="Assets\Certificates\SubCA.cer" />
I have used WixIIsExtension.dll to install these certificates to the windows store.
Overwrite: Is it important that the file never gets overwritten? If so, add
"Never Overwrite" to your component. WiX attribute: NeverOverwrite="yes". Remember to test upgrade scenarios!
Permanent Component: As stated by Pavel, you can set a component permanent:
<Component Permanent="yes">
<File Source="License.rtf" />
</Component>
Blank GUID: Another way to do it is to set a blank component GUID. It essentially means "install and then leave alone". No repair or uninstall should be done (remember to add NeverOverwrite="yes" if the file should never be overwritten):
<Component Guid="" Feature="MainApplication">
<File Source="SubCA.cer" KeyPath="yes" />
</Component>
Read-Only Copy: I sometimes install files to a per-machine path (for example somewhere under program files) and then copy them to a per-user location (somewhere in the user-profile) on application launch, and then do operations on them that entail that the files should not be deleted. This is good in cases where you want to do something that change the files in question (they need to be writable). Then it is good to "untangle" them from deployment concerns (files will not be meddled with by installer operations at all - the installer has no knowledge of them). The original read-only copy installed to program files can be uninstalled though (no longer needed?).
Other approaches: You can also create such files using custom actions during installation (usually text files only), you can download the file in question from your web site on application launch (makes the file easy to manage and update / replace? Vulnerable to connection problems - firewalls, etc...) and the application can create the file using "internal defaults" in the main executable on launch. And there are no doubt further approaches that I can't recall.
Put your binaries in a separate WiX component and make it permanent. Have a look at this thread as well

Wix component GUID "*" is not valid for this component

I'm trying to solve my issue with autogerating GUID for multiple components in same folder installed under AppData (per-user installation).
Before edit I had one component with 3 files. Then I've decided to use auto GUID for this component, so I have divided it into 3 component (each with one file). I thought that now I can use Component GUID with * and registry value with KeyPath=yes but it's not working. Any advice is very appreciated.
Here is code snippet:
<Directory Id='INSTALLDIR' Name='$(var.myInstallDir)'>
<Component Id='MainExecutable' Guid='I_WOULD_LIKE_ASTERISK_HERE_ALSO_BUT_HAVE_HARD_CODED_GUID' >
<RemoveFolder Id='RemoveINSTALLDIR' Directory='INSTALLDIR' On='uninstall' />
<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Name='Path' Value='[INSTALLDIR]' KeyPath='yes'/>
<File Id='ffile1' Name='file1' DiskId='1' Source='file1'> </File>
<Shortcut Id="startmenujfile" Directory="ProgramMenuDir" Name='$(var.myAppName)'
Target="[SystemFolder]cmd.exe" Arguments=" /c START javaw.exe -jar [INSTALLDIR]file1.jar ."
WorkingDirectory="INSTALLDIR"
Icon="apsoiconmultiico" IconIndex="0" />
<Shortcut Id="desktopjfile" Directory="DesktopFolder" Name='$(var.myAppName)'
Target="[INSTALLDIR]file1.jar" Arguments=" ."
WorkingDirectory="INSTALLDIR"
Icon="iconmultiico" IconIndex="0" />
</Component>
<Component Id='MainExecutable2' >
<File Id='ffile2' Name='file2' DiskId='1' Source='file2' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes'/>
</Component>
<Component Id='MainExecutable3' >
<File Id='ffile3' Name='file3' DiskId='1' Source='file3' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes'/>
</Component>
</Directory>
And error for components:
error CNDL0230 : The Component/#Guid attribute's value '*' is not valid for this component because it does not meet the criteria for having an automatically generated guid. Components with registry keypaths and files cannot use an automatically generated guid. Create multiple components, each with one file and/or one registry value keypath, to use automatically generated guids.
Thank you
EDIT:
Thanks to #Stein Åsmul answer. I need to ask one more time..
I'm trying to solve this because we are moving from Java Web Start (jnlp) to very simple .msi file which installs only elementary files and shortcuts. Then the app itself has automatical update system which downloads all other files.
Our app can have "mupliple sets of versions" installed on same machine (like set A: "app 1 demo, app 2 test" and set B: "app 2 demo, app 2 test"). Every set and every version in the set can have different files (this is a job for update system itself).
Now the question. I'm a newbie in .msi installation so I'm not sure about many steps. I know productId, upgradecode.. but what about component GUID (in my case Component Id='MainExecutable') in enviroment with multiple sets of app installed on same machine (per-user but different directory - AppData/local/setA and AppData/local/setB) with registry KeyPath=yes? Can this component has fixed GUID for all our installations if productId is different (so hardcoded in .wxs for all installations)? Thank you for explanation.
Short Answer: You cannot use auto-guids for components that have the same / non-unique key path - which is the case for per-user registry key paths. Simpler approach: Install files to a per-machine location and copy them into each user-profile on application launch instead of
installing them per-user via an MSI. This de-couples all user-profile files
from common deployment problems (overwriting / resetting, upgrade problems, uninstall problems, etc...). Auto-Guids are possible for per-machine key paths - they are unique per component.
Per-User Key Path: HKCU\Software\Company\Product\MyKeyPath
Repeats for every user! => No auto-guid possible. It is not unique.
User 1: C:\Profiles\User1\Product\File.exe, Key path: HKCU\Software\Product\MyKeyPath
User 2: C:\Profiles\User2\Product\File.exe, Key path: HKCU\Software\Product\MyKeyPath
For the record, here is what would happen if you set a userprofile disk-based key-path (as opposed to a registry key path which you are supposed to use): Color illustration.
Per-Machine Key Path: C:\Program Files\Company\Product\Main.exe
Only one installation instance! Unique key path allows auto-guid.
Read-Only Templates: A general issue first: it is recommended that you don't install files directly into the user profile folders. Rather you should install them to your main installation folder under Program Files and then copy them in place during application launch for every user who uses the application. The files can then be copied to every user-profile on demand and on launch of the application (upgrades are possible too, if you implement it well).
Technically: You cannot use an auto-guid for components that has the same / non-unique key path. The technical reasons can perhaps be best understood by reading this old answer: Change my component GUID in wix? Essentially the key path must be unique in order to be able to create an automatic GUID, and this is not the case with per-user registry keys. The path is the same for all users - to the same registry key (even if the content is different for each user). A limitation of the MSI technology.
Note that if you install to a per-machine path you will be able to use auto-GUIDs since you can have a unique file key path for the component. This should work fine. Just move the files to a per-machine path and set an auto-guid. Upgraded files will overwrite older files and you can copy newer files over the ones in the user profile on launch - if desirable. A risky operation most of the time.
Cloud: I am fond of cloud-based approaches to download files into the user profile on-demand directly from the Internet or Intranet as an alternative to deployment via MSI. It all depends what you have access to.
More Details: There are too many pre-existing answers that revolve around the same points for there to be any value in rewriting it. Please check the below links for more details on the deployment of per-user files with MSI:
Create folder and file on Current user profile, from Admin Profile
Wix deferred custom action access denied
How to create nested folder in AppData
Create a .config folder in the user folder
Make WIX installer place files in AppData

Merge module files into different locations

I'd like to parse merge module files into two different locations. Is it possible?
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="LoggerClient" Guid="*">
<File Id="log4net" Name="log4net.dll" Source="..\..\_Release\log4net.dll" KeyPath='yes' />
<File Id="LoggerLibrary" Name="LoggerLibrary.dll" Source="..\..\_$(var.Configuration)\LoggerLibrary.dll" />
<File Id="app.config" Name="app.config.xml" Source="..\..\_Release\app.config.xml" />
<File Id="msvcr110.dll" Name="msvcr110.dll" Source="c:\windows\sysWoW64\msvcr110.dll" />
</Component>
</Directory>
</Directory>
</Module>
<Merge Id ="MergeModule.msm" Language ="!(loc.Lang)" SourceFile ="_$(var.Configuration)\MergeModule.msm" DiskId ="1" />
I want the second file to copy to a different folder than the other files.
There is a concept for that, it is called a retargetable merge module. I have avoided used it - the concept doesn't seem right to me. I have not tried to make one with Wix.
I think you could combine a Wix include file (simple sample) with the new auto-generated component guids to deploy such duplicated files reliably by adding an Include statement where appropriate. You must not hard code the guids in this case, but let them be auto generated by the Wix compiler and linker.
Also have a read of WixLibs (Wix library files): http://robmensching.com/blog/posts/2008/10/10/what-are-.wixlibs-and-why-would-you-use-them/
Wix documentation; http://wixtoolset.org/documentation/manual/v3/overview/files.html
Merge modules are for installing common runtimes and genuinly shared files. Typically C and C++ runtimes and other, similar libraries that should be available in the latest version for all applications.
Your files look like they are part of your application folder, with the exception of msvcr110.dll which you should remove and allow to be loaded from the system folder.
If the remaining files have no per-machine registration (COM for example or COM Interop), you can duplicate them in several folders without interference, yes, but why not load them from a shared location inside your own application folder structure?
%ProgramFiles%\My Company\My Shared Runtimes
%ProgramFiles%\My Company\My Apps\My App 1\
%ProgramFiles%\My Company\My Apps\My App 2\
These sample folders you "own" and you can deploy things here however you like. Not so for shared, system folders. You could make your own merge module for shared components between your applications into "My Shared Runtimes" and make your applications aware of the shared location "....\MySharedRuntimes\"
It depends on what you mean by different locations. You can build a merge module with 4 files, each in their own component and directory. One could go to the CommonFilesFolder; another to the SystemFolder; another to...you get the idea. So it's potentially easy if you make each file its own component in its own directory. However you've got them all under TARGETDIR, so you're going the wrong direction. You just define the other directory and that other component and file and you might be done, unless there's more to the question than meets the eye.
I would suggest contacting me privately for a few 30-60 minute conversation on MSI, component rules, Merge Modules and file set theory. It's too much to write. In a nutshell I would advise more merge modules.

vsdrfCOMSelfReg equivalent for WixSharp

I am trying to recreate the functionality of a legacy installer using WixSharp. In the legacy Setup Project, some of the third party DLL's were marked "vsdrfCOMSelfReg". I have seen in various places that you can add to the File tag SelfRegCost="0" but it is highly frowned upon.
How can I properly register a COM DLL using WixSharp? Is there a way to just add SelfRegCost field to the File tag for the DLL from WixSharp?
It's true that you can say something like SelfRegCost=1 in the File element, but every install guy will tell you it's evil, as you discovered. The non-evil way is to use heat.exe on the Dll to extract the registration data into a wxs file. If necessary add interface entries for type library data by running heat.exe on a tlb file. Heat is just a WiX tool, I don't see how WiXSharp is involved.
The point is that registration data is static and can be stored in the MSI via WiX and simply written to the system at install time without requiring the Dll to be loaded and called.
After some further source browsing and experimentation, I figured out how to force the evil approach through WixSharp. I also later discovered that this was somewhat covered by the WixSharp Sample "CustomAttributes".
"Evil Way"
File LibToReg = new File("..\Path\To\LibToReg.dll");
LibToReg.AttributesDefinition += "SelfRegCost=1";
Alternatively (based on the CustomAttributes sample):
File LibToReg = new File("..\Path\To\LibToReg.dll")
{
Attributes = new Attributes() { { "SelfRegCost", "1" } }
};
This will generate the following wxs underneath:
<Component Id="Component.LibToReg.dll" Guid="EABD7A49-26DD-4720-AE5A-AA9EEFD8C91A">
<File Id="File.LibToReg.dll" Source="..\Path\To\LibToReg.dll" SelfRegCost="1" />
</Component>
The rest of the generated code looks the same as any other DLL that is installed.
For reference, here is the original wxs source that was generated from the original Setup Project using "VDProj to WiX Converter" from Add-In Express. I believe the SelfRegCost="0" was added by the converter, but a co-worker may have manually added it in afterwards.
<Component Id='com_FB7105EC_5352_4561_AE01_405562F0EA1E' Guid='6718170E-0335-4FD6-A1E8-D9E926DDE3EC' Permanent='no' SharedDllRefCount='no' Transitive='no'>
<File Id='_FB7105EC_5352_4561_AE01_405562F0EA1E' DiskId='1' Hidden='no' ReadOnly='no' SelfRegCost='0' System='no' Vital='yes' Compressed='yes' Name='LibToReg.dll' Source='..\Path\To\LibToReg.dll' KeyPath='yes' />
</Component>