Re-Thinking Positional Parameters

I mentioned in a previous post that I’ve recently changed my mind a bit about the Position parameter attribute. I guess technically it is the position parameter of the Parameter parameter attribute (i.e. there’s a parameter attribute called “Parameter” and it has a parameter called position). I don’t think you could come up with something much more difficult to correctly name.

Anyway, I’ve always had a low opinion of this particular parameter. Before I explain why, let’s review how it works.

If you have an advanced function, say Get-Stuff, you might see something like this:

Function Get-Stuff{
[CmdletBinding()]
Param([Parameter(Position=0)]$param1,
      [Parameter(Position=1)]$param2,
      [Parameter(Position=2)]$param3)
    
    #body of function
    write-output @{Param1=$param1;Param2=$param2;Param3=$param3}
}

The point of the Position= parameter (of the Parameter parameter attribute in the Param statement) is to say that if you use positional parameters in calling the function, you can expect that $param1 is in the first position (position 0), $param2 is in the second position (position 1) and so on.

The great part about it is that this code works the same without the Position= statements. Parameters (ignoring parameter sets) can be used in the order they’re listed in the function unless the PositionalBinding parameter of the CmdletBinding attribute is set to $false (which it isn’t, by default).

I’ve seen a lot of code which, in a function that has 12 parameters, mechanically sets Position= from 0 to 11 in order. It’s not exactly confusing, but it’s certainly not clear why you would bother doing it since it’s not necessary. From that observation, I decided that there was no point to using the Position= setting at all.

Micah Battin spoke a few months ago at the STLPSUG meeting on PowerShell Functions and got me to reconsider my position (no pun intended).

I explained my reservations and he said something to the effect that you should turn off automatic positional arguments (PositionalBinding=$false in the CmdletBinding()) and then set the position for the first one or two parameters. Those are the ones that people will be specifying postionally anyway.

Have you ever seen someone call a cmdlet and list 12 parameters with no names? I would guess not. There’s no reason to expect that people will want to write useless code like that, so why should your function definition encourage it?  By only including positions for the one or two “essential parameters” you’re doing your part to make the caller’s code better.

I’m going to be editing my “Advanced Function” snippet to include PositionalBinding=$False and see where it takes me.

What do you think?

–Mike