Our client only allows applications to be installed when logged in as Admin. The application that needs to be installed has to be installed for the current user of the machine. The application installs fine, my problem comes in when i need to drop a config file in the appdata/user profile folder of the user. As this is where they want it, currently the config is being dropped on the admin profile on installation. How do i get past this, is there a way for me to check on installation if there are other profiles and maybe write to them, but this feels dirty.
3 Answers
Cross-Reference: A related issue is when you have a settings file that regular users can't write to. This is a list of approaches for eliminating that condition: System.UnauthorizedAccessException while running .exe under program files.
I will just summarize what others have basically mentioned, fleshing things out a bit trying to make a "little reference".
Maybe have a look at the mentioning of the Win10 ransomware protection feature below for an important tidbit on how this Windows change can affect deployment of user-profile files.
COMMON APPROACHES
There are many ways to get files deployed to each user on a computer, but there are many drawbacks and problems with most of the approaches. In all honesty there are problems with all approaches, in one form or another.
Below is a list of some common deployment approaches first, and then a mention of some "cloud-based approaches". In the future this discussion may become irrelevant as settings are entirely cloud based and synced on the fly and deployment may switch entirely from per-machine to per-user based deployment. We will have to wait and see how it turns out.
1: Per-Machine Template
- Install the config file to a per-machine location that is readable for all users, then copy the file from there and put it into the userprofile on application launch using the application itself to do the copy-work once per user.
- This is the recommended approach. You can even update your application with logic to enforce updates per-user if you need to using an approach like this: http://forum.installsite.net/index.php?showtopic=21552.
- You will always be running in the right user context when the copy is happening, and you don't have to worry about complex MSI impersonation, conditioning and sequencing complexities.
- A nice advantage of this approach is that it will work even if the installation source (MSI) is missing at the time of the application launch.
2: Create File On Launch - "Internal Defaults"
- As gilliduck suggests, simply create the config file on launch using the application's internal defaults and don't install the file at all. Happens once per user, from then on you use the file that is there. Keeping such a file out of your installer means you eliminate the risk that the installer accidentally overwrites it or uninstalls it.
- The obvious question is why you would need such a file at all - if you can create it from internal defaults? The answer is obviously that you may want to enforce some specific values that are unique for the user's environment once the file is created. However, settings like these could just as well be saved in the registry?
- You could set the custom settings in question in the HKLM section of the registry via PUBLIC PROPERTIES during installation (configurable by the user on the command line or via a transform, see: How to make better use of MSI files for information on this), and enforce them for all users on application launch - in other words write them to HKCU. Or you could just keep the settings "read-only" in HKLM and enforce them for all users that way in your application? (non-user configurable settings - such as a network server name or similar).
- You can still use the method from the link above to enforce updates to existing config files on application launch by having your setup write a flag to HKLM to notify that a deployment has "happened" since last launch.
- Or, as stated, alternatively use the registry to hold settings instead.
- How to read embedded resource text file
3: MSI Self-Repair
- Put the config file in place per user using MSI self-repair. This happens on invoking an advertised entry point such as an advertised shortcut used to launch the application.
- Requires access to the installation source at the time the repair happens. Make sure to cache your MSI file on the box.
- Self-repair may not work on Terminal Servers (disabled feature). It has been years since I last tested this. I am not sure how servers are configured out of the box these days.
- Unless configured not to, the uninstall may uninstall the config file for the user who runs the actual uninstall or, critically, this may happen during a major upgrade (which is really an uninstall and reinstall of your product). In other words: set the component permanent (and never overwrite) - or your file may appear overwritten during the upgrade (but it is really uninstalled and reinstalled).
- For HKCU registry settings you don't necessarily need to have the installation source available. Check Stefan Kruger's explanation: http://www.msifaq.com/a/1011.htm. The procedure is the same to trigger installation of userprofile files (but then the installation source is needed). An associated discussion - in case it is helpful.
- Though untested by me, I have considered setting a registry key path value to:
HKCU\Software\MyCompany\MyApplication\Version\HKCU_KeyPath = [ComputerName]
in order to make the key path value a "moving target" so that self-repair is triggered reliably when the user logs into a new computer (despite roaming profiles bringing in existing HKCU settings). - As I said, untested since I have pretty much abandoned this approach - since it is less reliable to depend upon for every new update to Windows. Something strange is changed every time, with unpredictable results.
- Though not 100% related, I can mention the new ransomware protection feature in Windows 10 as an example - it seems to cause intermittent runtime errors for any MSI trying to write to user data folders. It remains to be seen how many deployment problems will result - while we see intermittent results so far - what will happen when and if they turn on the feature by default?.
- And, along the same lines as above, third party security software also provide obstacles to deployment by blocking certain file system activity and quarantining files that are flagged for some reason (including false positives) - causing self-repair that can never complete, but keep running in vain.
- See issue #7 here on self-repair and security software and malware: How do I avoid triggering MSI self-repair with my WiX / MSI package?
- A summary of deployment complexity in general: What is the benefit and real purpose of program installation? and towards the bottom here: Windows Installer and the creation of WiX.
- So as a short summary, here are some reasons why it becomes more and more useful to avoid deployment of userprofile files via self-repair:
- Roaming profile complications.
- Ransomware protection feature interference.
- Security software interference (particularly false malware positives).
- Terminal server restrictions on self-repair.
- Data reset or settings uninstall issues during major upgrade.
- Maybe you get the same feeling I get: there is more, and it will continue to get worse.
- My two cents: talk to your manager immediately about better data file management for your application and abandon all attempts to be "smart" during deployment. Deploy per machine file only with MSI - if possible.
- In the future this preference may likely change as deployment technology changes and installs are done per user only (maybe).
- A longer description of the problem written earlier: Why is it a good idea to limit deployment of files to the user-profile or HKCU when using MSI?
- And a whole messy chat about deployment problems in general: How do I avoid common design flaws in my WiX / MSI deployment solution?
4: Active Setup(no longer recommended, please read)- Put the config file in place using Active Setup. This happens on user login (which then requires a logout and login to happen unless you ensure the file is also installed to the current user profile on install).
- This is in effect a variation of approach 1. You should install the config file to a per-machine location, readable by all user.
- Then you register a task in the registry to run "something runnable" once per user. You can run anything such as a batch file, executable, script, or my preferred approach MSI repair that will manage to put the userprofile file in place (in this case you don't need a file in a per-machine location, but access to the installation source as Active Setup runs).
- Beware not to overwrite a config file put in place during the install for the current user. Or disable Active Setup from running for this user by writing the HKCU key that is written after Active Setup has run for the user in question (see link below).
- The procedure is attempted explained in my answer here: Updating every profile's registry on Windows Server 2003. It is all based on a HKLM key that is run once per user. Check the linked answer for detail, and there are a few external links in there that provide a lot more details.
- UPDATE: When installing on Terminal Server you put the server in "install mode" and then per-user registry entries are written to
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install
and then written to each user's HKCU hive when they log in. This may conflict with ActiveSetup - for all I know. I have never had the chance to test it. Packaging for Terminal Server is typically done by a dedicated, specialist server team.
5: MsiProvideComponent
- Phil's MsiProvideComponent is interesting, I have never used it. I should.
CLOUD-STYLE APPROACHES
With data storage seemingly moving to the cloud the common approaches to data file deployment may quickly become obsolete.
6: Download the Settings File
- Download the settings file - once for each users on application launch - from a local network database / share or from the Internet instead - if this is an option.
- The remote file can be maintained by an admin to update values if there are new default values or something needs to be removed.
- Configuration mechanisms in the settings file understood by your application could enforce new "forced" values to apply for all users.
- Allow configuration of a list of servers in HKLM? Configurable in the MSI via PUBLIC PROPERTIES?
- Or set a single URL in your setup during installation and maintain a list of servers via that URL (you redirect what server this points to via DNS so configuration is a sysadmin task without re-deployment required?). Present selection set in HKCU.
7: Read/Write Settings from Remote Database
- Read / write settings directly to / from a local AD database or the Internet continuously instead.
- No local settings file at all, or a cached read-only copy for when the server can't be reached? Or simply run with internal application defaults if server can't be reached? No file at all to manage in the latter approach.
- You can write a list of servers (URLs) to use to HKLM (even by group policy?), and even maintain the currently selected server in HKCU for each user. Then the rest happens online.
- Generally used in corporate client / server applications so far - but the cloud based platforms will change deployment forever - particularly for home users. We have seen browsers preserve settings via the Internet for a long time (Chrome, Opera, Firefox, etc...).
- Remote, database storage means you can maintain user settings as a database management task and you can even version the user data in the database and easily enforce new defaults or force update existing values for all users users as a centralized DBO task.
- No more pesky roaming profile issue.
- No more failed deployment of userprofile files.
- In summary: no user settings to deploy at all, and the data will never run out of sync on different machines.
- Firewall / proxy and network connectivity issues?
Summary
I don't like option 3 (Self-repair) and option 4 (Active Setup) anymore, although I have used them many times - and they do work when done right. They are, however, not immune to roaming profile issues (files not being copied in place on all systems the user logs onto) and lacking access to the MSI installation source when repair is running - which can cause deployment problems. There are also frequent complications during major upgrades with reset settings, and self-repair fails on terminal servers. Self-repair could fail for installation to the user-profile because of ransomware protection or security software interference. The command line specified in option 4 (Active Setup) could be buggy and wipe out data (for example you enable the wrong flag for the msiexec.exe repair and force overwrite the settings file by accident - this is often not discovered until it is too late and the damage is done). And there are further issues that escape me right now. Both approaches have similar, but slightly different limitations.
I more and more prefer cloud-based approaches to make local (and isolated) user settings files a thing of the past - but I rarely have been able to deploy things this way. These cloud approaches may face problems with firewall / proxy issues and network connectivity problems though - and probably several other things I am not aware of yet (now developers will quarrel with DBOs rather than deployment specialists, etc... ;-)). Distributed computing has its fallacies: https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing. Also: in cloud-based approaches it still may be a good idea for applications to allow settings to be backed up to disk, so some file management is obviously still needed - or do you just export a couple of database tables? Also: if you install a trial version of your application, you may want it to be able to function without network connectivity at all - in case the user is behind a very tight firewall. It is a very expensive mistake to make to not allow your user to test your application's features because of a technicality.
The great benefit of options 1 and 2 is that they will work even if the original installation media is missing when the repair is triggered. This is particularly important for home and small-office deployment where deployment may happen rather haphazardly without a centralized package share. You can work around this problem (missing source MSI) by using caching methods to cache the whole MSI on the system during the installation (available in Installshield, I haven't checked WiX or Advanced Installer).
You can make this work with the repair feature. The big picture is that file was installed for one user at install time at a user profile location, and in a per-system install that will mean that the file will be missing when another user logs on to use the app. It depends on the structure of the MSI components, features and shortcuts, but starting the app with an advertised shortcut may result in the missing file being installed with a self-repair. Obviously this requires the source MSI to remain available.
However the safest way to get the file installed for any new user is to explicitly call MsiProvideComponent passing the ProductCode of the MSI, Feature name, Component id and so on as described in the documentation. As the docs say, this will install the component if it's missing, again requiring the source MSI to be available.
This functionality deals with the case where there are user accounts that haven't been created yet, so obviously you can't yet put files in their profile folders.
Whether it's the best approach compared to others will depend on specific details of the app.