Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Script Argument matching

Does PowerShell do some sort of nearest match or autocompletion when dealing with arguments passed to a script? Given this code...

[CmdletBinding()]
Param(
    [string][Alias("aS")] $applySet,
    [string][Alias("cS")] $conformSet,

    [string][Alias("sL")] $setList,
    [Parameter(ValueFromRemainingArguments = $true)][Object[]]$extraParameters = @()
)

Write-Host "s:  $set"
Write-Host "sL: $setList"
Write-Host "aS: $applySet"
Write-Host "cS: $conformSet"
Write-Host "X:  $extraParameters"

If I use -junk "junk" in the script shortcut I get that info in $extraParameters as expected. Misspelling something, say -aplySet, also shows up as an extra parameter. However, using -set actually populates the $setList variable rather than $extraParameters as I would expect.

Verified in PowerShell 2.0 and 5.1. Any thoughts?

like image 734
Gordon Avatar asked Mar 11 '23 18:03

Gordon


2 Answers

It is somewhat undocumented, as far as I can tell.

  • about_Parameters doesn't mention the use of abbreviated parameters.
  • about_Command_Syntax talks about using parameters but not short versions.
  • I Save-Help'd all the help and grep sls'd it for likely terms, couldn't see anything relevant.
  • This blog post from 2006 talks about it, so it has been in PowerShell since version 1.0

In PowerShell 1.0, part of the parameter name resolution logic includes support for identifying parameters by the shortest substring that uniquely identifies the parameter or an alias to the parameter when compared with a list of parameters and aliases for the cmdlet.

and it's mentioned in PowerShell developer Bruce Payette's book 'PowerShell In Action', chapter 2, P.39-40:

The piece of the PowerShell interpreter that figures all of this out is called the parameter binder. The parameter binder is smart - it doesn’t require that you specify the full name of a parameter as long as you specify enough for it to uniquely distinguish what you mean.

But that's it, no comment on design choice or rationale that I can see. Speculating, as @Mike Shepard comments, PowerShell's dual role as an interactive shell (where people want to type as little as possible, and are writing one-off throwaway commands) and a scripting language (where people want clarity, readability, maintainability by multiple people over longer times) is what gives rise to the short form / long form versions of everything.

gci -r | sls (date)
Get-ChildItem -Recurse | Select-String -Pattern (Get-Date)
  • Aliases
  • Positional parameter binding, without the parameter name
  • Parameter name abbreviation
  • Parameter to object property automagic binding
  • Command resolution can lookup Get- cmdlets if the Get- is left out

Fwiw, it appears to be this line in the source code of System.Management.Automation/engine/MergedCommandParameterMetadat.cs, which someone on the PowerShell Slack identified, which actually does the parameter match:

foreach (string parameterName in _bindableParameters.Keys)
{
// ---
    if (CultureInfo.InvariantCulture.CompareInfo.IsPrefix(parameterName, name, CompareOptions.IgnoreCase))
// ---
    {
        // If it is an exact match then only return the exact match
        // as the result

        if (tryExactMatching && String.Equals(parameterName, name, StringComparison.OrdinalIgnoreCase))
        {
            return _bindableParameters[parameterName];
        }
        else
        {
            matchingParameters.Add(_bindableParameters[parameterName]);
        }
    }
}
like image 183
TessellatingHeckler Avatar answered Mar 13 '23 08:03

TessellatingHeckler


PowerShell allows using the initial characters of a parameter name as long as they are unambiguous.

like image 31
Mike Shepard Avatar answered Mar 13 '23 07:03

Mike Shepard