I have a Powershell script that runs fine in VSCode but from the Powershell Prompt, I'm getting an error. Below is the output.
→ C:\WINDOWS\system32› powershell.exe -file 'D:\Source\Repos\Powershell Scripts\SD-Report-Archive.ps1' -sourcePath 'D:\Archives\' -targetPath 'D:\Archives2\'
D:\Archives\
Get-ChildItem : Cannot find path 'D:\A' because it does not exist.
At D:\Source\Repos\Powershell Scripts\SD-Report-Archive.ps1:25 char:14
+ $files = Get-ChildItem -Recurse -File -Path $sourcePath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\A:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
As you can see on the 2nd line of the output I do a Write-Output of the parameter value that I am sending in and it's correct. When I execute Get-ChildItem it seems to truncate the value to 'D:\A' and I don't know why.
Param(
[Parameter(Mandatory = $true)]
[string]$sourcePath,
[Parameter(Mandatory = $true)]
[string]$targetPath
)
function Copy-FilesIntoFolders {
param()
Write-Output $sourcePath;
$files = Get-ChildItem -Path $sourcePath -Recurse -File
...
}
On Windows, PowerShell - of necessity - rebuilds the command line in order to invoke external programs.
Notably, most external programs don't understand single-quoted strings ('...'
) via their CLI, so after having performed its own parsing, PowerShell re-quotes the resulting (stringified) arguments using double quotes ("..."
) if it deems that necessary.
Unfortunately, this re-quoting is broken in several respects:
If the argument value doesn't contain spaces, no quoting is applied. Values without spaces but with special characters may therefore break commands, especially when another shell, such as cmd.exe
is invoked.
cmd /c echo 'a&b'
breaks, because a&b
is ultimately passed without quotes, and &
has special meaning in cmd.exe
If the argument has embedded double quotes ("
chars.), the re-quoting does not automatically escape them for syntactically correct embedding inside "..."
or unquoted literal use:
E.g., foo.exe 'Nat "King" Cole'
is translated to foo.exe "Nat "King" Cole"
- note the lack of escaping of the inner "
chars. - which results in a different string when parsed by most applications, namely Nat King Cole
(no double quotes).
You have to perform escaping manually, in addition to PowerShell's own escaping requirements, if applicable: foo.exe 'Nat \"King\" Cole'
or, with double-quoting, foo.exe "Nat \`"King\`" Cole"
(sic).
Similarly - as in your case - if the argument has spaces and ends in \
, that trailing \
is not escaped in the resulting double-quoted string, which breaks the argument syntax:
E.g., foo.exe 'a b\' c
becomes foo.exe "a b\" c
- however, most programs - including PowerShell's own CLI - interpret the \"
as an escaped "
char. rather than the closing double quote, resulting in misinterpretation of the argument, merging it with the next argument to result in a b" c
Again you have to perform escaping manually, by doubling the \
: foo.exe 'a b\\' c
\
is optional, simply omit the latter.