The Snazzy Secret of PowerShell Parameter Aliases

PowerShell functions are handy for making portable code that contain all of the requirements and workflow bits baked in, such as the parameters that can be passed over via the user or another script. There’s a lot of choice when it comes to designing the parameters: the type (string, int, switch), requirements (true, false), accepting pipeline inputs, and so forth.

One option that I hadn’t used much in the past was the [Alias()] declaration. It allows a parameter to be known by the name and one or more aliased names. For me, I find this handy in two primary use cases:

  1. Updating the name of a parameter without introducing a breaking change to older code.
  2. Using a Pascal Case “human friendly” name for parameters while building a relationship with other formatting cases used by computers.

In this post, I’ll cover the use of an alias and dive deeper into my two use cases.

PowerShell Aliases

Parameters can have one or more aliases assigned to them. The syntax is [Alias('value_1','value_2','value_n')] and should be placed in the Param section along with other parameter details. Here’s an example with one parameter named $Relic that has an alias of is_relic.

[CmdletBinding()]
  Param(
    # Filter results to include only relic (removed) databases
    [Alias('is_relic')]
    [Switch]$Relic
  )

The details of Get-Help on this particular function would only show the -Relic parameter option because the aliases are somewhat more hidden. If you want to see what aliases are available, you can get detailed help or use the Get-Command cmdlet to dive deeper.

Here’s an example against Rubrik’s Get-RubrikDatabase function using (Get-Command Get-RubrikDatabase).Parameters.Values to see which aliases are available for the $Relic parameter.

Name            : Relic
ParameterType   : System.Management.Automation.SwitchParameter
ParameterSets   : {[__AllParameterSets, System.Management.Automation.ParameterSetMetadata]}
IsDynamic       : False
Aliases         : {is_relic}
Attributes      : {__AllParameterSets, System.Management.Automation.AliasAttribute, System.Management.Automation.ArgumentTypeConverterAttribute}
SwitchParameter : True

That’s kinda cool, right? You could also filter it down further by using a where clause and selecting the Name and Aliases.

(Get-Command Get-RubrikDatabase).Parameters.Values | Where {$_.Name -eq 'Relic'} |  Select Name,Aliases
Name  Aliases
----  -------
Relic {is_relic}

Any further manipulation of the results are up to you.

Avoiding Breaking Changes

Projects have a way of changing direction which may impact the names of your parameters. If you’d like to make sure that code that depends on your function doesn’t immediately break by making a name change, use an alias to ensure backwards compatibility.

  1. Change the name of the parameter within the function. Make sure to find it everywhere that it is referenced to avoid keeping around legacy names!
  2. Use the [Alias(old_name)] declaration to allow any code calling the old name of the parameter to still function.

It’s important to note that PowerShell is not case sensitive when it comes to parameters. If you are only changing the case of your parameter, such as from Lower Camel Case to Pascal Case, you can do this without using an alias. If you try to use an alias that matches the parameter name, you’ll receive an error. Here’s an example of trying to load my Get-RubrikDatabase function when using the value relic as an alias for the parameter named Relic.

Get-RubrikDatabase : The parameter 'Relic' cannot be specified because it conflicts with the parameter alias of the same name for parameter 'Relic'.

Friendly Names

PowerShell parameters are typically made to be human friendly and expressed in Pascal Case. This is a bit like squishing together proper nouns to form a value that has no spaces or underscores. However, I often find that APIs and other external sources like to use their own case. In order to build a relationship between a human friendly Pascal Case parameter and the less friendly Snake Case or Camel Case values, I use an alias.

Let’s return to the relic example from above.

[CmdletBinding()]
  Param(
    # Filter results to include only relic (removed) databases
    [Alias('is_relic')]
    [Switch]$Relic
  )

The use of $Relic is a human friendly name while is_relic is the name of the key that the Rubrik API is expecting. The use of an alias lets other parts of my PowerShell code know that whenever it finds a value for the $Relic parameter – which is a [Switch] type – that it should use the results and pass them to the API under the name is_relic.

Here’s part of the verbose output displayed when calling the Get-RubrikDatabase function with the relic switch set to $true.

VERBOSE: URI = https://172.17.28.11/api/v1/mssql/db
VERBOSE: Build the query parameters
VERBOSE: URI = https://172.17.28.11/api/v1/mssql/db?is_relic=True

Notice how the is_relic=True query is appended to the URI string. This is because a private function (here) is being called to compare each parameter name and alias against a configuration file containing all of the API keys.

    # Walk through all of the parameters defined in the function
    # Both the parameter name and parameter alias are used to match against a query option
    # It is suggested to make the parameter name "human friendly" and set an alias corresponding to the query option name
    foreach ($param in $parameters)
    {
      # If the parameter name matches the query option name, build a query string
      if ($param.Name -eq $query)
      {
        $querystring += Test-QueryObject -object (Get-Variable -Name $param.Name).Value -location $resources.Query[$param.Name] -params $querystring
      }
      # If the parameter alias matches the query option name, build a query string
      elseif ($param.Aliases -eq $query)
      {
        $querystring += Test-QueryObject -object (Get-Variable -Name $param.Name).Value -location $resources.Query[$param.Aliases] -params $querystring
      }
    }

I find this to be an elegant solution that is rather simple to track without having to resort to a complex or exotic workaround. Plus, it keeps all of the parameters nice and easy for we humans to read while also allowing for pipeline input. In my humble opinion, making parameters that easily pass data through the pipeline is a cornerstone of healthy PowerShell function design, but is often missed when working with “automatic generators” of PowerShell functions.