Working With New CmdletBinding Arguments HelpURI,SupportsPaging and PositionalBinding In PowerShell V3

With PowerShell V3 out (still in Beta), there are some new things with the CmdletBinding that includes the following items:

  1. HelpURI
  2. SupportsPaging
  3. PositionalBinding

Each of these has their own specific uses and I will dive into each one to show you an example for each of these and give a explanation. Still available are the other items such as SupportsShouldProcess, DefaultParameterSetName and ConfirmImpact, but I will not be going into these today.

HelpURI

The HelpURI basically allows you to specify a URI (Uniform resource identifier) that can be used to point to more help documentation about the cmdlet/function by using the following command:

Get-Help <function> –Online

Note that this is an internet address and will open up a web browser to go to the specified location. If you have Comment Based help added (and why wouldn’t you Smile ) and have the .Link specified with an URI for help, then it will take precedence to whatever is being used with the cmdletbinding HelpURI.

First lets look at using this new feature with just the HelpURI specified:

Function Get-Something {
    [CmdletBinding(
        HelpURI='http://google.com'
    )]
    Param (
        [parameter(ValueFromPipeLine=$True)]
        $Data
    )
    Begin{}
    Process{Write-Output $Data}
    End{}
}

Get-Help Get-Something -Online

By doing this, Google.com will open up in your web browser. Now lets add the .Link and a different URI and watch what happens.

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding(
        HelpURI='http://google.com'
    )]
    Param (
        [parameter(ValueFromPipeLine=$True)]
        $Data
    )
    Begin{}
    Process{Write-Output $Data}
    End{}
}

Get-Help Get-Something -Online

Now when you use the –Online switch, it opens up to my blog homepage instead of Google.com. Something good to know if you are specifying a help URI in both of these places and to know which one takes precedence over the other.

SupportsPaging

This new argument with cmdletbinding allows you to add the following parameters to manage the output of data or to display a total count:

  • -IncludeTotalCount
  • -Skip
  • -First

Each of these will not just work on its own just because you set the SupportsPaging to $True. Some extra work is required on your part to make it work as needed.

IncludeTotalCount

We can first test for the use of –IncludeTotalCount with $PSCmdlet.PagingParameters.IncludeTotalCount and then determine the type of accuracy that will be used for the TotalCount:

  1. 1.0
    1. Some data sources might have the exact number of results retrieved and in this case would have accuracy 1.0
  2. 0.0 – 1.0
    1. Some data sources might only have an estimate and in this case would use accuracy between 0.0 and 1.0
  3. 0.0
    1. Other data sources might not know how many items there are in total and in this case would use accuracy 0.0

Knowing that we now need to apply some data to the $PSCmdlet.PagingParameters.NewTotalCount(<totalcount>,<accuracy>) which will then print out the total count.

Let’s see this in action:

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding(
        SupportsPaging = $True
    )]
    Param (
        [parameter(Position=0)]
        $Data
    )
    Begin{}
    Process{

    }
    End{
        If ($PSCmdlet.PagingParameters.IncludeTotalCount){
            [double]$Accuracy = 1.0
            $PSCmdlet.PagingParameters.NewTotalCount($Data.count, $Accuracy)
        }
    }
}

Get-Something -Data (Get-ChildItem C:\Windows\System32) -IncludeTotalCount

image

Skip and First

For –Skip and –First, there is (yes, you guessed it!) more work that is required to actually make this work like we want it to.

When you specify –Skip, you set the value of $PSCmdlet.PagingParameters.Skip to the specified value. The same goes with –first and $PSCmdlet.PagingParameters.First.

After that there is math involved to make sure that we get the accurate numbers for the first set of data all of the way to the last set of data. I make use of the [Math]::Min() method to make sure that we only get the data that we need and to not go over, especially in the case of the .First which is set to 18446744073709551615 by default. I also have to make sure that if the –Skip goes beyond the total count of items, that nothing is returned by the command.

The function I will be using is here:

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding(
        SupportsPaging = $True
    )]
    Param (
        $Data
    )
    Begin{}
    Process{

    }
    End {
        If($Data.count -gt 0) {
            If($PSCmdlet.PagingParameters.Skip -ge $Data.count) {
                Write-Verbose "No results satisfy the Skip parameters"
            } Elseif($PSCmdlet.PagingParameters.First -eq 0) {
                Write-Verbose "No results satisfy the First parameters"
            } Else {
            $First = $PSCmdlet.PagingParameters.Skip
            Write-Verbose ("First: {0}" -f $First)
            $Last = $First + 
                [Math]::Min($PSCmdlet.PagingParameters.First, $Data.Count - $PSCmdlet.PagingParameters.Skip) - 1    
            }
            If ($Last -le 0) {
                $Data = $Null
            } Else {
                $Data = $Data[$First..$last]
                Write-Output $Data            
            }
            Write-Verbose ("Last: {0}" -f $Last)
        }
        If ($PSCmdlet.PagingParameters.IncludeTotalCount){
            [double]$Accuracy = 1.0
            $PSCmdlet.PagingParameters.NewTotalCount($Data.count, $Accuracy)
        }
    }
}

Lets start by finding the first 10 items in C:\Windows\System32:

Get-Something -Data (Get-ChildItem C:\Windows\System32) -First 10

image

We already know from earlier that there are 2783 items under this folder, so lets skip all of the way to the last 10 by skipping 2773 items.

Get-Something -Data (Get-ChildItem C:\Windows\System32) -Skip 2773

image

We can actually combine all 3 to really narrow down the data:

Get-Something -Data (Get-ChildItem C:\Windows\System32) `
-First 15 -Skip 50 -IncludeTotalCount

 

image

Pretty cool stuff, isn’t it? We are able to combine all three to look at the first 15 items after skipping the initial 50 and then see the total count of items as validation of actually looking for the first 15.

PositionalBinding

This argument of cmdletbinding is actually set to $True by default meaning you don’t have to use it if you are planning on allowing positional parameters. If for some reason, you do not want to allow positional parameters, then you can set it to $False. Also note that this setting can be overwritten if you specify parameter positions using the [parameter(Position=n)] argument.

First lets see it by default:

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding( )]
    Param (
        [parameter()]
        $Data,
        [parameter()]
        $Data1,
        [parameter()]
        $Data2,
        [parameter()]
        $Data3
    )
    Begin{}
    Process{
        Write-Output ("Data: {0}" -f $Data)
        Write-Output ("Data1: {0}" -f $Data1)
        Write-Output ("Data2: {0}" -f $Data2)
        Write-Output ("Data3: {0}" -f $Data3)
    }
    End{}
}

Get-Something 1 2 3 4

image

As you can see, it works like a champ and processes each parameter without having to name it. But now lets set the PositionalBinding to $False and watch what happens:

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding(
        PositionalBinding = $False
    )]
    Param (
        [parameter()]
        $Data,
        [parameter()]
        $Data1,
        [parameter()]
        $Data2,
        [parameter()]
        $Data3
    )
    Begin{}
    Process{
        Write-Output ("Data: {0}" -f $Data)
        Write-Output ("Data1: {0}" -f $Data1)
        Write-Output ("Data2: {0}" -f $Data2)
        Write-Output ("Data3: {0}" -f $Data3)
    }
    End{}
}

Get-Something 1 2 3 4

image

Here you can see that we can no longer use positional parameters with the function, only ‘Named parameters’ can be used with the positionalbinding disabled. As I mentioned earlier, even if you have the argument set to $False, you can still have positional binding if you set each parameter argument to have a position as seen below:

Function Get-Something {
    <#
        .LINK
            http://Learn-PowerShell.net
    #>
    [CmdletBinding(
        PositionalBinding = $False
    )]
    Param (
        [parameter(Position=0)]
        $Data,
        [parameter(Position=1)]
        $Data1,
        [parameter(Position=2)]
        $Data2,
        [parameter(Position=3)]
        $Data3
    )
    Begin{}
    Process{
        Write-Output ("Data: {0}" -f $Data)
        Write-Output ("Data1: {0}" -f $Data1)
        Write-Output ("Data2: {0}" -f $Data2)
        Write-Output ("Data3: {0}" -f $Data3)
    }
    End{}
}

Get-Something 1 2 3 4

image

In Conclusion

So with that, we have now looked at the new features in the CmdletBinding() attribute that is with PowerShell V3 and shown how they can be put to use. While the HelpURI and the PositionalBinding can be over-ruled in other areas, it is still nice to see that they can be configured anyways in a different location.

Please remember that with this being a Beta still, things can and possibly will change by the time the final product is release later this year. But by all means hop onto the V3 train and try out all of the cool new things that come along with it.

Enjoy!

This entry was posted in powershell, scripts, V3 and tagged , , , , , . Bookmark the permalink.

1 Response to Working With New CmdletBinding Arguments HelpURI,SupportsPaging and PositionalBinding In PowerShell V3

  1. Fang Zhou says:

    About_Function_Advanced* topics are actually not well-organized so that people can easily understand these concepts. Even worse there are too few (acutally none) examples in the areas described here. Very nice to see this article which sorts out these advanced concepts in details. Very helpful. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s