What is CmdletBinding in PowerShell?

Image Description

Daily PowerShell #51

Daily PowerShell Basics

December 5, 2021

quote Discuss this Article

In this post, we’ll look at how to create advanced functions with the CmdletBinding attribute.

What is the CmdletBinding Attribute?

The CmdletBinding attribute is used to convert standard PowerShell functions into advanced functions that behave similar to compiled C# cmdlets. Some differences between standard functions include:

How do you use the CmdletBinding Attribute?

To use the CmdletBinding attribute, you need to define a function and place the attribute before the param block. You can optionally define parameters with the Parameter attribute to adjust how parameters behave.

function Switch-String {
   [CmdletBinding()]
   param([string]$String)

   $Array = $String.ToCharArray()
   [Array]::Reverse($Array)
   [string]::new($Array)
}

Confirm Impact

Advanced functions support the use of built-in parameters like -Confirm. If you define ConfirmImpact, you can call ShouldProcess to make the user confirm that action. The ConfirmImpact property should be set to the level at which the $ConfirmPreference should prompt for confirmation. You will also need to set SupportsShouldProcess in order to use ConfirmImpact. Resetting the Universe is set to high.

function Reset-Universe {
  [CmdletBInding(ConfirmImpact = 'High', SupportsShouldProcess)]
  param()

  if ($PSCmdlet.ShouldProcess("Universe"))
  {
     Write-Host "Universe reset!"
  }
}

The resulting operation looks like this.

PS > Reset-Universe

Confirm
Are you sure you want to perform this action?
Performing the operation "Reset-Universe" on target "Universe".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
Universe reset!

Default Parameter Set Name

You can use the CmdletBinding attribute to set the default parameter set name when multiple are defined. Sometimes it’s not possible to determine a parameter set name without the default parameter set.

function Select-DefaultParameterSet {
  [CmdletBinding(DefaultParameterSetName = "DefaultSet")]
  param(
    [Parameter(ParameterSetName = "DefaultSet")]
    $DefaultValue1 = "Default1",
    [Parameter(ParameterSetName = "NonDefaultSet")]
    $DefaultValue2 = "Default2"
  )

  if ($PSCmdlet.ParameterSetName -eq 'DefaultSet')
  {
    $DefaultValue1
  }
  else 
  {
    $DefaultValue2
  }
}

The result of executing this cmdlet is as follows.

PS > Select-DefaultParameterSet
Default1

Pipeline Input

Advanced functions support begin, process and end blocks. These blocks are used when processing pipeline input.

function Write-Pipeline {
   [CmdletBinding()]
   param(
     [Parameter(ValueFromPipeline)]
     [string]$String
   )

   Begin {
     Write-Host "Begin"
   }

   Process {
     Write-Host "Process: $String" 
   }

   End {
     Write-Host "End"
   }
}

The resulting output from the above function will be the following.

PS > "Hello", "World" | Write-Pipeline
Begin
Process: Hello
Process: World
End

We can update our Switch-String cmdlet to take pipeline by including the Parameter attribute and the Process block.

function Switch-String {
   [CmdletBinding()]
   param(
     [Parameter(ValueFromPipeline)]
     [string]$String
   )

   Process {
    $Array = $String.ToCharArray()
    [Array]::Reverse($Array)
    [string]::new($Array)
   }
}

The resulting behavior is that the Switch-String cmdlet can now take pipeline input.

PS > "Hello", "World" | Switch-String
olleH
dlroW

Positional Binding

With position binding defined, parameters can be used by position rather than by name.

function Write-Position {
  [CmdletBinding(PositionalBinding)]
  param(
    $Position1,
    $Position2
  )

  $Position1
  $Position2
}

You can then use the cmdlet without specifying the parameter names.

Write-Position 1 2

Support Paging

The pipeline in PowerShell supports paging parameters that are similar to data processing features of systems such as SQL. The parameters include:

function Get-Numbers {
    [CmdletBinding(SupportsPaging)]
    param()

    $FirstNumber = [Math]::Min($PSCmdlet.PagingParameters.Skip, 100)
    $LastNumber = [Math]::Min($PSCmdlet.PagingParameters.First +
      $FirstNumber - 1, 100)

    if ($PSCmdlet.PagingParameters.IncludeTotalCount) {
        $TotalCountAccuracy = 1.0
        $TotalCount = $PSCmdlet.PagingParameters.NewTotalCount(100,
          $TotalCountAccuracy)
        Write-Output $TotalCount
    }
    $FirstNumber .. $LastNumber | Write-Output
}

The result of executing the above cmdlet is the following:

PS > Get-Numbers -IncludeTotalCount -Skip 10 -First 10
Total count: 100
10
11
12
13
14
15
16
17
18
19