Skip to content

Latest commit

 

History

History
198 lines (123 loc) · 13.5 KB

parameter-best-practices.md

File metadata and controls

198 lines (123 loc) · 13.5 KB

Parameter Best Practices

Parameter Guidelines

Parameter Naming Conventions

The following are naming conventions to keep in mind when coming up with a name for your parameters.

In addition, a recommended list of parameter names can be found here.

Standard Parameter Name

From the Strongly Encouraged Development Guidelines:

Your cmdlet should use standard parameter names so that the user can quickly determine what a particular parameter means. If a more specific name is required, use a standard parameter name, and then specify a more specific name as an alias. For example, the Get-Service cmdlet has a parameter that has a generic name (Name) and a more specific alias (ServiceName). Both terms can be used to specify the parameter.

Pascal Case

Similar to cmdlets, parameters should follow pascal casing.From the Strongly Encouraged Development Guidelines:

Use Pascal case for parameter names. In other words, capitalize the first letter of each word in the parameter name, including the first letter of the name.

Acronyms

Do capitalize both characters of two-character acronyms. For example,-VMScaleSetName.

Do capitalize only the first character of acronyms with three or more characters, which aligned with Pascal case. For example, -Fqdn and -VmssName.

Singularity

From the Strongly Encouraged Development Guidelines:

Avoid using plural names for parameters whose value is a single element. This includes parameters that take arrays or lists because the user might supply an array or list with only one element.

Plural parameter names should be used only in those cases where the value of the parameter is always a multiple-element value. In these cases, the cmdlet should verify that multiple elements are supplied, and the cmdlet should display a warning to the user if multiple elements are not supplied.

Parameter Alias

If you there is a separate nomenclature for the parameter name, or if you would like to shorten the name of the parameter so it's easier to remember, you can add an alias attribute to your parameter to allow for this functionality.

Parameter Types

Valid Parameter Types

The type of parameters should always be defined; a parameter should never be of type object, PSObject, PSCustomObject or the like. Defining a parameter with any of these types can make it difficult for the user to know what value they should be providing to the parameter, as well as makes it difficult for the breaking change analyzer to detect any breaking changes made to the parameter since it has no knowledge about changes in the types' properties.

Consistent Parameter Types

From the Strongly Encouraged Development Guidelines:

When the same parameter is used by multiple cmdlets, always use the same parameter type. For example, if the Process parameter is an Int16 type for one cmdlet, do not make the Process parameter for another cmdlet a UInt16 type.

Array vs. Enumerable Types

For parameters that require a collection of elements to be provided, use an array instead of any other enumerable type to represent this collection.

From the Strongly Encouraged Development Guidelines:

Frequently, users must perform the same operation against multiple arguments. For these users, a cmdlet should accept an array as parameter input so that a user can pass the arguments into the parameter as a Windows PowerShell variable. For example, the Get-Process cmdlet uses an array for the strings that identify the names of the processes to retrieve.

Secret Parameters

For parameters whose type is string and which represent a value that should be kept secret in some fashion (such as a password, secret, key, etc.), the type of the parameter should be SecureString to limit the exposure of sensitive string data from unexpected leakage during cmdlet execution. The practice also applies to output properties whose type is string and that should be kept in secret.

Please notice that DO NOT use SecureString for encryption purposes. We only recommend to use SecureString as a wrapper of string to prevent unexpected leakage of information as string may still be exposed to any process or operation that has access to raw memory.

From How secure is SecureString?

SecureString is more secure than String because it limits the exposure of sensitive string data. However, those strings may still be exposed to any process or operation that has access to raw memory, such as a malicious process running on the host computer, a process dump, or a user-viewable swap file. Instead of using SecureString to protect passwords, the recommended alternative is to use an opaque handle to credentials that are stored outside of the process.

Bool vs. SwitchParameter

Parameters of type bool are strongly discouraged in PowerShell. The SwitchParameter type of a parameter acts a flag that signals whether or not some action should be taken based on if the parameter was provided or not.

The only case where a bool parameter should be used is for a PATCH operation wrapped by an Update-* cmdlet; in this case, the user will have the option to set the value to true or false, or not provide a value at all, which keeps the value the same on the server. For a PUT operation wrapped by a Set-* cmdlet, the normal SwitchParameter type should be used.

Argument Completers

PowerShell uses Argument Completers to provide tab completion for users. Azure PowerShell has multiple specific argument completers that should be applied to relevant parameters, as well as a generic argument completer that can be used to tab complete with a given list of values.

Resource Group Completer

For any parameter that takes a resource group name, the ResourceGroupCompleter should be applied as an attribute. This will allow the user to tab through all resource groups in the current subscription.

using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
...
[Parameter(Mandatory = false, HelpMessage = "The resource group name")]
[ResourceGroupCompleter]
public string ResourceGroupName { get; set; }

Resource Name Completer

For any parameter that takes a resource name, the ResourceNameCompleter should be applied as an attribute. This will allow the user to tab through all resource names for the ResourceType in the current subscription. This completer will filter based upon the current parent resources provided (for instance, if ResourceGroupName is provided, only the resources in that particular resource group will be returned). For this completer, please provide the ResourceType as the first argument, followed by the parameter name for all parent resources starting at the top level.

using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
...
[Parameter(Mandatory = false, HelpMessage = "The parent server name")]
[ResourceNameCompleter("Microsoft.Sql/servers", nameof(ResourceGroupName))]
public string ServerName { get; set; }

[Parameter(Mandatory = false, HelpMessage = "The database name")]
[ResourceNameCompleter("Microsoft.Sql/servers/databases", nameof(ResourceGroupName), nameof(ServerName))]
public string Name { get; set; }

Location Completer

For any parameter that takes a location, the LocationCompleter should be applied as an attribute. In order to use the LocationCompleter, you must input as an argument all of the Providers/ResourceTypes used by the cmdlet. The user will then be able to tab through locations that are valid for all of the Providers/ResourceTypes specified.

using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
...
[Parameter(Mandatory = false, HelpMessage = "The location of the resource")]
[LocationCompleter("Microsoft.Batch/operations")]
public string Location { get; set; }

Generic Argument Completer

For any parameter which you would like the user to tab through a list of suggested values (but you do not want to limit the users to only these values), the generic argument completer should be added.

using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
...
[Parameter(Mandatory = false, HelpMessage = "The tiers of the plan")]
[PSArgumentCompleter("Basic", "Premium", "Elite")]
public string Tier { get; set; }

Parameter Set Guidelines

Parameter Set Naming Conventions

The following are naming conventions to keep in mind when coming up with a name for your parameter set.

Pascal Case

Similar to parameters (mentioned above), parameter set names should follow pascal casing. From the Strongly Encouraged Development Guidelines:

Use Pascal case for cmdlet names. In other words, capitalize the first letter of the verb and all terms used in the noun. For example, "Clear-ItemProperty".

Attribute Guidelines

The following are guidelines that should be followed when working with the attributes of a parameter set.

Mutually Exclusive Parameter Sets

For PowerShell to determine which parameter set a user is intending to use with a set of provided parameters, the parameter sets need to be designed in such a way that they are mutually exclusive. From the remarks section of Parameter Attribute Declaration:

Each parameter set must have at least one unique parameter. Good cmdlet design indicates this unique parameter should also be mandatory if possible. If your cmdlet is designed to be run without parameters, the unique parameter cannot be mandatory.

Positional Parameters Limit

It is possible to call a PowerShell cmdlet without providing the parameter names, but just the values you would like to pass through. This is done by specifying the position at which the value of each parameter should be provided by using the Position property for a parameter. However, when there are too many positional parameters in a single parameter set, it can be difficult for the user to remember the exact ordering in which the parameter values should be provided. From the remarks section of Parameter Attribute Declaration:

When you specify positional parameters, limit the number of positional parameters in a parameter set to less than five. And, positional parameters do not have to be contiguous. Positions 5, 100, and 250 work the same as positions 0, 1, and 2.

In addition, there should be no two parameters with the same position in the same parameter set. From the remarks section of Parameter Attribute Declaration:

No parameter set should contain more than one positional parameter with the same position.

ValueFromPipeline Limit

Allowing the user to pipe an object from one cmdlet to another is a major scenario in PowerShell, but allowing multiple parameters in the same parameter set to accept their value from the pipeline can cause issues. From the remarks section of Parameter Attribute Declaration:

Only one parameter in a parameter set should declare ValueFromPipeline = true. Multiple parameters can define ValueFromPipelineByPropertyName = true.

Appendix: Parameter Syntax

In PowerShell documentation, square brackets ([]) indicate optional. Convention is as follows:

command-name
    -RequiredParameterName <RequiredParameterValue>
    [-OptionalParameterName <OptionalParameterValue>]
    [-OptionalSwitchParameters]
    [-OptionalParameterName] <RequiredParameterValue>

Using New-Alias cmdlet as an example:

New-Alias 
    [-Name] <string>                                                     -required 'positional' parameter
    [-Value] <string>                                                 
    [-Description <string>]                                              -optional parameter
    [-Force]                                                             -optional switch parameter (all switch parameters are optional, non-positional)
    [-Option {None | ReadOnly | Constant | Private | AllScope}]
    [-PassThru] 
    [-Scope <string>] 
    [-Confirm] 
    [-WhatIf] 
    [<CommonParameters>]