From feeceb57a829b34e6472610761cc0224769c0642 Mon Sep 17 00:00:00 2001 From: Bobby Reed Date: Mon, 20 May 2019 12:51:25 -0400 Subject: [PATCH] Fixes #3604, Fixes #3603 - Document ArgumentCompleter --- .../about_Functions_Advanced_Parameters.md | 169 +++++++++++++---- .../Register-ArgumentCompleter.md | 170 ++++++++++++++--- .../about_Functions_Advanced_Parameters.md | 175 +++++++++++++----- .../Register-ArgumentCompleter.md | 171 ++++++++++++++--- .../about_Functions_Advanced_Parameters.md | 173 ++++++++++++----- .../Register-ArgumentCompleter.md | 171 ++++++++++++++--- 6 files changed, 813 insertions(+), 216 deletions(-) diff --git a/reference/5.0/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md b/reference/5.0/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md index b3154737a112..0c4b81d06bca 100644 --- a/reference/5.0/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md +++ b/reference/5.0/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md @@ -1,5 +1,5 @@ --- -ms.date: 11/28/2017 +ms.date: 5/20/2019 schema: 2.0.0 locale: en-us keywords: powershell,cmdlet @@ -8,6 +8,7 @@ title: about_Functions_Advanced_Parameters # About Functions Advanced Parameters ## Short description + Explains how to add parameters to advanced functions. ## Long description @@ -41,7 +42,7 @@ has the following characteristics: ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [String[]] $ComputerName @@ -79,7 +80,7 @@ must follow "`Parameter`" with no intervening space. ```powershell Param( - [parameter(Argument=value)] + [Parameter(Argument=value)] $ParameterName ) ``` @@ -89,7 +90,7 @@ syntax to declare two arguments of the `Parameter` attribute. ```powershell Param( - [parameter(Argument1=value1, + [Parameter(Argument1=value1, Argument2=value2)] ) ``` @@ -100,7 +101,7 @@ name are still required. ```powershell Param( - [parameter()] + [Parameter()] $ParameterName ) ``` @@ -115,7 +116,7 @@ The following example declares the `ComputerName` parameter. It uses the ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [String[]] $ComputerName ) @@ -157,7 +158,7 @@ value in the command. ```powershell Param( - [parameter(Position=0)] + [Parameter(Position=0)] [String[]] $ComputerName ) @@ -184,17 +185,17 @@ parameter set, a `UserName` parameter in the "User" parameter set, and a ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="Computer")] [String[]] $ComputerName, - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="User")] [String[]] $UserName, - [parameter(Mandatory=$false)] + [Parameter(Mandatory=$false)] [Switch] $Summary ) @@ -211,18 +212,18 @@ parameter set and **Optional** in the other. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="Computer")] [String[]] $ComputerName, - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="User")] [String[]] $UserName, - [parameter(Mandatory=$false, ParameterSetName="Computer")] - [parameter(Mandatory=$true, ParameterSetName="User")] + [Parameter(Mandatory=$false, ParameterSetName="Computer")] + [Parameter(Mandatory=$true, ParameterSetName="User")] [Switch] $Summary ) @@ -242,7 +243,7 @@ and accepts an object that is passed to the function from the pipeline. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [String[]] $ComputerName @@ -265,7 +266,7 @@ passed to the function through the pipeline. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [String[]] $ComputerName @@ -296,7 +297,7 @@ function. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] [String[]] $ComputerName @@ -315,7 +316,7 @@ help message that explains the expected parameter value. ```powershell Param( - [parameter(mandatory=$true, + [Parameter(mandatory=$true, HelpMessage="Enter one or more computer names separated by commas.")] [String[]] $ComputerName @@ -332,8 +333,8 @@ The following example shows a parameter declaration that adds the "CN" and ```powershell Param( - [parameter(Mandatory=$true)] - [alias("CN","MachineName")] + [Parameter(Mandatory=$true)] + [Alias("CN","MachineName")] [String[]] $ComputerName ) @@ -355,7 +356,7 @@ a Null value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowNull()] [String] $ComputerName @@ -370,7 +371,7 @@ parameter that can have an empty string value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowEmptyString()] [String] $ComputerName @@ -385,7 +386,7 @@ parameter that can have a empty collection value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowEmptyCollection()] [String[]] $ComputerName @@ -404,7 +405,7 @@ takes one to five parameter values. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateCount(1,5)] [String[]] $ComputerName @@ -422,7 +423,7 @@ In the following example, each computer name must have one to ten characters. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateLength(1,10)] [String[]] $ComputerName @@ -447,14 +448,14 @@ each digit must be a number zero to nine. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidatePattern("[0-9][0-9][0-9][0-9]")] [String[]] $ComputerName ) ``` -In the following example, the value of the variable $number must be a +In the following example, the value of the variable `$number` must be a four-digit number, and each digit must be a number zero to nine. ```powershell @@ -470,14 +471,14 @@ between zero and ten. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateRange(0,10)] [Int] $Attempts ) ``` -In the following example, the value of the variable $number must be between +In the following example, the value of the variable `$number` must be between zero and ten. ```powershell @@ -500,7 +501,7 @@ greater than or equal to the current date. ```powershell Param( - [parameter()] + [Parameter(Mandatory=$true)] [ValidateScript({$_ -ge (Get-Date)})] [DateTime] $EventDate @@ -523,7 +524,7 @@ not match a value in the set. In the following example, the value of the ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateSet("Low", "Average", "High")] [String[]] $Detail @@ -535,7 +536,7 @@ In the following example, the value of the variable `$flavor` must be either ```powershell [ValidateSet("Chocolate", "Strawberry", "Vanilla")] -[String]$flavor = Strawberry +[String]$flavor = "Strawberry" ``` Note that the validation occurs whenever that variable is assigned even within @@ -543,7 +544,7 @@ the script. For example, the following results in an error at runtime: ```powershell Param( - [ValidateSet("hello","world")] + [ValidateSet("hello", "world")] [String]$Message ) @@ -556,18 +557,18 @@ The `ValidateNotNull` attribute specifies that the parameter value cannot be `$null`. PowerShell generates an error if the parameter value is `$null`. The `ValidateNotNull` attribute is designed to be used when the type of the -parameter value is not specified or when the specified type will accept a -value of `$null`. (If you specify a type that will not accept a `$null` value, -such as a string, the `$null` value will be rejected without the +parameter value is not specified or when the specified type accepts a +value of `$null`. (If you specify a type that does not accept a `$null` value, +such as a string, the `$null` value is rejected without the `ValidateNotNull` attribute, because it does not match the specified type.) In the following example, the value of the `ID` parameter cannot be `$null`. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateNotNull()] - # $ID + $ID ) ``` @@ -580,7 +581,7 @@ an empty string `""`, or an empty array `@()`. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]] $UserName @@ -687,7 +688,7 @@ Param([Switch]) ```powershell Param( - [parameter(Mandatory=$false)] + [Parameter(Mandatory=$false)] [Switch] $ ) @@ -710,6 +711,94 @@ that the parameter name communicates the effect of the parameter to the user, and avoid ambiguous terms, such as Filter or Maximum, that might imply that a value is required. +## ArgumentCompleter attribute + +The **ArgumentCompleter** attribute allows you to add tab completion values +to a specific parameter. Like DynamicParameters, the available values are +calculated at runtime when the user presses `` after the parameter name. + +To add an **ArgumentCompleter** attribute, you need to define a script block +that will determine the values. The script block must take the following +parameters in the order specified below. The parameter's names +do not matter as the values are provided *positionally*. + +The syntax is as follows: + +```powershell +Param( + [Parameter(Mandatory)] + [ArgumentCompleter({ + param ($commandName, $wordToComplete, $commandAst, $fakeBoundParameter) + # Perform calculation of tab completed values here. + })] +) +``` + +### The 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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](about_Automatic_Variables.md). + +The **ArgumentCompleter** script block must unroll the values using the +pipeline (`ForEach-Object`, `Where-Object`, etc.), 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 no +`$Type` is specified, fruits and vegetables are returned. If a `$Type` is +specified, only values for the type are specified. In addition the `-like` +operator ensures that if the user types +`Test-ArgumentCompleter -Type Fruits -Value A`, only **Apple** is +returned. + +```powershell +function Test-ArgumentCompleter { +[CmdletBinding()] + param ( + [Parameter(Mandatory)] + [ValidateSet('Fruits', 'Vegetables')] + $Type, + [Parameter(Mandatory)] + [ArgumentCompleter( { + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + + $possibleValues = @{ + Fruits = @('Apple', 'Orange', 'Banana') + Vegetables = @('Tomato', 'Squash', 'Corn') + } + if ($fakeBoundParameters.ContainsKey('Type')) + { + $possibleValues[$fakeBoundParameters.Type] | Where-Object { + $_ -like "$wordToComplete*" + } + } + else + { + $possibleValues.Values | ForEach-Object {$_} + } + } )] + $Value + ) +} +``` + ## See also [about_Functions](about_Functions.md) diff --git a/reference/5.0/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md b/reference/5.0/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md index c9e269738877..77b1123f58c5 100644 --- a/reference/5.0/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md +++ b/reference/5.0/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md @@ -1,5 +1,5 @@ --- -ms.date: 5/15/2019 +ms.date: 5/20/2019 schema: 2.0.0 locale: en-us keywords: powershell,cmdlet @@ -29,43 +29,118 @@ Register-ArgumentCompleter -CommandName -ScriptBlock [- ## DESCRIPTION -The **Register-ArgumentCompleter** cmdlet registers a custom argument completer. +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. ## EXAMPLES ### Example 1: Register a custom argument completer -``` -PS C:\> Register-ArgumentCompleter -Native -CommandName powershell -ScriptBlock { - param($wordToComplete, $commandAst, $cursorPosition) - - echo -- -PSConsoleFile -Version -NoLogo -NoExit -Sta -NoProfile -NonInteractive ` - -InputFormat -OutputFormat -WindowStyle -EncodedCommand -File -ExecutionPolicy ` - -Command | - Where-Object { $_ -like "$wordToComplete*" } | - Sort-Object | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) - } +The following example registers an argument completer for the **Id** parameter of the `Set-TimeZone` +cmdlet. + +```powershell +$scriptBlock = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + (Get-TimeZone -ListAvailable).Id | Where-Object { + $_ -like "$wordToComplete*" + } | ForEach-Object { + "'$_'" + } } -PS C:\> Register-ArgumentCompleter -CommandName Get-Command -ParameterName Verb -ScriptBlock { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) +Register-ArgumentCompleter -CommandName Set-TimeZone -ParameterName Id -ScriptBlock $scriptBlock +``` - Get-Verb "$wordToComplete*" | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.Verb, $_.Verb, 'ParameterValue', ("Group: " + $_.Group)) - } +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the available values for **Id** are retrieved using the +`Get-TimeZone` cmdlet. The **Id** property for each Time Zone is piped to the `Where-Object` cmdlet. +The `Where-Object` cmdlet filters out any ids that do not start with the value provided by +`$wordToComplete`, which represents the text the user typed before they pressed ``. The +filtered ids are piped to the `For-EachObject` cmdlet which encloses each value in quotes, should +the value contain spaces. + +The second command registers the argument completer by passing the scriptblock, the +**ParameterName** "Id" and the **CommandName** `Set-TimeZone`. + +### Example 2: Add details to your tab completion values + +The following example overwrites tab completion for the **Name** parameter of the `Stop-Service` +cmdlet and only returns running services. + +```powershell +$s = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + $services = Get-Service | Where-Object {$_.Status -eq "Running" } + $services | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object { + New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_, + $_, + "ParameterValue", + $_ + } } +Register-ArgumentCompleter -CommandName dotnet -Native -ScriptBlock $s ``` +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the first command retrieves all running services using the `Where-Object` +cmdlet. The services are piped to the `ForEach-Object` cmdlet. The `ForEach-Object` cmdlet creates +a new +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) object +and populates it with the values of the current service (represented by the pipeline variable `$_`). + +The **CompletionResult** object allows you to provide additional details to each returned value: + +- **completionText** (String) - The text to be used as the auto completion result. This is the value + sent to the command. +- **listItemText** (String) - The text to be displayed in a list, such as when the user presses + `+`. This is used for display only and is not passed to the command when selected. +- **resultType** ([CompletionResultType](/dotnet/api/system.management.automation.completionresulttype)) - The type of completion result. +- **toolTip** (String) - The text for the tooltip with details to be displayed about the object. + This is visible when the user selects an item after pressing `+`. + +The last command demonstrates that stopped services can still be passed in manually to the +`Stop-Service` cmdlet. The tab completion is the only aspect affected. + +### Example 3: Register a custom Native argument completer + +You can use the **Native** parameter to provide tab-completion for a native command. The following +example adds tab-completion for the `dotnet` Command Line Interface (CLI). + +> [!NOTE] +> The `dotnet complete` command is only available in version 2.0 and greater of the dotnet cli. + +```powershell +$scriptblock = { + param($commandName, $wordToComplete, $cursorPosition) + dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + } +Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock +``` + +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. +Within the script block, the `dotnet complete` command is used to perform the tab completion. +The results are piped to the `ForEach-Object` cmdlet which use the **new** static method of the +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) class +to create a new **CompletionResult** object for each value. ## PARAMETERS ### -CommandName -Specifies the name of the command as an array. -If the command line uses an alias, this value is the actual command, not the alias. +Specifies the name of the commands as an array. ```yaml Accept pipeline input: False @@ -80,7 +155,8 @@ Type: String[] ### -Native -Indicates that custom argument handlers are dispatched based on the command name. +Indicates that the argument completer is for a native command where PowerShell cannot complete +parameter names. ```yaml Type: SwitchParameter @@ -96,8 +172,10 @@ Accept wildcard characters: False ### -ParameterName -Specifies the name of the parameter whose argument is being completed. -If the command line uses a parameter alias, this value is the actual parameter, not the alias. +Specifies the name of the parameter whose argument is being completed. The parameter name specified +cannot be an enumerated value, such as the **ForegroundColor** parameter of the `Write-Host` cmdlet. + +For more information on enums, see [about_Enum](./About/about_Enum.md). ```yaml Type: String @@ -113,9 +191,42 @@ Accept wildcard characters: False ### -ScriptBlock -Specifies the commands to run. -Enclose the commands in braces ( { } ) to create a script block. -This parameter is required. +Specifies the commands to run to perform tab completion. The script block you provide should return +the values complete the input. The script block must unroll the values using the pipeline +(`ForEach-Object`, `Where-Object`, etc.), or another suitable method. Returning an array of values +causes PowerShell to treat the entire array as **one** tab completion value. + +The script block should also accept the following parameters in the order specified below. The names +of the parameters are not important because PowerShell passes in the values *positionally*. + +- `$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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](./About/about_Automatic_Variables.md). + +When you specify the **Native** parameter, the script block should take the following parameters in +the specified order. The names of the parameters are not important because PowerShell +passes in the values *positionally*. + +- `$commandName` (Position 0) - This parameter is set to the name of the + command for which the script block is providing tab completion. +- `$wordToComplete` (Position 1) - This parameter is set to value the user has + provided before they pressed ``. Your script block should use this value + to determine tab completion values. +- `$cursorPosition` (Position 2) - This parameter is set to the position of the cursor when the + user pressed ``. + +You can also provide an **ArgumentCompleter** as a parameter attribute. For more information, see +[about_Functions_Advanced_Parameters](./About/about_Functions_Advanced_Parameters.md). ```yaml Type: ScriptBlock @@ -133,8 +244,7 @@ Accept wildcard characters: False This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, --WarningAction, and -WarningVariable. For more information, see about_CommonParameters -(http://go.microsoft.com/fwlink/?LinkID=113216). +-WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](./About/about_CommonParameters.md). ## INPUTS diff --git a/reference/5.1/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md b/reference/5.1/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md index acbdc70a1ae1..a09d0a802102 100644 --- a/reference/5.1/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md +++ b/reference/5.1/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md @@ -1,5 +1,5 @@ --- -ms.date: 11/28/2017 +ms.date: 5/20/2019 schema: 2.0.0 locale: en-us keywords: powershell,cmdlet @@ -42,7 +42,7 @@ has the following characteristics: ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [String[]] $ComputerName @@ -80,7 +80,7 @@ must follow "`Parameter`" with no intervening space. ```powershell Param( - [parameter(Argument=value)] + [Parameter(Argument=value)] $ParameterName ) ``` @@ -90,7 +90,7 @@ syntax to declare two arguments of the `Parameter` attribute. ```powershell Param( - [parameter(Argument1=value1, + [Parameter(Argument1=value1, Argument2=value2)] ) ``` @@ -101,7 +101,7 @@ name are still required. ```powershell Param( - [parameter()] + [Parameter()] $ParameterName ) ``` @@ -116,7 +116,7 @@ The following example declares the `ComputerName` parameter. It uses the ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [String[]] $ComputerName ) @@ -158,7 +158,7 @@ value in the command. ```powershell Param( - [parameter(Position=0)] + [Parameter(Position=0)] [String[]] $ComputerName ) @@ -185,17 +185,17 @@ parameter set, a `UserName` parameter in the "User" parameter set, and a ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="Computer")] [String[]] $ComputerName, - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="User")] [String[]] $UserName, - [parameter(Mandatory=$false)] + [Parameter(Mandatory=$false)] [Switch] $Summary ) @@ -212,18 +212,18 @@ parameter set and **Optional** in the other. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="Computer")] [String[]] $ComputerName, - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ParameterSetName="User")] [String[]] $UserName, - [parameter(Mandatory=$false, ParameterSetName="Computer")] - [parameter(Mandatory=$true, ParameterSetName="User")] + [Parameter(Mandatory=$false, ParameterSetName="Computer")] + [Parameter(Mandatory=$true, ParameterSetName="User")] [Switch] $Summary ) @@ -243,7 +243,7 @@ and accepts an object that is passed to the function from the pipeline. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [String[]] $ComputerName @@ -266,7 +266,7 @@ passed to the function through the pipeline. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [String[]] $ComputerName @@ -297,7 +297,7 @@ function. ```powershell Param( - [parameter(Mandatory=$true, + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] [String[]] $ComputerName @@ -316,7 +316,7 @@ help message that explains the expected parameter value. ```powershell Param( - [parameter(mandatory=$true, + [Parameter(mandatory=$true, HelpMessage="Enter one or more computer names separated by commas.")] [String[]] $ComputerName @@ -333,8 +333,8 @@ The following example shows a parameter declaration that adds the "CN" and ```powershell Param( - [parameter(Mandatory=$true)] - [alias("CN","MachineName")] + [Parameter(Mandatory=$true)] + [Alias("CN","MachineName")] [String[]] $ComputerName ) @@ -356,7 +356,7 @@ a Null value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowNull()] [String] $ComputerName @@ -371,7 +371,7 @@ parameter that can have an empty string value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowEmptyString()] [String] $ComputerName @@ -386,7 +386,7 @@ parameter that can have a empty collection value. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [AllowEmptyCollection()] [String[]] $ComputerName @@ -405,7 +405,7 @@ takes one to five parameter values. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateCount(1,5)] [String[]] $ComputerName @@ -423,7 +423,7 @@ In the following example, each computer name must have one to ten characters. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateLength(1,10)] [String[]] $ComputerName @@ -448,14 +448,14 @@ each digit must be a number zero to nine. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidatePattern("[0-9][0-9][0-9][0-9]")] [String[]] $ComputerName ) ``` -In the following example, the value of the variable $number must be a +In the following example, the value of the variable `$number` must be a four-digit number, and each digit must be a number zero to nine. ```powershell @@ -471,14 +471,14 @@ between zero and ten. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateRange(0,10)] [Int] $Attempts ) ``` -In the following example, the value of the variable $number must be between +In the following example, the value of the variable `$number` must be between zero and ten. ```powershell @@ -501,7 +501,7 @@ greater than or equal to the current date. ```powershell Param( - [parameter()] + [Parameter(Mandatory=$true)] [ValidateScript({$_ -ge (Get-Date)})] [DateTime] $EventDate @@ -524,7 +524,7 @@ not match a value in the set. In the following example, the value of the ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateSet("Low", "Average", "High")] [String[]] $Detail @@ -536,7 +536,7 @@ In the following example, the value of the variable `$flavor` must be either ```powershell [ValidateSet("Chocolate", "Strawberry", "Vanilla")] -[String]$flavor = Strawberry +[String]$flavor = "Strawberry" ``` Note that the validation occurs whenever that variable is assigned even within @@ -544,7 +544,7 @@ the script. For example, the following results in an error at runtime: ```powershell Param( - [ValidateSet("hello","world")] + [ValidateSet("hello", "world")] [String]$Message ) @@ -557,18 +557,18 @@ The `ValidateNotNull` attribute specifies that the parameter value cannot be `$null`. PowerShell generates an error if the parameter value is `$null`. The `ValidateNotNull` attribute is designed to be used when the type of the -parameter value is not specified or when the specified type will accept a -value of `$null`. (If you specify a type that will not accept a `$null` value, -such as a string, the `$null` value will be rejected without the +parameter value is not specified or when the specified type accepts a +value of `$null`. (If you specify a type that does not accept a `$null` value, +such as a string, the `$null` value is rejected without the `ValidateNotNull` attribute, because it does not match the specified type.) In the following example, the value of the `ID` parameter cannot be `$null`. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateNotNull()] - # $ID + $ID ) ``` @@ -581,7 +581,7 @@ an empty string `""`, or an empty array `@()`. ```powershell Param( - [parameter(Mandatory=$true)] + [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]] $UserName @@ -599,8 +599,8 @@ If you use relative path, the current drive must be in the allowed drive list. ```powershell Param( - [ValidateDrive("C","D","Variable","Function")] - [string]$Path + [ValidateDrive("C", "D", "Variable", "Function")] + [String]$Path ) ``` @@ -616,11 +616,10 @@ If you use relative path, the current drive must be `User`. You can define `User` drive in Just Enough Administration (JEA) session configurations. - ```powershell Param( [ValidateUserDrive()] - [string]$Path + [String]$Path ) ``` @@ -724,7 +723,7 @@ Param([Switch]) ```powershell Param( - [parameter(Mandatory=$false)] + [Parameter(Mandatory=$false)] [Switch] $ ) @@ -747,6 +746,94 @@ that the parameter name communicates the effect of the parameter to the user, and avoid ambiguous terms, such as Filter or Maximum, that might imply that a value is required. +## ArgumentCompleter attribute + +The **ArgumentCompleter** attribute allows you to add tab completion values +to a specific parameter. Like DynamicParameters, the available values are +calculated at runtime when the user presses `` after the parameter name. + +To add an **ArgumentCompleter** attribute, you need to define a script block +that will determine the values. The script block must take the following +parameters in the order specified below. The parameter's names +do not matter as the values are provided *positionally*. + +The syntax is as follows: + +```powershell +Param( + [Parameter(Mandatory)] + [ArgumentCompleter({ + param ($commandName, $wordToComplete, $commandAst, $fakeBoundParameter) + # Perform calculation of tab completed values here. + })] +) +``` + +### The 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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](about_Automatic_Variables.md). + +The **ArgumentCompleter** script block must unroll the values using the +pipeline (`ForEach-Object`, `Where-Object`, etc.), 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 no +`$Type` is specified, fruits and vegetables are returned. If a `$Type` is +specified, only values for the type are specified. In addition the `-like` +operator ensures that if the user types +`Test-ArgumentCompleter -Type Fruits -Value A`, only **Apple** is +returned. + +```powershell +function Test-ArgumentCompleter { +[CmdletBinding()] + param ( + [Parameter(Mandatory)] + [ValidateSet('Fruits', 'Vegetables')] + $Type, + [Parameter(Mandatory)] + [ArgumentCompleter( { + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + + $possibleValues = @{ + Fruits = @('Apple', 'Orange', 'Banana') + Vegetables = @('Tomato', 'Squash', 'Corn') + } + if ($fakeBoundParameters.ContainsKey('Type')) + { + $possibleValues[$fakeBoundParameters.Type] | Where-Object { + $_ -like "$wordToComplete*" + } + } + else + { + $possibleValues.Values | ForEach-Object {$_} + } + } )] + $Value + ) +} +``` + ## See also [about_Functions](about_Functions.md) diff --git a/reference/5.1/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md b/reference/5.1/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md index fa6b623d352e..d59a7ce7843b 100644 --- a/reference/5.1/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md +++ b/reference/5.1/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md @@ -3,7 +3,7 @@ external help file: System.Management.Automation.dll-Help.xml keywords: powershell,cmdlet locale: en-us Module Name: Microsoft.PowerShell.Core -ms.date: 5/15/2019 +ms.date: 5/20/2019 online version: http://go.microsoft.com/fwlink/?LinkId=821507 schema: 2.0.0 title: Register-ArgumentCompleter @@ -30,42 +30,118 @@ Register-ArgumentCompleter [-CommandName ] -ParameterName -Sc ## DESCRIPTION -The **Register-ArgumentCompleter** cmdlet registers a custom argument completer. +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. ## EXAMPLES ### Example 1: Register a custom argument completer -``` -PS C:\> Register-ArgumentCompleter -Native -CommandName powershell -ScriptBlock { - param($wordToComplete, $commandAst, $cursorPosition) - - echo -- -PSConsoleFile -Version -NoLogo -NoExit -Sta -NoProfile -NonInteractive ` - -InputFormat -OutputFormat -WindowStyle -EncodedCommand -File -ExecutionPolicy ` - -Command | - Where-Object { $_ -like "$wordToComplete*" } | - Sort-Object | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) - } +The following example registers an argument completer for the **Id** parameter of the `Set-TimeZone` +cmdlet. + +```powershell +$scriptBlock = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + (Get-TimeZone -ListAvailable).Id | Where-Object { + $_ -like "$wordToComplete*" + } | ForEach-Object { + "'$_'" + } } -PS C:\> Register-ArgumentCompleter -CommandName Get-Command -ParameterName Verb -ScriptBlock { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) +Register-ArgumentCompleter -CommandName Set-TimeZone -ParameterName Id -ScriptBlock $scriptBlock +``` - Get-Verb "$wordToComplete*" | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.Verb, $_.Verb, 'ParameterValue', ("Group: " + $_.Group)) - } +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the available values for **Id** are retrieved using the +`Get-TimeZone` cmdlet. The **Id** property for each Time Zone is piped to the `Where-Object` cmdlet. +The `Where-Object` cmdlet filters out any ids that do not start with the value provided by +`$wordToComplete`, which represents the text the user typed before they pressed ``. The +filtered ids are piped to the `For-EachObject` cmdlet which encloses each value in quotes, should +the value contain spaces. + +The second command registers the argument completer by passing the scriptblock, the +**ParameterName** "Id" and the **CommandName** `Set-TimeZone`. + +### Example 2: Add details to your tab completion values + +The following example overwrites tab completion for the **Name** parameter of the `Stop-Service` +cmdlet and only returns running services. + +```powershell +$s = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + $services = Get-Service | Where-Object {$_.Status -eq "Running" } + $services | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object { + New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_, + $_, + "ParameterValue", + $_ + } } +Register-ArgumentCompleter -CommandName dotnet -Native -ScriptBlock $s ``` -This example registers a custom argument completer. +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the first command retrieves all running services using the `Where-Object` +cmdlet. The services are piped to the `ForEach-Object` cmdlet. The `ForEach-Object` cmdlet creates +a new +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) object +and populates it with the values of the current service (represented by the pipeline variable `$_`). + +The **CompletionResult** object allows you to provide additional details to each returned value: + +- **completionText** (String) - The text to be used as the auto completion result. This is the value + sent to the command. +- **listItemText** (String) - The text to be displayed in a list, such as when the user presses + `+`. This is used for display only and is not passed to the command when selected. +- **resultType** ([CompletionResultType](/dotnet/api/system.management.automation.completionresulttype)) - The type of completion result. +- **toolTip** (String) - The text for the tooltip with details to be displayed about the object. + This is visible when the user selects an item after pressing `+`. + +The last command demonstrates that stopped services can still be passed in manually to the +`Stop-Service` cmdlet. The tab completion is the only aspect affected. + +### Example 3: Register a custom Native argument completer + +You can use the **Native** parameter to provide tab-completion for a native command. The following +example adds tab-completion for the `dotnet` Command Line Interface (CLI). + +> [!NOTE] +> The `dotnet complete` command is only available in version 2.0 and greater of the dotnet cli. + +```powershell +$scriptblock = { + param($commandName, $wordToComplete, $cursorPosition) + dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + } +Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock +``` + +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the `dotnet complete` command is used to perform the tab completion. +The results are piped to the `ForEach-Object` cmdlet which use the **new** static method of the +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) class +to create a new **CompletionResult** object for each value. ## PARAMETERS ### -CommandName -Specifies the name of the command as an array. +Specifies the name of the commands as an array. ```yaml Accept pipeline input: False @@ -80,8 +156,8 @@ Type: String[] ### -Native -Indicates that the argument completer is for a native command where Windows PowerShell cannot -complete parameter names. +Indicates that the argument completer is for a native command where PowerShell cannot complete +parameter names. ```yaml Type: SwitchParameter @@ -97,7 +173,10 @@ Accept wildcard characters: False ### -ParameterName -Specifies the name of the parameter whose argument is being completed. +Specifies the name of the parameter whose argument is being completed. The parameter name specified +cannot be an enumerated value, such as the **ForegroundColor** parameter of the `Write-Host` cmdlet. + +For more information on enums, see [about_Enum](./About/about_Enum.md). ```yaml Type: String @@ -113,9 +192,42 @@ Accept wildcard characters: False ### -ScriptBlock -Specifies the commands to run. -Enclose the commands in braces ( { } ) to create a script block. -This parameter is required. +Specifies the commands to run to perform tab completion. The script block you provide should return +the values complete the input. The script block must unroll the values using the pipeline +(`ForEach-Object`, `Where-Object`, etc.), or another suitable method. Returning an array of values +causes PowerShell to treat the entire array as **one** tab completion value. + +The script block should also accept the following parameters in the order specified below. The names +of the parameters are not important because PowerShell passes in the values *positionally*. + +- `$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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](./About/about_Automatic_Variables.md). + +When you specify the **Native** parameter, the script block should take the following parameters in +the specified order. The names of the parameters are not important because PowerShell +passes in the values *positionally*. + +- `$commandName` (Position 0) - This parameter is set to the name of the + command for which the script block is providing tab completion. +- `$wordToComplete` (Position 1) - This parameter is set to value the user has + provided before they pressed ``. Your script block should use this value + to determine tab completion values. +- `$cursorPosition` (Position 2) - This parameter is set to the position of the cursor when the + user pressed ``. + +You can also provide an **ArgumentCompleter** as a parameter attribute. For more information, see +[about_Functions_Advanced_Parameters](./About/about_Functions_Advanced_Parameters.md). ```yaml Type: ScriptBlock @@ -133,8 +245,7 @@ Accept wildcard characters: False This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, --WarningAction, and -WarningVariable. For more information, see about_CommonParameters -(http://go.microsoft.com/fwlink/?LinkID=113216). +-WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](./About/about_CommonParameters.md). ## INPUTS diff --git a/reference/6/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md b/reference/6/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md index 3cd571c01df3..1b4c55d11e9e 100644 --- a/reference/6/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md +++ b/reference/6/Microsoft.PowerShell.Core/About/about_Functions_Advanced_Parameters.md @@ -1,5 +1,5 @@ --- -ms.date: 11/28/2017 +ms.date: 5/20/2019 schema: 2.0.0 locale: en-us keywords: powershell,cmdlet @@ -8,6 +8,7 @@ title: about_Functions_Advanced_Parameters # About Functions Advanced Parameters ## Short description + Explains how to add parameters to advanced functions. ## Long description @@ -41,8 +42,8 @@ has the following characteristics: ```powershell Param( - [Parameter(Mandatory = $true, - ValueFromPipeline = $true)] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true)] [String[]] $ComputerName ) @@ -79,7 +80,7 @@ must follow "`Parameter`" with no intervening space. ```powershell Param( - [Parameter(Argument = value)] + [Parameter(Argument=value)] $ParameterName ) ``` @@ -89,8 +90,8 @@ syntax to declare two arguments of the `Parameter` attribute. ```powershell Param( - [Parameter(Argument1 = value1, - Argument2 = value2)] + [Parameter(Argument1=value1, + Argument2=value2)] ) ``` @@ -115,7 +116,7 @@ The following example declares the `ComputerName` parameter. It uses the ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [String[]] $ComputerName ) @@ -157,7 +158,7 @@ value in the command. ```powershell Param( - [Parameter(Position = 0)] + [Parameter(Position=0)] [String[]] $ComputerName ) @@ -184,17 +185,17 @@ parameter set, a `UserName` parameter in the "User" parameter set, and a ```powershell Param( - [Parameter(Mandatory = $true, - ParameterSetName = "Computer")] + [Parameter(Mandatory=$true, + ParameterSetName="Computer")] [String[]] $ComputerName, - [Parameter(Mandatory = $true, - ParameterSetName = "User")] + [Parameter(Mandatory=$true, + ParameterSetName="User")] [String[]] $UserName, - [Parameter(Mandatory = $false)] + [Parameter(Mandatory=$false)] [Switch] $Summary ) @@ -211,18 +212,18 @@ parameter set and **Optional** in the other. ```powershell Param( - [Parameter(Mandatory = $true, - ParameterSetName = "Computer")] + [Parameter(Mandatory=$true, + ParameterSetName="Computer")] [String[]] $ComputerName, - [Parameter(Mandatory = $true, - ParameterSetName = "User")] + [Parameter(Mandatory=$true, + ParameterSetName="User")] [String[]] $UserName, - [Parameter(Mandatory = $false, ParameterSetName = "Computer")] - [Parameter(Mandatory = $true, ParameterSetName = "User")] + [Parameter(Mandatory=$false, ParameterSetName="Computer")] + [Parameter(Mandatory=$true, ParameterSetName="User")] [Switch] $Summary ) @@ -242,8 +243,8 @@ and accepts an object that is passed to the function from the pipeline. ```powershell Param( - [Parameter(Mandatory = $true, - ValueFromPipeline = $true)] + [Parameter(Mandatory=$true, + ValueFromPipeline=$true)] [String[]] $ComputerName ) @@ -265,8 +266,8 @@ passed to the function through the pipeline. ```powershell Param( - [Parameter(Mandatory = $true, - ValueFromPipelineByPropertyName = $true)] + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true)] [String[]] $ComputerName ) @@ -296,8 +297,8 @@ function. ```powershell Param( - [Parameter(Mandatory = $true, - ValueFromRemainingArguments = $true)] + [Parameter(Mandatory=$true, + ValueFromRemainingArguments=$true)] [String[]] $ComputerName ) @@ -315,8 +316,8 @@ help message that explains the expected parameter value. ```powershell Param( - [Parameter(Mandatory = $true, - HelpMessage = "Enter one or more computer names separated by commas.")] + [Parameter(mandatory=$true, + HelpMessage="Enter one or more computer names separated by commas.")] [String[]] $ComputerName ) @@ -332,8 +333,8 @@ The following example shows a parameter declaration that adds the "CN" and ```powershell Param( - [Parameter(Mandatory = $true)] - [Alias("CN", "MachineName")] + [Parameter(Mandatory=$true)] + [Alias("CN","MachineName")] [String[]] $ComputerName ) @@ -355,7 +356,7 @@ a Null value. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [AllowNull()] [String] $ComputerName @@ -370,7 +371,7 @@ parameter that can have an empty string value. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [AllowEmptyString()] [String] $ComputerName @@ -385,7 +386,7 @@ parameter that can have a empty collection value. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [AllowEmptyCollection()] [String[]] $ComputerName @@ -404,7 +405,7 @@ takes one to five parameter values. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateCount(1,5)] [String[]] $ComputerName @@ -422,7 +423,7 @@ In the following example, each computer name must have one to ten characters. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateLength(1,10)] [String[]] $ComputerName @@ -447,7 +448,7 @@ each digit must be a number zero to nine. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidatePattern("[0-9][0-9][0-9][0-9]")] [String[]] $ComputerName @@ -479,7 +480,7 @@ In the following example, the value of the ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateRange(0,10)] [Int] $Attempts @@ -516,7 +517,7 @@ greater than or equal to the current date. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateScript({$_ -ge (Get-Date)})] [DateTime] $EventDate @@ -539,7 +540,7 @@ not match a value in the set. In the following example, the value of the ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateSet("Low", "Average", "High")] [String[]] $Detail @@ -613,7 +614,7 @@ In the following example, the value of the `ID` parameter cannot be `$null`. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateNotNull()] $ID ) @@ -628,7 +629,7 @@ an empty string `""`, or an empty array `@()`. ```powershell Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]] $UserName @@ -770,7 +771,7 @@ Param([Switch]) ```powershell Param( - [Parameter(Mandatory = $false)] + [Parameter(Mandatory=$false)] [Switch] $ ) @@ -793,6 +794,94 @@ that the parameter name communicates the effect of the parameter to the user, and avoid ambiguous terms, such as Filter or Maximum, that might imply that a value is required. +## ArgumentCompleter attribute + +The **ArgumentCompleter** attribute allows you to add tab completion values +to a specific parameter. Like DynamicParameters, the available values are +calculated at runtime when the user presses `` after the parameter name. + +To add an **ArgumentCompleter** attribute, you need to define a script block +that will determine the values. The script block must take the following +parameters in the order specified below. The parameter's names +do not matter as the values are provided *positionally*. + +The syntax is as follows: + +```powershell +Param( + [Parameter(Mandatory)] + [ArgumentCompleter({ + param ($commandName, $wordToComplete, $commandAst, $fakeBoundParameter) + # Perform calculation of tab completed values here. + })] +) +``` + +### The 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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](about_Automatic_Variables.md). + +The **ArgumentCompleter** script block must unroll the values using the +pipeline (`ForEach-Object`, `Where-Object`, etc.), 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 no +`$Type` is specified, fruits and vegetables are returned. If a `$Type` is +specified, only values for the type are specified. In addition the `-like` +operator ensures that if the user types +`Test-ArgumentCompleter -Type Fruits -Value A`, only **Apple** is +returned. + +```powershell +function Test-ArgumentCompleter { +[CmdletBinding()] + param ( + [Parameter(Mandatory)] + [ValidateSet('Fruits', 'Vegetables')] + $Type, + [Parameter(Mandatory)] + [ArgumentCompleter( { + param ( $commandName, + $parameterName, + $wordToComplete, + $commandAst, + $fakeBoundParameters ) + + $possibleValues = @{ + Fruits = @('Apple', 'Orange', 'Banana') + Vegetables = @('Tomato', 'Squash', 'Corn') + } + if ($fakeBoundParameters.ContainsKey('Type')) + { + $possibleValues[$fakeBoundParameters.Type] | Where-Object { + $_ -like "$wordToComplete*" + } + } + else + { + $possibleValues.Values | ForEach-Object {$_} + } + } )] + $Value + ) +} +``` + ## See also [about_Functions](about_Functions.md) @@ -803,4 +892,4 @@ value is required. [about_Functions_CmdletBindingAttribute](about_Functions_CmdletBindingAttribute.md) -[about_Functions_OutputTypeAttribute](about_Functions_OutputTypeAttribute.md) +[about_Functions_OutputTypeAttribute](about_Functions_OutputTypeAttribute.md) \ No newline at end of file diff --git a/reference/6/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md b/reference/6/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md index 98e88f64f399..d59a7ce7843b 100644 --- a/reference/6/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md +++ b/reference/6/Microsoft.PowerShell.Core/Register-ArgumentCompleter.md @@ -3,7 +3,7 @@ external help file: System.Management.Automation.dll-Help.xml keywords: powershell,cmdlet locale: en-us Module Name: Microsoft.PowerShell.Core -ms.date: 5/15/2019 +ms.date: 5/20/2019 online version: http://go.microsoft.com/fwlink/?LinkId=821507 schema: 2.0.0 title: Register-ArgumentCompleter @@ -30,42 +30,118 @@ Register-ArgumentCompleter [-CommandName ] -ParameterName -Sc ## DESCRIPTION -The **Register-ArgumentCompleter** cmdlet registers a custom argument completer. +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. ## EXAMPLES ### Example 1: Register a custom argument completer -``` -PS C:\> Register-ArgumentCompleter -Native -CommandName powershell -ScriptBlock { - param($wordToComplete, $commandAst, $cursorPosition) - - echo -- -PSConsoleFile -Version -NoLogo -NoExit -Sta -NoProfile -NonInteractive ` - -InputFormat -OutputFormat -WindowStyle -EncodedCommand -File -ExecutionPolicy ` - -Command | - Where-Object { $_ -like "$wordToComplete*" } | - Sort-Object | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) - } +The following example registers an argument completer for the **Id** parameter of the `Set-TimeZone` +cmdlet. + +```powershell +$scriptBlock = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + (Get-TimeZone -ListAvailable).Id | Where-Object { + $_ -like "$wordToComplete*" + } | ForEach-Object { + "'$_'" + } } -PS C:\> Register-ArgumentCompleter -CommandName Get-Command -ParameterName Verb -ScriptBlock { - param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) +Register-ArgumentCompleter -CommandName Set-TimeZone -ParameterName Id -ScriptBlock $scriptBlock +``` - Get-Verb "$wordToComplete*" | - ForEach-Object { - [System.Management.Automation.CompletionResult]::new($_.Verb, $_.Verb, 'ParameterValue', ("Group: " + $_.Group)) - } +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the available values for **Id** are retrieved using the +`Get-TimeZone` cmdlet. The **Id** property for each Time Zone is piped to the `Where-Object` cmdlet. +The `Where-Object` cmdlet filters out any ids that do not start with the value provided by +`$wordToComplete`, which represents the text the user typed before they pressed ``. The +filtered ids are piped to the `For-EachObject` cmdlet which encloses each value in quotes, should +the value contain spaces. + +The second command registers the argument completer by passing the scriptblock, the +**ParameterName** "Id" and the **CommandName** `Set-TimeZone`. + +### Example 2: Add details to your tab completion values + +The following example overwrites tab completion for the **Name** parameter of the `Stop-Service` +cmdlet and only returns running services. + +```powershell +$s = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + $services = Get-Service | Where-Object {$_.Status -eq "Running" } + $services | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object { + New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_, + $_, + "ParameterValue", + $_ + } } +Register-ArgumentCompleter -CommandName dotnet -Native -ScriptBlock $s ``` -This example registers a custom argument completer. +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the first command retrieves all running services using the `Where-Object` +cmdlet. The services are piped to the `ForEach-Object` cmdlet. The `ForEach-Object` cmdlet creates +a new +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) object +and populates it with the values of the current service (represented by the pipeline variable `$_`). + +The **CompletionResult** object allows you to provide additional details to each returned value: + +- **completionText** (String) - The text to be used as the auto completion result. This is the value + sent to the command. +- **listItemText** (String) - The text to be displayed in a list, such as when the user presses + `+`. This is used for display only and is not passed to the command when selected. +- **resultType** ([CompletionResultType](/dotnet/api/system.management.automation.completionresulttype)) - The type of completion result. +- **toolTip** (String) - The text for the tooltip with details to be displayed about the object. + This is visible when the user selects an item after pressing `+`. + +The last command demonstrates that stopped services can still be passed in manually to the +`Stop-Service` cmdlet. The tab completion is the only aspect affected. + +### Example 3: Register a custom Native argument completer + +You can use the **Native** parameter to provide tab-completion for a native command. The following +example adds tab-completion for the `dotnet` Command Line Interface (CLI). + +> [!NOTE] +> The `dotnet complete` command is only available in version 2.0 and greater of the dotnet cli. + +```powershell +$scriptblock = { + param($commandName, $wordToComplete, $cursorPosition) + dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + } +Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock +``` + +The first command creates a script block which takes the required parameters which are passed +in when the user presses ``. For more information, see the **ScriptBlock** parameter +description. + +Within the script block, the `dotnet complete` command is used to perform the tab completion. +The results are piped to the `ForEach-Object` cmdlet which use the **new** static method of the +[`[System.Management.Automation.CompletionResult]`](/dotnet/api/system.management.automation.completionresult) class +to create a new **CompletionResult** object for each value. ## PARAMETERS ### -CommandName -Specifies the name of the command as an array. +Specifies the name of the commands as an array. ```yaml Accept pipeline input: False @@ -74,7 +150,7 @@ Accept wildcard characters: False Parameter Sets: NativeSet, PowerShellSet Required: True (NativeSet), False (PowerShellSet) Default value: None -Aliases: +Aliases: Type: String[] ``` @@ -97,7 +173,10 @@ Accept wildcard characters: False ### -ParameterName -Specifies the name of the parameter whose argument is being completed. +Specifies the name of the parameter whose argument is being completed. The parameter name specified +cannot be an enumerated value, such as the **ForegroundColor** parameter of the `Write-Host` cmdlet. + +For more information on enums, see [about_Enum](./About/about_Enum.md). ```yaml Type: String @@ -113,9 +192,42 @@ Accept wildcard characters: False ### -ScriptBlock -Specifies the commands to run. -Enclose the commands in braces ( { } ) to create a script block. -This parameter is required. +Specifies the commands to run to perform tab completion. The script block you provide should return +the values complete the input. The script block must unroll the values using the pipeline +(`ForEach-Object`, `Where-Object`, etc.), or another suitable method. Returning an array of values +causes PowerShell to treat the entire array as **one** tab completion value. + +The script block should also accept the following parameters in the order specified below. The names +of the parameters are not important because PowerShell passes in the values *positionally*. + +- `$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 ``. 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 + [Ast Class](/dotnet/api/system.management.automation.language.ast). +- `$fakeBoundParameter` (Position 4) - This parameter is set to a hashtable + containing the `$PSBoundParameters` for the cmdlet, before the user pressed + ``. For more information, see [about_Automatic_Variables](./About/about_Automatic_Variables.md). + +When you specify the **Native** parameter, the script block should take the following parameters in +the specified order. The names of the parameters are not important because PowerShell +passes in the values *positionally*. + +- `$commandName` (Position 0) - This parameter is set to the name of the + command for which the script block is providing tab completion. +- `$wordToComplete` (Position 1) - This parameter is set to value the user has + provided before they pressed ``. Your script block should use this value + to determine tab completion values. +- `$cursorPosition` (Position 2) - This parameter is set to the position of the cursor when the + user pressed ``. + +You can also provide an **ArgumentCompleter** as a parameter attribute. For more information, see +[about_Functions_Advanced_Parameters](./About/about_Functions_Advanced_Parameters.md). ```yaml Type: ScriptBlock @@ -133,8 +245,7 @@ Accept wildcard characters: False This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, --WarningAction, and -WarningVariable. For more information, see about_CommonParameters -(http://go.microsoft.com/fwlink/?LinkID=113216). +-WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](./About/about_CommonParameters.md). ## INPUTS @@ -150,4 +261,4 @@ This cmdlet returns no output. ## NOTES -## RELATED LINKS \ No newline at end of file +## RELATED LINKS