about_Functions_Argument_Completion

Short description

Argument completion is a feature of PowerShell that provide hints, enables discovery, and speeds up input entry of argument values.

Long description

This article describes the different ways you can implement argument completers for PowerShell functions. Argument completers provide the possible values for a parameter. The available values are calculated at runtime when the user presses the Tab key after the parameter name. There are several ways to define an argument completer for a parameter.

Note

Tab is the default key binding on Windows. This keybinding can be changed by the PSReadLine module or the application that is hosting PowerShell. The keybinding is different on non-Windows platforms. For more information, see about_PSReadLine.

ValidateSet attribute

The ValidateSet attribute specifies a set of valid values for a parameter or variable and enables tab completion. PowerShell generates an error if a parameter or variable value doesn't match a value in the set. In the following example, the value of the Fruit parameter can only be Apple, Banana, or Pear.

Param(
    [Parameter(Mandatory=$true)]
    [ValidateSet('Apple', 'Banana', 'Pear')]
    [string[]]
    $Fruit
)

In the following example, the value of the variable $flavor must be either Chocolate, Strawberry, or Vanilla. The ValidateSet attribute can be used on any variable, not just parameters.

[ValidateSet('Chocolate', 'Strawberry', 'Vanilla')]
[string]$flavor = 'Strawberry'

The validation occurs whenever that variable is assigned even within the script.

Param(
    [ValidateSet('hello', 'world')]
    [string]$Message
)

$Message = 'bye'

This example returns the following error at runtime:

MetadataError: The attribute cannot be added because variable Message with
value bye would no longer be valid.

For more information about tab expansion, see about_Tab_Expansion.

Dynamic ValidateSet values using classes

You can use a Class to dynamically generate the values for ValidateSet at runtime. In the following example, the valid values for the variable $Sound are generated via a Class named SoundNames that checks three filesystem paths for available sound files:

Class SoundNames : System.Management.Automation.IValidateSetValuesGenerator {
    [string[]] GetValidValues() {
        $SoundPaths = '/System/Library/Sounds/',
                      '/Library/Sounds',
                      '~/Library/Sounds'
        $SoundNames = ForEach ($SoundPath in $SoundPaths) {
            If (Test-Path $SoundPath) {
                (Get-ChildItem $SoundPath).BaseName
            }
        }
        return [string[]] $SoundNames
    }
}

The [SoundNames] class is then implemented as a dynamic ValidateSet value as follows:

Param(
    [ValidateSet([SoundNames])]
    [string]$Sound
)

Note

The IValidateSetValuesGenerator class was introduced in PowerShell 6.0.

ArgumentCompletions attribute

The ArgumentCompletions attribute allows you to add tab completion values to a specific parameter. An ArgumentCompletions attribute must be defined for each parameter that needs tab completion. The ArgumentCompletions attribute is similar to ValidateSet. Both attributes take a list of values to be presented when the user presses Tab after the parameter name. However, unlike ValidateSet, the values are not validated and more like suggestions. Therefore the user can supply any value, not just the values in the list.

The ArgumentCompletions attribute should not be confused with the ArgumentCompleter attribute, which needs a scriptblock to define the options. the specified values are available

The syntax is as follows:

function Test-ArgumentCompletions {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ArgumentCompletions('Fruits', 'Vegetables')]
        $Type,

        [Parameter()]
        [ArgumentCompletions('Apple', 'Banana', 'Orange')]
        $Fruit,

        [Parameter()]
        [ArgumentCompletions('Onion', 'Carrot', 'Lettuce')]
        $Vegetable
    )
}

Each of the parameters is provided a list of options to the ArgumentCompletions attribute to enable tab completion.

This attribute was introduced in PowerShell 6.0.

ArgumentCompleter attribute

The ArgumentCompleter attribute allows you to add tab completion values to a specific parameter. An ArgumentCompleter attribute must be defined for each parameter that needs tab completion.

To add an ArgumentCompleter attribute, you need to define a script block that determines the values. The script block must take the following parameters in the order specified below. The parameter's names don't matter as the values are provided positionally.

The syntax is as follows:

function MyArgumentCompleter {
    Param(
        [Parameter(Mandatory)]
        [ArgumentCompleter( {
            param ( $commandName,
                    $parameterName,
                    $wordToComplete,
                    $commandAst,
                    $fakeBoundParameters )
            # Perform calculation of tab completed values here.
        } )]
        $ParamName
    )
}

ArgumentCompleter script block

The script block parameters are set to the following values:

  • $commandName (Position 0) - This parameter is set to the name of the command for which the script block is providing tab completion.
  • $parameterName (Position 1) - This parameter is set to the parameter whose value requires tab completion.
  • $wordToComplete (Position 2) - This parameter is set to value the user has provided before they pressed Tab. Your script block should use this value to determine tab completion values.
  • $commandAst (Position 3) - This parameter is set to the Abstract Syntax Tree (AST) for the current input line. For more information, see the AST type documentation.
  • $fakeBoundParameters (Position 4) - This parameter is set to a hashtable containing the $PSBoundParameters for the cmdlet, before the user pressed Tab. For more information, see about_Automatic_Variables.

The ArgumentCompleter script block must unroll the values using the pipeline, such as ForEach-Object, Where-Object, or another suitable method. Returning an array of values causes PowerShell to treat the entire array as one tab completion value.

The following example adds tab completion to the Value parameter. If only the Value parameter is specified, all possible values, or arguments, for Value are displayed. When the Type parameter is specified, the Value parameter only displays the possible values for that type.

In addition, the -like operator ensures that if the user types the following command and uses Tab completion, only Apple is returned.

Test-ArgumentCompleter -Type Fruits -Value A

function MyArgumentCompleter{
    param ( $commandName,
            $parameterName,
            $wordToComplete,
            $commandAst,
            $fakeBoundParameters )

    $possibleValues = @{
        Fruits = @('Apple', 'Orange', 'Banana')
        Vegetables = @('Onion', 'Carrot', 'Lettuce')
    }

    if ($fakeBoundParameters.ContainsKey('Type')) {
        $possibleValues[$fakeBoundParameters.Type] | Where-Object {
            $_ -like "$wordToComplete*"
        }
    } else {
        $possibleValues.Values | ForEach-Object {$_}
    }
}

function Test-ArgumentCompleter {
[CmdletBinding()]
 param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Fruits', 'Vegetables')]
        $Type,

        [Parameter(Mandatory=$true)]
        [ArgumentCompleter({ MyArgumentCompleter @args })]
        $Value
      )
}

Class-based argument completers

Beginning in PowerShell 7.2, a new feature was added that allows you to define more generic implementations of parameterized argument completers.

By deriving from ArgumentCompleterAttribute, it's possible to create generic completers that can be reused, for example:

[DirectoryCompleter(ContainingFile="pwsh.exe", Depth=2)]

[DateCompleter(WeekDay='Monday', From="LastYear")]

[GitCommits(Branch='release')]

The derived attributes must implement the IArgumentCompleterFactory interface and use property values to create a specialized completer.

using namespace System.Collections
using namespace System.Collections.Generic
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

class NumberCompleter : IArgumentCompleter {

    [int] $From
    [int] $To
    [int] $Step

    NumberCompleter([int] $from, [int] $to, [int] $step) {
        if ($from -gt $to) {
            throw [ArgumentOutOfRangeException]::new("from")
        }
        $this.From = $from
        $this.To = $to
        $this.Step = $step -lt 1 ? 1 : $step
    }

    [IEnumerable[CompletionResult]] CompleteArgument(
        [string] $CommandName,
        [string] $parameterName,
        [string] $wordToComplete,
        [CommandAst] $commandAst,
        [IDictionary] $fakeBoundParameters) {

        $resultList = [List[CompletionResult]]::new()
        $local:to = $this.To
        $local:step = $this.Step
        for ($i = $this.From; $i -lt $to; $i += $step) {
            $resultList.Add([CompletionResult]::new($i.ToString()))
        }

        return $resultList
    }
}

class NumberCompletionsAttribute : ArgumentCompleterAttribute, IArgumentCompleterFactory {
    [int] $From
    [int] $To
    [int] $Step

    NumberCompletionsAttribute([int] $from, [int] $to, [int] $step) {
        $this.From = $from
        $this.To = $to
        $this.Step = $step
    }

    [IArgumentCompleter] Create() { return [NumberCompleter]::new($this.From, $this.To, $this.Step) }
}

Usage from PowerShell would then be:

function Add{
    param(
       [NumberCompletions(0, 100, 5)]
       [int] $X,

       [NumberCompletions(0, 100, 5)]
       [int] $Y
    )
    $X + $Y
}

Register-ArgumentCompleter

The Register-ArgumentCompleter cmdlet registers a custom argument completer. An argument completer allows you to provide dynamic tab completion, at run time for any command that you specify.

For more information, see Register-ArgumentCompleter.

See also