最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

powershell - What is the precedence of parameter binding? - Stack Overflow

programmeradmin2浏览0评论

I am a PowerShell novice. Suppose that I wish to call

Get-Service -Name winrm, netlogon

Due to parameter binding, this will be parsed as if we typed @("winrm", "netlogon") rather than winrm, netlogon. But what is the precedence of parameter binding? Can anything happen before it? The documentation lists the comma operator as having very high precedence. But, somehow, parameter binding beats it.

I am a PowerShell novice. Suppose that I wish to call

Get-Service -Name winrm, netlogon

Due to parameter binding, this will be parsed as if we typed @("winrm", "netlogon") rather than winrm, netlogon. But what is the precedence of parameter binding? Can anything happen before it? The documentation lists the comma operator as having very high precedence. But, somehow, parameter binding beats it.

Share Improve this question asked Mar 12 at 22:38 J. MiniJ. Mini 1,6421 gold badge20 silver badges56 bronze badges 1
  • 1 Lots of things happen before parameter binding. Parsing of the entire script, injection of usage directives, type compilation, and then of course the invocation of all previous statements in the same block for example. Is that what you're asking about? – Mathias R. Jessen Commented Mar 13 at 9:52
Add a comment  | 

1 Answer 1

Reset to default 3
  • Operator precedence in PowerShell only applies to expressions, i.e. code parsed in expression (parsing) mode.

  • By contrast, any call to a command (such as Get-Service) is parsed in argument (parsing) mode.

    • In this mode, the overall parsing logic is based on invoking a command (a named unit of executable code, which may be a PowerShell command (alias, cmdlet, function, script block), a PowerShell script file (*.ps1), or an external program) with zero or more (potentially named) arguments.

      • See the conceptual about_Command_Syntax help topic for more information
    • , - the array constructor ("comma") operator - is the only operator that is directly recognized in this mode and only in the context of a given command argument.

      • Unlike in expression mode, its operands (array elements) - just like stand-alone arguments - may be passed as so-called barewords, i.e. as unquoted strings, as long as they don't contain any (unescaped) metacharacters, notably spaces.

      • However, you're free to use expressions as arguments via (...), the grouping operator, which also accepts a command (pipeline); you may even pass (the output from) entire statements via $(...), the subexpression operator, or @(...), the array-subexpression operator.

  • Irrespective of how a command argument is passed - whether as a (potentially expandable, i.e. interpolating) bareword, a (potentially expandable) string literal, via (...), $(...), or @(...) - it is evaluated up front, which in the case of embedded commands or statements means that they are run to completion, before the (potentially collected) result(s) are passed to the target command.

  • In argument mode, the , operator allows you to construct an array from two or more of any of the above-mentioned constructs; let's call them <token> in this discussion:

    • <token>, <token>[, ...] - whitespace around , is optional.
    • Each token, if applicable, is evaluated first, before the array is constructed and passed to the target command, though note that only PowerShell commands are fundamentally capable of receiving arrays such - external programs are not (see below).

Given that argument winrm, netlogon is passed to a PowerShell command, it is indeed equivalent to the following expression: @('winrm', 'netlogon'), i.e. it constructs a 2-element array whose elements are strings.[1]

By contrast, an external program would see this as two arguments, namely verbatim winrm, and netlogon.[2]

If you want any given command to receive winrm, netlogon as a single string, use quoting, e.g. a verbatim string, '...', i.e. 'winrm, netlogon'; if you need string interpolation (expansion), use an expandable string, "...", e.g. "$serviceName1, netlogon"

If you want to use , verbatim as part of a bareword, use `, the so-called backtick, PowerShell's escape character, e.g. winrm`,

For a comprehensive overview of how unquoted command arguments are parsed in argument mode, see this answer.


[1] But note that it depends on the type of the parameter of the target command that the argument binds whether an array is accepted as such. See this answer for more information.

[2] This applies to PowerShell (Core) 7; in Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1), the trailing , is _stripped from winrm. By contrast, if you were to pass winrm,netlogin, i.e. a token without spaces, verbatim winrm,netlogin would be passed in both editions. Another notably difference - which is regrettable owed to a bug - is that PowerShell (Core) 7 neglects to expand (interpolate) the ,-separated elements when calling external programs, even though it should, and does so both in isolation and when calling PowerShell commands; e.g., passing $HOME alone to an external program passes the value of said variable in both editions, but passing $HOME, foo does not result in expansion of $HOME in PowerShell 7 as of v7.5.x. See GitHub issue #18502 for the relevant bug report.

发布评论

评论列表(0)

  1. 暂无评论