Using --% in PowerShell

I also blogged about this shortly after v3 shipped. --% turns PowerShell into a dumb parser from that character sequence until the end of the line. That means you don't get any variable evaluation after --%.. However, you case use environment variables like so:

$env:hostname = $hostname
$env:user     = $user
$env:passwd   = $password
$env:command  = $command
.\plink.exe --% %hostname% -l %user% -pw %passwd% %Command%

That said, in this scenario I don't see any reason to use --%. This should work just fine:

.\plink.exe $Hostname -l $Username -pw $Password $Command

You only want to use --% when the EXE's command line arguments expect arguments with characters that trip up PowerShell e.g.:

tf.exe status . /r /workspace:*;domain\user

In this case, tf.exe uses ; to separate the workspace name from the workspace owner but PowerShell interprets the ; as a statement separator which messes up the invocation of tf.exe. You would fix it like so:

tf.exe status . /r --% /workspace:*;domain\user

BTW the use of & is unnecessary here because you don't need to quote `.\plink.exe'. You would only need to quote it if the filename or path contained a space.


I had this same problem, and there is a workaround for this problem. I recently blogged about this (Use PowerShell variables after escaping parsing in PowerShell v3.0 - 2013-09-17) after taking inspiration from my own answer, Executing external command from PowerShell is not accepting a parameter.

The trick is to use --% itself as a variable and include that along with other variables in PowerShell.

So instead of this,

&"./plink.exe" --% $Hostname -l $Username -pw $Password $Command

try this:

$escapeparser = '--%'
& "./plink.exe" $escapeparser $Hostname -l $Username -pw $Password $Command

It may be related, but I used single quotes in all variables.


--% will prevent the remainder of a statement from being parsed by PowerShell. Jose Barreto's Blog on TechNet has a very relevant entry to this problem. Along with providing example usage of --%, there are others, such as cmd /c, which may be more helpful for solving your issue since PowerShell not resolving variables after --% seems problematic for your use case.

--% is new in PowerShell version 3.

Some example usage from the linked blog:

PS C:\> ICACLS.EXE --% C:\TEST /GRANT USERS:(F)
processed file: C:\TEST
Successfully processed 1 files; Failed processing 0 files

PS C:\> ICACLS.EXE C:\TEST --% /GRANT USERS:(F)
processed file: C:\TEST
Successfully processed 1 files; Failed processing 0 files

As I mentioned above, you would probably be better off trying a solution where you can use PowerShell variables. & " " or cmd /c " " will both resolve variables and may be a good place to start.

cmd /c "path/plink.exe $Hostname -l $Username -pw $Password $Command"

I was digging around in the PowerShell Language Specification for something unrelated and found some documentation for --%. I'll post it here in the hopes that it will be easier to find online for future users:

Excerpt from 8.2 "Pipeline statements"

An argument of --% indicates that all arguments following it are to be passed with minimal parsing and processing. This argument is called the verbatim parameter. Arguments after the verbatim parameter are not PowerShell expressions even if they are syntactically valid PowerShell expressions.

Windows PowerShell: If the command type is Application, the parameter --% is not passed to the command. The arguments after --% have any environment variables (strings surrounded by %) expanded. For example:

echoargs.exe --% "%path%" # %path% is replaced with the value $env:path

Tags:

Powershell