Reputation: 843
I execute the following lines in powershell :
$argList = "-NoExit -NoProfile -Command {Write-Host 'hello world'}";
Start-Process PowerShell -ArgumentList $argList;
My desired output is to create a new powershell windows and output the hello world
.
But what I get is opening a new powershell windows and writing the command itself like Write-Host 'hello world'
. So the Write-Host actually is not executed in the new window. how to solve this?
Upvotes: 1
Views: 2144
Reputation: 437708
Theo's helpful answer provides effective solutions; to add some background information:
It is only from inside a PowerShell session, in direct invocation of powershell.exe
, the Windows PowerShell CLI[1], that you can use a script block ({ ... }
) by itself[2]; e.g.:
# Works, but only from inside a PowerShell session.'
# -Command may be omitted.
PS> powershell -NoProfile -Command { Write-Host 'hello world' }
hello world
By contrast, calling the CLI via Start-Process
invariably behaves like an invocation from the outside, where everything following -Command
is parsed as strings, and, after removing outer "
quoting, the resulting tokens are joined with spaces and then interpreted as PowerShell source code, as if you had submitted that code from inside PowerShell.
Submitting a script block by itself inside a PowerShell session does not results in its execution; it simply outputs its verbatim content (except {
and }
), and that is what you saw:
# Submitting a script block *definition* without *calling it* prints
# its verbatim content as a string, it is the equivalent of calling .ToString()
# on it.
PS> { Write-Host 'hello world' }
Write-Host 'hello world'
Therefore, you could have made your solution work simply by prepending &
, the call operator to the embedded script block in order to ensure its execution:
# Note the `&` before the script block to ensure that it is *called*.
$argList = "-NoExit -NoProfile -Command & { Write-Host 'hello world' }"
Start-Process pwsh -ArgumentList $argList
[1] This applies analogously to pwsh
, the PowerShell (Core) 7 CLI.
[2] In this scenario, PowerShell translates the script block as well as any arguments into Base64-encoded strings behind the scenes, and passes them via -EncodedCommand
and -EncodedArguments
, along with -OutputFormat Xml
. The receiving PowerShell process decodes these strings, executes the command, and serializes the output objects as CLIXML, which the calling PowerShell session automatically deserializes, which ensures rich type support, albeit within the limits of serialization - see the bottom section of this answer for details.
It is the need for this behind-the-scenes translation / deserialization that implies that the technique can only work from PowerShell.
Upvotes: 6
Reputation: 61068
The problem is in the quoting of the $argList string in which you insert the scriptblock as text.
Try any of these:
$argList = "-NoExit -NoProfile `"Write-Host 'hello world'`"" # works
$argList = "-NoExit -NoProfile -Command `"Write-Host 'hello world'`"" # works
$arglist = '-NoExit', '-NoProfile', '-Command', 'Write-Host "hello world"' # works
$arglist = '-NoExit', '-NoProfile', '-Command', {Write-Host "hello world"} # works
$argList = '-NoExit -NoProfile -Command', {Write-Host "hello world"} # works
$argList = '-NoExit -NoProfile -Command', 'Write-Host "hello world"' # works
Start-Process PowerShell -ArgumentList $argList
Upvotes: 5