Running a powershell command using full path and arguments from command line [duplicate]

As an aside: The quoting-related part of the problem could have been avoided by using environment variable $env:ProgramFiles instead of literal "C:\Program Files\..." in the script path, which would have simplified the command to:
powershell "& $env:ProgramFiles\Folder\file.ps1 -verbose:$True -restart"


Indeed, in order to execute scripts referenced by literal paths with embedded spaces in PowerShell, those paths must be quoted and the quoted path must be passed to & or .

However, when using PowerShell’s CLI it is simpler to use -File (-f) to execute a script, which makes & unnecessary and simplifies quoting:

powershell -File "C:\Program Files\Folder\file.ps1" -Verbose -Restart

When PowerShell is called from the outside, arguments that follow -File are taken literally (after removing syntactic "...", if present) – they are not interpreted the way they would be if you ran the command from inside PowerShell; e.g., when calling from outside PowerShell, powershell -File script.ps1 $env:USERNAME would pass string $env:USERNAME verbatim to script.ps1 rather than expanding it – if you need that, use -Command.

Use -Command (-c) only if you need to pass a snippet of PowerShell code and/or arguments script-file arguments must be interpreted as they would from inside PowerShell:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"

Note: -Command is notably needed in order to be able to pass arrays as script-file arguments; see this answer.

The crucial improvements to your attempt are:

  • & is placed inside "...", which prevents cmd.exe from interpreting it itself, before PowerShell sees it.

  • The script path is enclosed in embedded quoting ('...'), so that PowerShell sees the path as quoted.

Note:

  • -Command is used for clarity; in Windows PowerShell, it can be omitted (as you did), because it is the default parameter; note, however, that in PowerShell Core the default is now -File. See this answer for a comprehensive overview of the two PowerShell CLIs.

  • You don’t strictly need to pass everything as one "..." string, but it is conceptually clearer that way.

See below for details.

Also note that how the (process) exit code is set differs between -File and -Command – see this answer.


As for what you tried:

Above command doesn’t run the script; Instead it’s opening the PS command prompt and when exiting it, it opens the script in notepad.

This implies that you’re calling from cmd.exe (from the Command Prompt or a batch file), where an & not enclosed in "..." has special meaning: it is the command-sequencing operator.

That is, your command is the equivalent of the following 2 commands, executed in sequence:

powershell
"C:\Program Files\Folder\file.ps1 -verbose:$True -restart"

The 1st command opens an interactive PowerShell session.
Only after you manually exit it does the 2nd command get executed.

Note that your specific symptom suggests that you used only "C:\Program Files\Folder\<file.ps1>", without arguments, as the 2nd command, which would indeed open that script file as a document, for editing.

With the arguments, the entire double-quoted string is interpreted as a filename, and you’ll get the usual ... is not recognized as an internal or external command, operable program or batch file.

In order for cmd.exe to pass a & through to a command being invoked, it must either be enclosed in "...", or, outside of such a string, escaped as ^&.

However, even fixing that one problem isn’t enough:

rem # !! Still doesn't work
powershell ^& "C:\Program Files\Folder\file.ps1 -verbose:$True -restart"

The other problem is that when you use the -Command CLI parameter, which is implied in your case, PowerShell uses the following logic to process the arguments:

  • Each argument is stripped of its enclosing "...", if present.
  • The stripped arguments are concatenated with spaces.
  • The resulting single string is then executed as PowerShell code.

That is, with the above command PowerShell tried to execute a string with the following verbatim content:

& C:\Program Files\Folder\file.ps1 -verbose:$True -restart

As you can see, the script file path, which contains a space, lacks the necessary quoting.

You have several options to provide the necessary quoting around the script path:


If you know that your script path does not contain ' chars, use embedded '...' quoting:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"

With only a single, outer pair of " chars., you needn’t worry about cmd.exe inadvertently interpreting your arguments up front, before they reach PowerShell.

You could also omit the outer quoting in this case, but that makes the unquoted arguments susceptible to unwanted interpretation by cmd.exe (though it’s fine in this case), and note that ' has no special meaning in cmd.exe, so a PowerShell-style '...' string is considered unquoted by cmd.exe:

rem # Works, but generally less robust than the above.
powershell -Command ^& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart

If you want to ensure that even paths with embedded ' chars. work properly:

Use embedded double-quoting, with the " escaped as \" (sic):

powershell -Command "& \"C:\Program Files\Folder\file.ps1\" -Verbose:$true -Restart"

Unfortunately, this again makes the string between the \" instances subject to potentially unwanted interpretation by cmd.exe.

You can work around this by using \"" (sic) instead, but that makes the string between the \"" instances subject to whitespace normalization: that is, multiple spaces in a row are folded into one.

In Windows PowerShell, you can avoid that by using "^"" (sic), but note that in PowerShell Core you’ll get the same behavior as with \"".

rem # The most robust form in Windows PowerShell.
rem # Still subject to whitespace normalization in PowerShell Core.
powershell -Command "& "^""C:\Program Files\Folder\file.ps1"^"" -Verbose:$true -Restart"

Leave a Comment