The CmdletBinding and the Parameter attribute turn a simple function into an advanced function, thereby adding features that are common in cmdlets. However, the question is whether you really need advanced functions in your PowerShell scripts.
Latest posts by Michael Pietroforte (see all)

Advanced functions were originally called script cmdlets because they allow you to script commands that behave essentially like compiled cmdlets. Their leaner counterparts are called simple, standard, or normal functions.

Cmdlets share a common set of features to make our work in an interactive environment consistent. For instance, cmdlets support common parameters such as -ErrorAction or -WhatIf, they prompt for confirmation if you are about to run a command with high impact, or they force you to pass mandatory parameters. These are all features that simple functions lack but that are available in advanced functions.

Two ways exist to create an advanced function: you can either add the CmdletBinding attribute or add the Parameter attribute. It is also possible to work with both attributes in the same function.

The purpose of the Parameter attribute is to specify certain features of the function’s parameters, such as making a parameter mandatory or defining its position in the command as is common in cmdlets.

You can use the CmdletBinding attribute to add basic cmdlet features, such as common parameters, to functions or to make certain methods available that allow you to change the behavior of the function. Let’s look at some examples.

The CmdletBinding attribute

The simplest advanced function I can think of looks like this:

Function Go-Advanced {
     [CmdletBinding()]Param()
}

Note that the Param keyword is required here even if you don’t define parameters in your function.

The easiest way to find out if a function is recognized as advanced is to check whether it supports common parameters. If you run the above function in PowerShell ISE and then type its name on the command prompt with a hyphen, as you see in the screenshot below, the PowerShell ISE auto completion feature presents you with a list of common parameters.

Creating an advanced function with the CmdletBinding attribute

Creating an advanced function with the CmdletBinding attribute

Aside from demonstrating how an advanced function can be built, this function has no other purpose. Let’s look at an example where you can actually use one of those common parameters that PowerShell automatically added to our function. In the example below, we use the Write-Verbose cmdlet, which allows you to display a message if a function is called with the common parameter -Verbose.

Function Go-Verbose {
     [CmdletBinding()]Param()
     Write-Verbose "Alright, you prefer talkative functions. First of all, I appreciate your wish to learn more about the common parameter -Verbose. Secondly, blah blah.."
     Write-Host "This is self-explanatory, anyway."
}

Using Write-Verbose

Using Write-Verbose

This is all very simple, and you could easily add this kind of functionality to your function by yourself. This applies to many features of advanced functions. However, the point is that it saves you time if you use the built-in features of advanced functions. Let’s try something that is a little bit more sophisticated.

The next function demonstrates the usage of the ShouldContinue method, which can be helpful if you want to work with confirmation requests. You can access this method through the automatic variable $PSCmdlet, which is only available in advanced functions. In addition, the CmdletBinding attribute has to set the SupportsShouldProcess parameter to $True.

Function Remove-ByForce {
     [cmdletbinding(SupportsShouldProcess)] 
     Param([string]$File)

     If ($PSCmdlet.ShouldContinue("Are you sure that you know what you are doing?","Delete with -Force parameter!")) {  
             Remove-Item $File -Force
     } Else {  
             "Mission aborted!"     
     } 
}
Remove-ByForce test -Confirm

Working with the ShouldContinue method

Working with the ShouldContinue method

As you can see in the screenshot, if you call the function with the -Confirm parameter, the ShouldContinue method produces a confirmation request. If the user clicks No, the message in the Else block will be displayed.

If you want the request to show up even without the use of the -Confirm parameter, you have to first set the $ConfirmPreference variable to “Low,” which makes PowerShell prompt for confirmation when running cmdlets with a low, medium, or high risk.

Function Remove-ByForce {
     [CmdletBinding(SupportsShouldProcess)] 
     Param([String]$File)

     $ConfirmPreference = "Low"
     If ($PSCmdlet.ShouldContinue("Are you sure that you know what you are doing?","Delete with -Force parameter!")) {  
             Remove-Item $File -Force
     } Else {  
             "Mission aborted!"
     }
}
Remove-ByForce test

Using the $ConfirmPreference variable

Using the $ConfirmPreference variable

Quite a few other methods exist that allow you to build your functions with many features that are typical for cmdlets.

The Parameter attribute

As mentioned above, instead of using the CmdletBinding attribute, you can create an advanced function with the Parameter attribute. Don’t confuse the Parameter attribute with the Param keyword. The latter is used to define parameters in simple and advanced functions, whereas the Parameter attribute is for limiting the values of parameters in advanced functions.

Function Go-Advanced {  
   Param(
         [Parameter()]
         $myParameter
         )
}

Creating an advanced function with the Parameter attribute

Creating an advanced function with the Parameter attribute

In the example, the parameter $myParameter is defined as we would do it in a standard function. We can then use this parameter to pass data to the function. The Parameter attribute doesn’t do anything else here other than telling the PowerShell engine that our function is supposed to have advanced features. In the next example, the Parameter attribute ensures that our parameter is mandatory.

Function Make-Mandatory {
  Param(
        [Parameter(Mandatory)]
        $myParameter
        )
}

Making a parameter mandatory

Making a parameter mandatory

If you call a function without passing a value for a mandatory parameter, PowerShell will prompt you to supply the value.

The function in the next example allows you to copy items recursively from a source to either one or two destinations depending on the parameters you specify. For each case, we create a parameter set—that is, a collection of parameters that can be used together in the command. The $Source parameter does not belong to a particular parameter set, which means it can be used with the parameters of both sets. We also set the Position argument for the $Source parameter, which means that you can omit the parameter name if the first argument you pass is the source path.

Function Copy-OneTwo {
    Param(
            [Parameter(Mandatory=$True,
                      Position=0)]
            [String]$Source,

            [Parameter(Mandatory=$True,
                      ParameterSetName="OneDestination")]
            [String]$Destination,

            [Parameter(Mandatory=$True,
                      ParameterSetName="TwoDestinations")]
            [String]$Destination1,
            
            [Parameter(Mandatory=$True,
                      ParameterSetName="TwoDestinations")]
            [String]$Destination2
         )

     switch ($PsCmdlet.ParameterSetName){
        "OneDestination"   { Copy-Item -Recurse $Source $Destination } 
        "TwoDestinations"  { Copy-Item -Recurse $Source $Destination1; Copy-Item $Source $Destination2 } 
     } 
}

To view the syntax of the function with its parameters set, you can use the Get-Help cmdlet. As you can see in the screenshot below, it displays the the syntax of each parameter set separately.

Creating a parameter set

Creating a parameter set

For more information about the available arguments of the Parameter attribute, please read Microsoft’s documentation.

Advanced vs. simple function

I only scratched the surface here of what you can do with advanced functions. Actually, describing everything there is to say about advanced functions is essentially describing PowerShell. After all, advanced functions are for making cmdlets in scripts, and PowerShell consists mostly of cmdlets.

Because advanced functions are so powerful, PowerShell geeks often recommend using them instead of simple functions. However, in my view, this doesn’t really make sense. Albert Einstein once said, “Everything should be made as simple as possible, but not simpler.” The quantifier “Everything” also applies to PowerShell. Because disproving Einstein has proved difficult, you should use simple functions when possible and use advanced functions only when you really need them. So, when do you need advanced functions? I already answered this question at the beginning of this post. You usually only need advanced functions when you create cmdlets that will be used in an interactive environment.

In a way, the term “advanced function” is a bit misleading. Because there is only one keyword for creating functions (Function), there is actually only one type of function. The CmdletBinding and Parameter attributes just change the behavior of functions. But this also applies to other keywords, such as Process or the validation attributes (which don’t need advanced functions). Thus, if you really need an advanced function feature—say, mandatory parameters—you can use the Parameter attribute. But ask yourself if you really need mandatory parameters in a non-interactive environment.

You should also be aware that advanced functions lack some features of standard functions. For example, you can’t use the automatic variable $Args that allows you to pass an unknown number of values to a function. Advanced functions are also less forgiving when you pass a named parameter that wasn’t defined in the function.

What’s your view? Advanced or simple?

avataravatar
3 Comments
  1. PowerMe! (Rank 3) 4 years ago

    Very nice explanation. I have started Advanced Functions and really love it (.. I used to be scared of them when I started PoweShell)!

    One of the things I like is the Pipeline parameter.

    Param(
      [Parameter(ValueFromPipeline)]
      $Variable
    )
    avatar
  2. Ramon Tan (Rank 2) 4 years ago

    Very educational and very well written Mr Pietroforte.  Many thanks.

    avataravatar
  3. ErikN 1 year ago

    I guess something has changed in PowerShell in the past three years, because despite following this guide to the letter it doesn’t work as described. Not sure why.

Leave a reply

Your email address will not be published.

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account