3

Have an msi file that is run by the user manually. They need to be able to choose the install directory in most cases however we need to forbid certain install locations. E.g. Installing it to the root directory C:\ will cause all kinds of problems, so we need to either overwrite that decision (i.e. overwrite C:\ with C:\Program Files (x86)\xxx) or pop up with an error. Is there some way I can enforce this?

The msi in question has custom actions already however there doesn't seem to be a way to edit the install location from there.

Alternatively, the msi in this case is wrapped up in a WiX bundle so if we can forbid certain directories from there that would also be good. Cannot find a way to do this either though (only know how to edit the default with <Variable Name="InstallFolder" ...>)

Only other solution I can think of would be rather horrible: make a separate application that selects a directory that then runs the installer with acceptable directory.

Can this be done either through an msi or a WiX Bundle?

I am using the "Visual Studio 2013 Installer Projects" extension to build the msi.

Patrick
  • 677
  • 5
  • 14

3 Answers3

3

As a contrary view:

In general this is a bad idea. In most cases the correct answer will be to install the application code to the appropriate Program Files folder (64-bit or x86) and the data files to data locations and so on, and the user should get no choice. It is not clear to me that a choice is a good idea when (for example) the Windows Certification rules say that your code must go to the Program Files location, so just do it right. Users simply care that the installed application works correctly, and if it fails when installed to some locations then the answer is to either 1) Fix the application so that it works or 2) use Program Files and give the user no choice.

Also, if you are using Visual Studio Installer projects then you can't write custom actions to do this because they all run too late to change the install location. You seem to have discovered this already. But you CAN hide the browse folder dialog and install to the default correct location.

The other issue is that it's not clear how you would define an "allowed" location. If it's not C:\, then can it be D:\SomeOtherLocation? Can it be an attached USB drive? Can it be a network share such as \\Servername\share? A mapped drive to a network share? There are likely to be any number of chosen locations that will fail the install or the app when it runs, and I don't think there can be a useful list of what's allowed. On top of that, let's say you have a 32-bit install and the user chooses the native Program Files folder on a 64-bit system, then it won't even go there - it will be redirected to the Program Files(x86) location. Finally, it's not clear what you do in silent install mode assuming the user specifies a location on the command line, it fails your test, then the install silently fails (because silent means silent, and the install might be unattended).

In other words, just install to Program Files and have done with it.

PhilDW
  • 20,260
  • 1
  • 18
  • 28
  • Great points. Too many things are possible that make no sense - no offence to the OP - he has work to do. I have never liked redirected installation folders, but when disc space is scarce, people demand it. Could we have mandatory `%ProgramFiles%` installation (exceptions: GAC, WinSxS, System, etc...) and OS features to deal with lacking space instead? Automatic system drive migration to new disk preserving OS installation as an OS feature? Seems more reliable than to allow storage over several physical disks which could fall apart the minute you take out the physical disk or it fails somehow? – Stein Åsmul May 26 '18 at 13:37
  • I agree that users don't need to be asked. Almost all won't need to change it and some will be stuck on the question when they don't even need to decide. If disk space is sparse they can create a junction point to patch in space where they need it. If they really need to override the installation folder they can set it on the command-line since it would be a public property. – Tom Blodget May 27 '18 at 14:50
  • You raise good points unfortunately it's a requirement to be able to choose the location. You're quite right though, it's hard to predict what stupid thing the user might do with the installer. – Patrick May 28 '18 at 00:16
  • 1
    Your application - on launch - could do some defensive sanity checking on what its installation state really is? Just to check if it can find its feet with a runtime environment that doesn't fall over. With some meaningful error messages? Code in the application is much easier to debug and maintain and there are no issues relating to impersonation, sequencing and conditioning - which is what tends to break custom actions (even though setup GUI-custom actions are easier than deferred mode custom actions or silent custom actions in general). – Stein Åsmul May 28 '18 at 01:05
1

Custom Action: This will be short. Will check back later. I can't say I have bothered implementing this recently, but a custom action can certainly inspect the installation location and abort the setup or halt it - if the path selected is found to not be satisfactory. It should also be noted that MSI actively resists installing directly to the root of C:\ and stuff like that due to the way the Directory table is implemented.

GUI: I guess one way would be to run a custom action when the user clicks the Next button in the setup's destination path customization dialog which then does "whatever you want" in terms of checking the path, and then reports any errors. This involves a DoAction event hooked up to the OK or Next button on the path customization dialog.

Silent Mode:You can also hook up the same custom action to run in silent mode (or another custom action calling the same path check function) - to account for the fact that an undesirable path could also be specified for a silent installation. In that case the custom action should abort the setup after writing into the log file, instead of reporting the path problem to the user - which is what you would do from the dialog event mentioned above - obviously.

Github: I do not have WiX code for you to implement this available on this computer. I would hit github.com and search for other projects that use WiX - you will probably find something quickly - no money for nothing and WiX for free.

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • When I run the msi it doesn't stop me from installing in C:\. Possibly I'm using a different way of constructing the msi? I'll add that to the question. – Patrick May 25 '18 at 05:25
  • 1
    I like to document what people should not do, rather than trying to protect the package from what users can come up with. The reason explained by [Grady Booch](https://en.wikipedia.org/wiki/Grady_Booch): "*Users are amazingly creative when it comes to exercising systems in unexpected ways*". Often you end up with bugs in your protection feature - work and grief for you and annoyance for your users. How about a very short and useful one page PDF with deployment information? And a short list of what **not** to do. [**Maybe see the PDF-section here**](https://stackoverflow.com/a/50455886/129130). – Stein Åsmul May 26 '18 at 14:23
  • Is your package very big perhaps? Can it be modularized so you can leave out certain parts of it from a standard install? You can use [**MSI features**](https://stackoverflow.com/a/1055861/129130) to allow this. You get *"user selectable pieces"* of functionality to install or not. For example, you can leave "**Developer SDK**" out of a default product install. Or you can leave out all **"Help Files**" - relying instead on online help, etc... We know deployment is a nuisance, and good deployment can't save a bad product, but bad deployment can sink a good product. – Stein Åsmul May 26 '18 at 14:28
0

Based on the users being able to manually install it (and hence using the UI sequence), it might be easier to:

  1. In the InstallUISequence, sequence the LaunchCondition action to just before the ExecuteAction action.

  2. Then in the LaunchCondition table, add a condition like so:

    Condition: TARGETDIR~<<"C:\Program Files\"

    Description: You must install to the Program Files folder

What we're saying in the condition is:

If the TARGETDIR starts with "C:\Program Files\" (therefore the user can install anywhere under this folder) continue with the install. Otherwise throw an error.

Rather then preventing certain locations, I'd probably just enforce the Program Files folder as a best practise.

Captain_Planet
  • 1,228
  • 1
  • 12
  • 28