mongodbpowershellwindows-installer

Why doesn't this msiexec.exe command work in powershell?


I am trying to execute the following command through powershell, in a script invoked by an Advanced Installer generated installation program. The problem is that when the script executes, it chokes on a call to MSIEXEC.exe. More specifically, it puts up a windows dialog of the msiexec help screen.

Ok so maybe it doesn't like the way advanced installer is executing it. So I take the actual line that is causing problems:

msiexec.exe /q /i 'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' ADDLOCAL='all'

And when I execute this directly in powershell, I still get the same stupid help screen. I have tried every conceivable variation of this command line:

In all cases, I get the damnable "help" dialog. The only thing that appears to make a difference is if I leave off the INSTALLLOCATION and ADDLOCAL options. (These are apparently used as per "Unattended Installation part 2" found here: https://docs.mongodb.com/tutorials/install-mongodb-on-windows/). In that case it just exits quietly without installing anything.

I'm honestly at my wits' end having been beating my head against the wall on this all afternoon.

By the way, the reason I'm installing mongo in such an absurd way is I need a method of having a single-install system for my company's product. It depends on Mongo, and we have to have it run as a server and use authentication, so I have to have scripts to create the admin and database user and put it into authenticated mode. Since I needed to know where mongo was installed (to execute mongod.exe and mongo.exe) I need to query the user first for the location, then pass on the install location to the mongo installer. If I'm completely off the rails here please let me know that there's a better way. Thanks

EDITED: I forgot to mention I wrote my complete powershell script and tested it before trying to execute it through advanced installer. The script worked until I tried to run it through the installer. Strange that I still can't execute the command though manually now.


Solution

  • Update:


    It seems that in order to pass paths with embedded spaces to msiexec, you must use explicit embedded "..." quoting around them.

    In your case, this means that instead of passing
    INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\', you must pass INSTALLLOCATION='"C:\Program Files\MongoDB\Server\3.4\\"'[1]

    Note the embedded "..." and the extra \ at the end of the path to ensure that \" alone isn't mistaken for an escaped " by msiexec (though it may work without the extra \ too).

    To put it all together:

    # See v7.3+ caveat below.
    msiexec.exe /q /i `
      'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' `
      INSTALLLOCATION='"C:\Program Files\MongoDB\Server\3.4\\"' ADDLOCAL='all'
    

    Note:

    Caveat:

    # No workarounds needed with the 'ie' function from the 'Native' module.
    ie msiexec.exe /q /i 'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' ADDLOCAL='all'
    

    The alternative is to stick with the original quoting and use --%, the stop-parsing symbol, but note that this means that you cannot use PowerShell variables in all subsequent arguments (however, you could define environment variables - e.g. $env:foo = ... - and then reference them with cmd.exe syntax - e.g. %foo%`):

    msiexec.exe /q /i `
      'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' `
       --% INSTALLLOCATION="C:\Program Files\MongoDB\Server\3.4\\" ADDLOCAL='all'
    

    Note that msiexec, despite having a CLI (command-line interface), is a GUI-subsystem application, so it runs asynchronously by default; if you want to run it synchronously, preferably use the ... | Write-Output trick mentioned above; alternatively, use
    Start-Process -Wait:

    $msiArgs = '/q /i "C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi" INSTALLLOCATION="C:\Program Files\MongoDB\Server\3.4\\" ADDLOCAL=all'
    
    $ps = Start-Process -PassThru -Wait msiexec -ArgumentList $msiArgs
    
    # $ps.ExitCode contains msiexec's exit code.
    

    Note that the argument-list string, $msiArgs, is used as-is by Start-Process as part of the command line used to invoke the target program (msiexec), which means:

    Even though Start-Process technically supports passing the arguments individually, as an array, this is best avoided due to a longstanding bug - see GitHub issue #5576.


    [1] The reason that INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' doesn't work is that PowerShell transforms the argument by "..."-quoting it as a whole, which msiexec doesn't recognize; specifically, what is passed to msiexec in this case is:
    "INSTALLLOCATION=C:\Program Files\MongoDB\Server\3.4\"