Powershell not interpreting spaces correctly

I have a script that is used to copy common binaries to known folders. This script is invoked by the build system after a successful build. This script is failing because Powershell is not parsing the arguments correctly that have spaces in them.

I tried searching for “Powershell -File” and “running a script from cmd.exe” but I didn’t find an answer.
Any help in determining whether the failure is user error or a bug would be appreciated.

The shell the build system uses in the NT command shell so I need call Powershell.exe with the -File parameter passing in the script and arguments. The arguments have spaces so must be quoted

Here is a script that will demonstrate the problem

"The number of parameters passed in is $($Args.Count)"
$i = 0
foreach ($arg in $Args) { echo "The $i parameter is $arg"; $i++ }

Here is the output of the above command line ran from the “NT shell” using single quotes
The number of parameters passed in is 7
The 0 parameter is 'D:\Users\robertla\Documents\Visual
The 1 parameter is Studio
The 2 parameter is 2017\Samples\Debug_Utilities'
The 3 parameter is ‘Debug
The 4 parameter is Utilities’
The 5 parameter is ‘.dll’
The 6 parameter is ‘Debug’

Using double quotes fails differently. The behavior is the same way as if the script was invoked from a Powershell shell
The number of parameters passed in is 2
The 0 parameter is D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities" Debug
The 1 parameter is Utilities .dll Debug

thx
bob

Double quotes should work fine e.g.

#Saved as E:\temp\testme.ps1
foreach ($arg in $args) {
	Write-Host $arg
}

From cmd:

powershell.exe -file E:\temp\testme.ps1 "D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\Debug Utilities.dll"

Output

D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\Debug Utilities.dll

What’s the source of the argument? Does the source have any extra quotes or line breaks that might screw things up?

The source is Visual Studio (VS) which has a number of macros. However the problem can be duplicated outside of Visual Studio

The macros I’m using to pass to the script are the: Project Name and Directory, type of binary (LIB/DLL) and whether this is a retail or debug build. This gives me enough information to copy the PDB and binary files to the LIB or BIN folder and the header to the Include folder so that other projects can access them.

To reproduce this behavior outside VS I’ve copied values of these macros, here they are again. Note this is a partial and not full path. Please try this as is either in NT shell (cmd.exe) or Powershell

powershell.exe -file E:\temp\testme.ps1 "D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\" "Debug Utilities.dll"

I find it interesting that Powershell correctly interprets the strings when one of the string values are a complete path to a file c:\…\ rather than a partial path c:\…\ but that doesn’t help me.

The behavior is slightly different when using single vs double quotes in the NT shell rather than Powershell. The reason I’m testing in NT’s shell is this is what VS will spawn in the Post-Build event. The reason for single quotes is Powershell pass the string along literally unlike double quotes where it pre-processes the string prior to passing it along

Ok, I understand now.

So what’s happening is that the final \ on the path is causing the second " to be escaped.

If you want to pass two arguments you can escape the \ by making the first argument

"D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\\"

Or you can join the items and pass as one argument using single quotes:

"'D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\' 'Debug Utilities.dll'"

Thanks Matt,

I understand I can add a second \ or remove the trailing \ either would work. Trouble is I’m not the one that is passing the arguments VS is.

I am passing this

powershell  -ExecutionPolicy remotesigned -File "%SampleDir%\update.ps1"  "$(ProjectDir)"   "$(TargetName)"  "$(TargetExt)"   "$(Configuration)"

VS will call the script filling in these values for the macro’s

powershell  -ExecutionPolicy remotesigned -File "%SampleDir%\update.ps1"  "D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\"   "Debug Utilities"  ".dll"   "Debug"

While under the covers these two commands may work quite differently. I think we all agree that the input passed to the script should be the same

powershell  -ExecutionPolicy remotesigned -File "$env:SampleDir\echo-args.ps1"  "D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\"   "Debug Utilities"  ".dll"   "Debug"
 & "$env:SampleDir\echo-args.ps1"  "D:\Users\robertla\Documents\Visual Studio 2017\Samples\Debug_Utilities\"   "Debug Utilities"  ".dll"   "Debug"