I'm trying to set a public property in an InstallShield installer with a value containing space. While running the MSI installer, I'm using below command on PowerShell prompt. Since the value contains a space so I used double quotes to pass the value
msiexec -i "myinstaller.msi" MYDIRPATH="C:\new folder\data.txt"
It breaks the command as the argument value C:\new folder\data.txt
has a space in the string new folder
. It results in showing up below error prompt of msiexec. It suggests that arguments passed to the msiexec command is problematic:
If I run the very same command on Windows default command prompt then it works fine.
The options that I've tried so far are as below:
Note:
This answer addresses direct, but asynchronous invocation of msiexec
from PowerShell, as in the question. If you want synchronous invocation, use Start-Process
with the -Wait
switch, as shown in Kyle 74's helpful answer, which also avoids the quoting problems by passing the arguments as a single string with embedded quoting.
Additionally, if you add the -PassThru
switch, you can obtain a process-information object that allows you to query msiexec
's exit code later:
# Invoke msiexec and wait for its completion, then
# return a process-info object that contains msiexec's exit code.
$process = Start-Process -Wait -PassThru msiexec '-i "myinstaller.msi" MYDIRPATH="C:\new folder\data.txt"'
$process.ExitCode
msiexec
synchronous: pipe the call to a cmdlet, such as Wait-Process
msiexec ... | Wait-Process
) - see this answer for more information.To complement Marko Tica's helpful answer:
Calling external programs in PowerShell is notoriously difficult, because PowerShell, after having done its own parsing first, of necessity rebuilds the command line that is actually invoked behind the scenes in terms of quoting, and it's far from obvious what rules are applied.
msiexec.exe
requires.PSNativeCommandArgumentPassing
, available since Core 7.2.0-preview.5), the workaround would break. Sadly, it looks like then simply omitting the workaround won't work either, because it was decided not to include accommodations for the special quoting requirements of high-profile CLIs such as msiexec
- see GitHub issue #15143.To help with this problem, PSv3+ offers --%
, the stop-parsing symbol, which is the perfect fit here, given that the command line contains no references to PowerShell variables or expressions: --%
passes the rest of the command line as-is to the external utility, save for potential expansion of %...%
-style environment variables:
# Everything after --% is passed as-is.
msiexec --% -i "myinstaller.msi" MYDIRPATH="C:\new folder\data.txt"
If you do need to include the values of PowerShell variables or expressions in your msiexec
call, the safest option is to call via cmd /c
with a single argument containing the entire command line; for quoting convenience, the following example uses an expandable here-string (see the bottom section of this answer for an overview of PowerShell's string literals).
$myPath = 'C:\new folder\data.txt'
# Let cmd.exe invoke msiexec, with the quoting as specified.
cmd /c @"
msiexec --% -i "myinstaller.msi" MYDIRPATH="$myPath"
"@
If you don't mind installing a third-party module, the ie
function from the Native
module (Install-Module Native
) obviates the need for any workarounds: it fixes problems with arguments that have embedded "
chars. as well as empty-string arguments and contains important accommodations for high-profile CLIs such as msiexec
on Windows, and will continue to work as expected even with the PSNativeCommandArgumentPassing
feature in effect:
# `ie` takes care of all necessary behind-the-scenes re-quoting.
ie msiexec -i "myinstaller.msi" MYDIRPATH="C:\new folder\data.txt"
As for what you tried:
PowerShell translatedMYDIRPATH="C:\new folder\data.txt"
into"MYDIRPATH=C:\new folder\data.txt"
behind the scenes - note how the entire token is now enclosed in "..."
.
Arguably, these two forms should be considered equivalent by msiexec
, but all bets are off in the anarchic world of Windows command-line argument parsing.
This is the best way to install a program in general with Powershell.
Here's an example from my own script:
start-process "c:\temp\SQLClient\sqlncli (x64).msi" -argumentlist "/qn IACCEPTSQLNCLILICENSETERMS=YES" -wait
Use Start-Process "Path\to\file\file.msi or .exe" -argumentlist (Parameters) "-qn or whatever" -wait
.
Now -wait is important, if you have a script with a slew of programs being installed, the wait command, like piping to Out-Null, will force Powershell to wait until the program finishes installing before continuing forward.
Try with this
msiexec -i "myinstaller.msi" MYDIRPATH=`"C:\new folder\data.txt`"
The escape character in PowerShell is the grave-accent(`).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With