1

if I do this in a powershell:

echo beep ; echo beep

it prints:

beep
beep

but if I do this in a regular console:

powershell -command { echo beep ; echo beep }

it prints:

echo beep ; echo beep

what is the correct syntax to obtain the same result ?

2
  • 4
    powershell -command "&{echo beep ; echo beep}" Commented Sep 30, 2017 at 18:31
  • 1
    @SagePourpre That works, but note that there's no reason to use & { ... } in order to invoke code passed to PowerShell's CLI via the -command (-c) parameter - just use ... directly. Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected - see this GitHub docs issue. Commented Aug 9, 2020 at 1:40

1 Answer 1

1

Passing a list of commands inside a script block ({ ... }) to powershell -Command for execution as-is is only supported from within PowerShell itself, as running powershell -h will tell you.

From outside of PowerShell, simply pass the commands as-is, but preferably inside double quotes, so as to prevent unintended up-front interpretation of the arguments by cmd.exe:

powershell -command "echo beep ; echo beep"

Note, however, that cmd.exe-style environment-variable references (e.g., %USER%) are still expanded up front.

Alternatively, you could pass a script block (string)[1] preceded by &, the call operator to ensure the script block's execution, but that is only necessary if you want to pass arguments to the script block:

powershell -command "& { echo $Args[0]; echo $Args[0] } beep"

beep is passed as the 1st argument, which the script block references as $Args[0].


As an aside: In PowerShell echo is an alias of Write-Output, which writes to the success output stream; the output from any command or expression that isn't captured or redirected implicitly goes to the output stream, so that use of echo / Write-Output is generally unnecessary:

powershell -command "& { $Args[0]; $Args[0] } beep"

[1] From inside PowerShell, passing a script block to powershell -command causes the calling PowerShell session to recognize it and to treat the enclosed commands as the ones to pass to the new session to execute.
From outside of PowerShell, {...} is a string passed to the new session, and it is the new session that then parses that string as PowerShell code. Evaluating a script block by itself, without explicit invocation via & (or .), simply outputs the literal contents of the script block, which explains your output; you can verify this behavior by submitting
{ echo beep; echo beep } at the PowerShell prompt.

Sign up to request clarification or add additional context in comments.

4 Comments

It recognize passing script block to any native application, but not powershell -command only: cmd /c echo -command { Test } -args Test
@PetSerAl: Thanks; that is intriguing - and smells like a bug. Am I missing something? Is there a good reason for this behavior?
I do not know why it implemented this way. I can only speculate. Likely it is just better than other alternatives, like invent some complex buggy rule to decide when enable this transformation and when not. For example: cmd /c powershell -command { Test }. You can not just pass ScriptBlock to ordinary process anyway, nothing will broke if you always do that transformation.
Thanks, @PetSerAl. It's definitely an edge case and I get that detecting when PowerShell is the target executable is not always trivial, but note that you don't even need a preceding -command to trigger the current behavior: any script block on the command line triggers the Base64-encoding behavior, whereas you could argue that when not invoking PowerShell, a script block should simply be stringified (.ToString()) when passed to an external utility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.