I create an installer and during installation the user is asked for the install path.
If the user enters a path that contains spaces, then I can get the uninstaller to run, but at the end of the uninstall process, all the features that should have been removed have not been.
The user is asked for the install directory as follows:
<directoryParameter name=' installdirOrig'
default=' ${platform_install_prefix}/${project.vendor}/${product_shortname}'
ask=' yes'
mustBeWritable=' yes'
mustExist=' 0'
width=' 40' >
<validationActionList>
<!-- Replace space with '+', then in scripts revert '+' to space -->
<setInstallerVariableFromRegEx name=' installdir'
pattern=' '
text=' ${installdirOrig}'
substitution=' +' />
<globalVariables names=' installdir' />
</validationActionList>
</directoryParameter>
The install path has spaces replaced by '+' and the scripts that use the install path revert '+' to space
During uninstall I run a number of powershell scripts initiated from functions.
A typical example is to ask for the user password as follows:
<runProgram program=' cmd.exe'
showMessageOnError=' 0'
abortOnError=' 0' >
<programArguments>/C ' ${msg(PowershellTemplate)} -File ${installdirOrig.dos}/scripts/validate-credentials.ps1 ${accessUsername} ${accessDomain} ${accessPassword.password} &' </programArguments>
</runProgram>
where ${msg(PowershellTemplate)} is defined as:
PowershellTemplate=powershell.exe -ExecutionPolicy Unrestricted -NonInteractive -WindowStyle Hidden
I've used ${installdirOrig.dos} so that spaces will be handled correctly
However, the uninstall log has entries like
Validate the user credentials
Executing cmd.exe /C ' powershell.exe -ExecutionPolicy Unrestricted -NonInteractive -WindowStyle Hidden -File C: or PROGRA~1 or InstallPath or Path with spaces/scripts/validate-credentials.ps1 username domain **** &'
Script exit code: 0
It looks like 'Program Files' has been altered, but 'Path with spaces' has not
All of the scripts that are executed in this manner return a script exit code of 0, but when the install path contains spaces, not everything is removed as expected by the uninstaller. In contrast, when the install path does NOT contain spaces, everything is removed as expected by the uninstaller.
The &
at the end of the arguments was found to be necessary, otherwise the scripts failed with:
child killed: unknown signal
I'm not sure exactly what is happening, but because there are spaces in the -File switch to the powershell.exe
command, then I'm guessing that the remainder are treated as parameters.
How can I correctly handle a path with spaces during uninstall ?
Thanks for any help
What you can do is use .dos
to convert path to short paths - such as:
<directoryParameter name= or ' installdirOrig or ' default= or ' ${platform_install_prefix}/${project.vendor}/${product_shortname} or ' ask= or ' yes or ' mustBeWritable= or ' yes or ' mustExist= or ' 0 or ' width= or ' 40 or ' > <validationActionList> <!-- Replace space with '+', then in scripts revert '+' to space --> <setInstallerVariableFromRegEx name= or ' installdir or ' pattern= or ' or ' text= or ' ${installdirOrig.dos} or ' substitution= or ' + or ' /> <globalVariables names= or ' installdir or ' /> </validationActionList> </directoryParameter>
This will convert ${installdirOrig} to short names and the rest of the XML should use the value properly.
Also, it should not be needed to run cmd /c to run powershell - for example:
<runProgram program= or ' ${msg(PowershellTemplate)} or ' showMessageOnError= or ' 0 or ' abortOnError= or ' 0 or ' > <programArguments>-File or ' ${installdirOrig.dos}/scripts/validate-credentials.ps1 or ' or ' ${accessUsername} or ' or ' ${accessDomain} or ' or ' ${accessPassword.password} or ' & or ' </programArguments> </runProgram>
The problem with your XML is that cmd /c performs space parsing on its own and it is very tricky to get this to work. If you need to use cmd /c, it may be easier to use <writeFile>
and create a temporary .bat file instead.
Thanks for the answer. I've tried the suggestion but I'm not getting what I expect.
For the substitution, I've used as suggested and logged the substitution
<logMessage text= or ' If ${installdirOrig} contains spaces it will be handled as ${installdir} or ' /> [14:58:11] If C: or or Program Files or or InstallPath or or Path with spaces contains spaces it will be handled as C: or or Program+Files or or InstallPath or or Path+with+spaces
Would I expect ${installdirOrig.dos}
to evaluate to something like:
C: or or Progra~1 or or InstallPath or or Path~2 or or
It seems that the .dos modifier suffix is not removing spaces - or am I missing something ?
I've also tried running the powershell command directly as suggested, but I get an error as the following script and log entry shows:
<runProgram program= or ' ${msg(PowershellTemplate)} or ' showMessageOnError= or ' 0 or ' abortOnError= or ' 0 or ' > <programArguments> -File or ' ${installdirOrig.dos}/scripts/validate-credentials.ps1 or ' or ' ${accessUsername} or ' or ' ${accessDomain} or ' or ' ${accessPassword.password} or ' & or ' </programArguments> </runProgram> Validate the user credentials Executing powershell.exe -ExecutionPolicy Unrestricted -NonInteractive -WindowStyle Hidden -File or ' C: or or PROGRA~1 or or InstallPath or or Path with spaces/scripts/validate-credentials.ps1 or ' or ' username or ' or ' domain or ' or ' **** or ' & or ' Script exit code: Script output: Script stderr: Unknown error while running powershell.exe -ExecutionPolicy Unrestricted -NonInteractive -WindowStyle Hidden -File or ' C: or or PROGRA~1 or or InstallPath or or Path with spaces/scripts/validate-credentials.ps1 or ' or ' username or ' or ' domain or ' or ' **** or ' & or '
I suspect this is related to:
and is the reason for launching powershell via the cmd /c
I think that is exactly the problem.
I'm asking the user for an installation directory that may not exist before the installation.
The user may very well choose a new install location and that new install location could contain spaces.
Any suggestions of a way around this ?
I have tried to create the install directory immediately after asking the user for the parameter.
Then I do the substitution - and this is what I get:
<!-- Immediately create the install directory so that .dos modifier suffix can be used --> <createDirectory path= or ' ${installdirOrig} or ' /> <!-- Convert installdirOrig to Dos short name --> <!-- Replace space with '+', then in scripts revert '+' to space --> <setInstallerVariableFromRegEx name= or ' installdir or ' pattern= or ' or ' text= or ' ${installdirOrig.dos} or ' substitution= or ' + or ' /> <globalVariables names= or ' installdir or ' /> <logMessage text= or ' If ${installdirOrig} contains spaces ${installdirOrig.dos} will handle spaces as ${installdir} or ' />
The log file entry is:
[17:13:07] If C: or or Program Files or or InstallPath or or Path with space contains spaces C: or or PROGRA~1 or or InstallPath or or Path with space will handle spaces as C: or or PROGRA~1 or or InstallPath or or Path+with+space
So it looks like the .dos modifier suffix is correctly handling the space in Program Files
but not in Path with space
Is that how it is intended to work ?
I finally managed to fix the problem of installing / uninstalling when the user selects a path that includes spaces. The fix is to use the <writeFile>
mechanism as suggested above.
In order to get the .bat file to work correctly with Powershell, the following is required:
<writeFile> <path>${sxg_temp.dos}/adlds_cred_uninstall.bat</path> <text> start /wait powershell.exe -File or ' ${installdir.dos}/scripts/validate-credentials.ps1 or ' ${accessUsername} ${accessDomain} ${accessPassword.password} </text> </writeFile>
where start /wait causes
the command to return only when the powershell has completed.
Using the above, the install path can be enclosed in quotes, so spaces are handled Ok.