This powershell code works fine:
powershell -NoProfile -Command {Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '"C:\Users\TestAccount\Desktop\cartella con spazi\test.vbs" "/CurrentDirectory:C:\Users\TestAccount\Desktop\Cartella con spazi" "/AppData:C:\Users\TestAccount\AppData\Roaming"'}
But when I enter the complete command, powershell leaves only one space between the words but in my path there are two consecutive ones:
Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList "-NoProfile -Command & {Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '\`"C:\Users\TestAccount\Desktop\cartella con spazi\test.vbs\`" \`"/CurrentDirectory:C:\Users\TestAccount\Desktop\Cartella con spazi\`" \`"/AppData:C:\Users\TestAccount\AppData\Roaming\`"'}"
Same error with this:
Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList "-NoProfile -Command Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '\`"C:\Users\TestAccount\Desktop\cartella con spazi\test.vbs\`" \`"/CurrentDirectory:C:\Users\TestAccount\Desktop\Cartella con spazi\`" \`"/AppData:C:\Users\TestAccount\AppData\Roaming\`"'"
This is the error message:
As you can see, in the error message the path contains only one space between words, while in the code I have correctly entered two consecutive ones.
This is the code to enter the credentials (just before the line that gives an error):
$username = 'Username'
$password = 'Password'
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
I've been getting a single line of code to work properly for days but without success.
Those example paths I entered are actually variables (with an indefinite number of consecutive spaces) and therefore by enclosing -ArgumentList in single quotes, the variables are not expanded.
You can adopt the strategy you think is most appropriate to help me.
Windows 10 Pro 64-bit
Powershell Version: 5.1.19041.1237 (Integrated in Windows 10).
UPDATE:
@mklement0 There is the problem that in reality the line in question contains an expandable variable:
Start-Process -FilePath powershell.exe -WorkingDirectory "$env:ALLUSERSPROFILE" -Credential $credential -WindowStyle Hidden -ArgumentList @"
-NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '\"$PWD\test.vbs\" \"/CurrentDirectory:$PWD\" \"/AppData:$env:APPDATA\"'"
"@
so if the path contains single quotes, the line goes in error.
UPDATE 2:
@mklement0 Your solution has stopped working since I put it in a script, which is what I need, with the following error message:
Note: This answer addresses the Start-Process
problem; for the unrelated problem with .ps1
files whose paths have spaces in them failing to run when they are double-clicked in File Explorer, see this answer.
Try the following, with the arguments passed verbatim:
Start-Process `
-FilePath powershell.exe `
-WorkingDirectory "$env:ALLUSERSPROFILE" `
-Credential $credential `
-WindowStyle Hidden `
-ArgumentList @'
-NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '\"C:\Users\TestAccount\Desktop\cartella con spazi\test.vbs\" \"/CurrentDirectory:C:\Users\TestAccount\Desktop\Cartella con spazi\" \"/AppData:C:\Users\TestAccount\AppData\Roaming\"'"
'@
The -Command
argument is enclosed in "..."
in order to preserve the command-internal spaces as-is.
The embedded "
characters in the command string are escaped as \"
The outer -ArgumentList
uses a here-string to simplify the embedded quoting.
@'<newline>...<newline>'@
) is used here; use the _expandable form, @"<newline>...<newline>"@
, if you need string interpolation (the ability to embed variable references and expressions) - see next section.While PowerShell-internally it is `
, the backtick, that serves as the escape character, PowerShell's CLI expects "
characters to be \
-escaped on the command line, so as to conform to the most widely used escaping convention.
The cross-platform PowerShell (Core) 7+ edition now also accepts ""
as an alternative to \"
, another common convention on Windows.
While you may situationally have to combine the two escaping approaches, i.e. to use `\"
in order to quote a "
first for the CLI and then for PowerShell-internal use, in the context of interpreting a -Command
argument, this isn't needed in the command above, because the inner -ArgumentList
argument uses single-quoting, inside of which "
can be be used as-is.
Generalized solution, with arguments provided via variables:
The assumption is that the variable whose value are to be used are named $dir1
, $dir2
, and $dir3
(and that their values have no embedded "
chars., but "
aren't supported in file-system paths on Windows anyway).
Start-Process `
-FilePath powershell.exe `
-WorkingDirectory "$env:ALLUSERSPROFILE" `
-Credential $credential `
-WindowStyle Hidden `
-ArgumentList @"
-NoProfile -Command "Start-Process -FilePath wscript.exe -Verb RunAs -ArgumentList '\"$($dir1 -replace "'", "''")\" \"/CurrentDirectory:$($dir2 -replace "'", "''")\" \"/AppData:$($dir3 -replace "'", "''")\"'"
"@
The interpolating form of a here-string (@"<newline>...<newline>"@
) must now be used for the outer -ArgumentList
argument.
Since the variable values are interpolated inside what powershell.exe
will see as a single-quoted string ('...'
), any '
characters embedded in the variable values must be escaped as ''
, which is what -replace "'", "''"
in the embedded $(...)
subexpressions does.
It can be difficult to diagnose problems with calls to external programs, especially in a nested call such as this. The following is a Windows solution; see the bottom for a Unix solution.
echoArgsPause.exe
:The following creates a helper executable, echoArgsPause.exe
, which echoes the full command line it was called with, as well as the individual arguments it has parsed the command line into, and then waits for a keystroke.
Note:
As a .NET-based *.exe
, it uses .NET's rules for command-line parsing, which in turn is based on Microsoft's C/C++ conventions. Unfortunately, not all executables are guaranteed to use the same conventions. And, indeed, the WSH CLIs (cscript.exe
and wscript.exe
) do not support embedded "
characters in arguments, for instance.
Run the code from Windows PowerShell, because the executable must be compiled via .NET Framework, not .NET (Core), because only the former reports the true, raw command line via [Environment]::CommandLine
.
For later reuse, place the resulting .\echoArgsPause.exe
file in a directory in your PATH (in a directory listed in $env:PATH
).
To create a variant that doesn't wait for a keystroke, remove the Console.Write("Press a key to exit: ");
and Console.ReadKey(true);
lines and change -OutputAssembly .\echoArgsPause.exe
to, say, -OutputAssembly ./echoArgs.exe
Add-Type -OutputType ConsoleApplication -OutputAssembly .\echoArgsPause.exe -TypeDefinition @'
using System;
static class ConsoleApp {
static int Main(string[] args) {
Console.WriteLine("\nraw: [{0}]\n", Environment.CommandLine);
for (int i = 0; i < args.Length; ++i) {
Console.WriteLine("arg #{0}: [{1}]", i, args[i]);
}
Console.Write("Press a key to exit: ");
Console.ReadKey(true);
return 0;
}
}
'@
echoArgsPause.exe
to troubleshoot a callechoArgsPause.exe
in lieu of your target executable (wscript.exe
) to print the command line and the parsed arguments.# Specify the full path to the helper executable.
# Here I'm assuming it is in the current dir.
$echoArgsPausePath = "$($PWD.ProviderPath)\echoArgsPause.exe"
# Sample variable values.
$dir1='c:\temp''o 1'
$dir2='c:\temp 2'
$dir3='c:\temp 3'
# Call your command, with echoArgsPause.exe in lieu
# of the target executable (wscript.exe)
Start-Process `
-FilePath powershell.exe `
-WorkingDirectory "$env:ALLUSERSPROFILE" `
-WindowStyle Hidden `
-ArgumentList @"
-NoProfile -Command "Start-Process -FilePath "$echoArgsPausePath" -Verb RunAs -ArgumentList '\"$($dir1 -replace "'", "''")\" \"/CurrentDirectory:$($dir2 -replace "'", "''")\" \"/AppData:$($dir3 -replace "'", "''")\"'"
"@
Unix-like platforms have no process-level command line; instead, they are launched via an array of verbatim arguments.
Therefore, a simple solution is to use the standard printf
utility to list each argument received on its own line; e.g.:
printf %s\n foo 'c:\temp''o 1' '3" of snow'
Output up to PowerShell (Core) 7.2.x (broken! note the missing "
):
foo
c:\temp'o 1
3 of snow
Output in v7.3.0+:
foo
c:\temp'o 1
3" of snow
The 7.2.x behavior reveals a long-standing bug with respect to passing arguments with embedded double quotes, which was fixed in 7.3.0; it is in effect by default on Unix-like platforms, but will be opt-in on Windows, at some point post-v7.3.1 - see this answer.