Skip to content

"-"-prefixed barewords in argument mode should always be interpreted as parameter names #4591

Closed

Description

#4578 shows that you can sometimes use --prefixed bareword as parameter values - namely only if the bareword happens not to (prefix)-match a parameter name of the target command - and when such barewords are recognized as values, they don't behave the same way as non---prefixed barewords with respect to interpolation and being recognized as a single argument.

This inconsistency is problematic.

Given, Jason Shirk (@lzybkr)'s comment at #4576 (comment)

The "workaround" is in my opinion the preferred style - use quotes.

it seems that the desired solution is to disallow --prefixed barewords as values and to always assume that such an unquoted --prefixed token is a parameter name.

# Currently interpreted as *value*, because no Write-Output parameter name starts with -z.
# This should no longer be supported.
> Write-Output -InputObject -z
-z

# Interpreted as *parameter name*, because -n prefix-matches parameter -NoEnumeration
> Write-Output -InputObject -n
Write-Output : Missing an argument for parameter 'InputObject'. Specify a parameter of type 'System.Management.Automation.PSObject[]' and try again.

Environment data

PowerShell Core v6.0.0-beta.5

Activity

  1. added
    WG-Languageparser, language semantics
    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif
    on Aug 16, 2017
  2. lzybkr commented on Aug 16, 2017

    @lzybkr
    Contributor

    I believe this is very much by design.

    These parameters as arguments are often parameters themselves, but they are unknown to the cmdlet accepting them.

    Here is a good example:

    PS> Get-Command -Syntax Get-ChildItem -Path cert:
    
    Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert] [-DocumentEncryptionCert] [-SSLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-ExpiringInDays <int>] [<CommonParameters>]
    
    Get-ChildItem [[-Filter] <string>] -LiteralPath <string[]> [-Include <string[]>] [-Exclude <string[]>] [-Recurse] [-Depth <uint32>] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert] [-DocumentEncryptionCert] [-SSLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-ExpiringInDays <int>] [<CommonParameters>]
    

    Get-Command accepts it's parameter ArgumentList with ValueFromRemainingArguments, and in this scenario, values that look like parameters are expected. The use case here is to help determine dynamic parameters (which is why I used cert: to show the syntax includes the correct dynamic parameters.)

    I suppose there could be a refinement to ValueFromRemainingArguments to specify that parameters are not arguments - that might be useful and avoid confusion in a few cases, but I'm not sure Write-Object is such a case as parameters are rarely named with that cmdlet.

  3. mklement0 commented on Aug 16, 2017

    @mklement0
    ContributorAuthor

    Leaving ValueFromRemainingArguments aside for now, which is not that common:

    While Write-Output was not the best example, there are definitely cmdlets where this inconsistency is more likely to arise:

    Get-Item -LiteralPath -z vs. Get-Item -LiteralPath -p, for instance.

    That the specific content of a token (beyond its lexical structure) would decide its syntactical role situtationally sounds iffy to me.

  4. lzybkr commented on Aug 16, 2017

    @lzybkr
    Contributor

    For non-cmdlet binding functions or for ValueFromRemainingArguments, the current behavior is definitely by design. In other cases, it might be of questionable value, but the behavior is consistent and I guess easy to explain.

    The parser doesn't interpret the script any differently - you can verify this by looking at the AST, so this is just a parameter binding issue.

  5. mklement0 commented on Aug 16, 2017

    @mklement0
    ContributorAuthor

    I suppose there could be a refinement to ValueFromRemainingArguments to specify that parameters are not arguments - that might be useful and avoid confusion in a few cases

    Don't get that, but let me point out how ValueFromRemainingArguments is confusing the way it works currently, using a less mind-bending example than Get-Command, namely Join-Path (as an aside: nothing in Join-Path -? tells us that ValueFromRemainingArguments is supported):

    # OK: non-"-"-prefixed tokens
    > Join-Path a b c
    a/b/c
    
    # OK: quoted "-"-prefixed tokens.
    > Join-Path '-z' '-z' '-z'
    -z/-z/-z
    
    # BROKEN: not clear what's happening here.
    > Join-Path -z -z -z
    
    cmdlet Join-Path at command pipeline position 1
    Supply values for the following parameters:
    Path[0]: 
    
  6. lzybkr commented on Aug 17, 2017

    @lzybkr
    Contributor

    Yeah, ValueFromRemainingArguments has issues, see #2038

  7. mklement0 commented on Aug 17, 2017

    @mklement0
    ContributorAuthor

    Pragmatically speaking:

    • I know we're talking about edge cases.

    • I know that I can avoid ambiguity by quoting.

    That said, not having to quote constantly due to uncertainty over how barewords will be interpreted would be nice - after all, use of barewords is a perk of argument mode / shell-like syntax.

    the behavior is consistent and I guess easy to explain.

    I'm not trying to be flippant when I say: Please do.

    I'm honestly confused at this point, so if you can give a concise, comprehensive explanation of how --prefixed barewords are meant to be handled in all scenarios - current bugs notwithstanding - based on rules people can actually keep in their heads, without needing to know how the parameter sausage is made, I'd personally appreciate it, but, as usual, documenting it for the world at large is the right thing to do.

    Also worth noting that PowerShell already has an unrelated bareword-rules complexity problem - see #3217

  8. mklement0 commented on Aug 17, 2017

    @mklement0
    ContributorAuthor

    P.S.: Let's not forget that when a -<letter>-prefixed bareword does make it through as a value, it is not expanded the same way as non --prefixed bareword, as originally discussed in #4578:

    > Join-Path a b z$HOME
    a/b/zhome/jdoe
    
    > Join-Path a b -z$HOME
    a/b/-z$HOME  # no expansion
  9. mklement0 commented on Aug 20, 2017

    @mklement0
    ContributorAuthor

    I've taken a step back; please see #4624

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifResolution-AnsweredThe question is answered.WG-Languageparser, language semantics

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions