not using [parameter()] on some parameters in a PowerShell advanced function - powershell

If you are doing advanced functions and have the parameters decorated [parameter()], would there be any reason to NOT decorate a parameter with [Parameter()] . I've seen this a few times and don't know whether its just a case of laziness, oversight, or purposeful design.

Laziness I think but to be fair, it isn't needed if you aren't using any special parameter attibutes like Mandatory, Position, etc. As long is one parameter is marked [Parameter(...)] or the param block is marked [CmdletBinding(...)] PowerShell will interpret that function as an advanced function. OTOH there is no harm in adding the empty [Parameter()] to parameters.

Related

Is there some way to define a parameterless powershell parameter set?

I've got some fairly complex functions that I'm writing for a library module, with lots of different ways it can be called. However, it is in fact possible to default all of them, but when I try to call my function with no parameters the call fails because the parameter set cannot be determined.
I would like to define a parameter set that contains no parameters whatsoever, such that calls with no parameters succeed. This is difficult to do since ParameterSetName is a property of the Parameter attribute though, and it's not possible to attribute nothing.
I experimented with the DefaultParameterSet property of the CmdletBinding attribute that is placed on the param block, however nothing seemed to work. It seems that the parameter set name defined there must actually exist in order for Powershell to default to it.
Currently my best approximation of this use case is to define one of the parameter sets to have no Mandatory parameters, however these fail when empty strings or nulls are piped in, and I would like for this not to be the case.
Is this possible?
Sure is. Just specify a default parameter set name that isn't used otherwise:
function Foo {
[CmdletBinding(DefaultParameterSetName='x')]
Param(
[Parameter(Mandatory=$true, ParameterSetName='y')]$a,
[Parameter(Mandatory=$false, ParameterSetName='y')]$b,
[Parameter(Mandatory=$true, ParameterSetName='z')]$c,
[Parameter(Mandatory=$false)]$d
)
"`$a: $a"
"`$b: $b"
"`$c: $c"
"`$d: $d"
}

Multiple conditions on parameterset

In a function, I have 2 [String] parameters, $DBServer and $ServiceServer
Both should be allowed to be blank or filled, but nothing inbetween.
Is this possible to do with parametersets?
Or should I include a check in my PowerShell function which makes sure that my conditions are made?
Yes, you do this with Parameter Sets. So you'd have 2 sets. One in which both parameters are Mandatory, and one in which both parameters are absent.
function Ruin-Database {
[CmdletBinding(DefaultParameterSetName='Blank')]
param(
[Parameter(
ParameterSetName='Filled',
Mandatory=$true
)]
[ValidateNotNullOrEmpty()]
[String]
$DBServer ,
[Parameter(
ParameterSetName='Filled',
Mandatory=$true
)]
[ValidateNotNullOrEmpty()]
[String]
$ServiceServer
)
If ($PSCmdlet.ParameterSetName -eq 'Blank') {
Write-Verbose 'Blank' -Verbose
} else {
Write-Verbose 'Filled' -Verbose
}
}
Once you define the function this way, look at the help to see both parameter sets:
Get-Help Ruin-Database
Explanation
If a parameter specifies one or more parameter sets, then it will only be included in those sets. If it doesn't specify, it will be included in all sets.
PowerShell must be able to unambiguously resolve the set if you want it to work, so sometimes it takes some trial and error.
One thing you can do to help this is to specify a DefaultParameterSetName in the CmdletBinding attribute. But you can also specify a parameter set name there that you haven't used in any other parameter. That means the default set would only include parameters that don't specify any set (are available in all), even if there are none of those.
Running help on a function/cmdlet is a good way to see what sets PowerShell is interpreting, as it can get complex.
You can specify multiple [Parameter()] attributes on a single parameter to define different characteristics in different sets, for example, a parameter may be mandatory in one set, but optional in another. It may be specified via pipeline in one set, but not in another.

Are there technical benefits using "param(<params here))" inside a function over "function myfunc(<param here>)"?

Why are there two different formatting possible for parameters input? Are there any benefits other than personal taste to this?
For example, i'm using this because that's what I first seen reading documentation about Powershell
function MyAwesomeFunction
(
[parameter(Mandatory=$Whatever)]
[string]
$MyAwesomeVariable = MyAwesomeDefaultValue
)
{MyAwesome stuff to do}
But there's case when looking at user made examples where the parameters are made that way
function MyAwesomeFunction
{
param(
[parameter(Mandatory=$Whatever)]
[string]
$MyAwesomeVariable = MyAwesomeDefaultValue
)
MyAwesome stuff to do
}
If you're just writing a plain old function, PowerShell doesn't care which style you use; it should work just as well either way. However, a lot of people use Param() for consistency, as it is required in certain situations. Most notably, the CmdletBinding() attribute requires the use of Param() (even if your function doesn't have any parameters).

What is [cmdletbinding()] and how does it work?

According to get-help about_Functions_CmdletBindingAttribute
The CmdletBinding attribute is an attribute of functions that makes them operate like compiled cmdlets
We can use it on the top of our scripts. What is the function in this case? An internal implicit "main" function called by the PowerShell engine for all its inputs?
Regarding this syntax:
[CmdletBinding(ConfirmImpact=<String>,
DefaultParameterSetName=<String>,
HelpURI=<URI>,
SupportsPaging=<Boolean>,
SupportsShouldProcess=<Boolean>,
PositionalBinding=<Boolean>)]
What are we doing? Instantiating a cmdlbinding object and passing an argument list to its constructor? This syntax can be found in param() - for example: [Parameter(ValueFromPipeline=$true)]. Does this syntax have a particular name, and can it be found elsewhere?
Lastly, are we able, as simple PowerShellers, to mimic this functionality and modify the behavior of scripts by setting an attribute?
Generally speaking, CmdletBinding is what makes a function into an Advanced function. Putting it at the top of a script makes the script an "advanced" script. Functions and scripts are much the same, where the script file name is equivalent to the function name and the script content is equivalent to the scriptblock section of a function.
CmdletBinding attributes give you control over function capabilities, such as adding Confirm and WhatIf support (via SupportsShouldProcess), Disable parameters positional binding, and so on.
CmdletBinding, Parameter etc. are special attribute classes that scripters can use to define PowerShell's behavior, e.g. make a function an Advanced function with Cmdlet capabilites.
When you call them via e.g. [CmdletBinding()] you initialize a new instance of the class.
Read more about the CmdletBindingAttribute class at: MSDN
Read more about the ParameterAttribute class at: MSDN
More about Attribute classes here and here
Regarding the syntax question, the format closely matches how you apply a .NET attribute class to a member using named parameters in C#.
Compare the (simplified) grammar for attributes from section B.2.4 of The PowerShell Language Specification with that from section C.2.13 of the C# Language Specification:
B.2.4 Attributes (PowerShell)
attribute: [ attribute-name ( attribute-arguments ) ]
attribute-arguments: attribute-argument attribute-argument , attribute-arguments
attribute-argument: simple-name = expression
C.2.13 Attributes (C#)
attribute: [ attribute-name ( named-argument-list ) ]
named-argument-list: named-argument named-argument-list , named-argument
named-argument: identifier = attribute-argument-expression
I agree it might have been nice from a sense of conceptual brevity to e.g. re-use hashtable initialization syntax for attribute initialization. However, I can imagine supporting all the options from hashtables (like [A(P=v)] and [A('P'=v)] and $n = 'P'; [A($n=v)] and such, or some particular subset of them) just to use ; as the separator character would have been more trouble than it was worth.
On the other hand, if you want to use advanced functions, then maybe it makes sense to learn an advanced syntax :)

How to mark a switch parameter as mandatory in Powershell

I'm pretty sure I don't have any other options other than what I've uncovered, but I wanted to pick the collective internet brain.
I prefer to use a [switch] parameter when passing boolean values to custom functions. However, I have a few cases in which I wanted to mark the switch parameter as mandatory. This can optionally be accomplished through [parameter(Mandatory = $true)] on the parameter. However, I really dislike the UI prompt that shows up. I much prefer throwing an exception.
But, a switch can be either true or false, and the "IsPresent" property makes no distinction. If I pass a switch parameter as -example:$false, the switch reports that $example.IsPresent is false!
I have resorted to using a [bool]. For example:
param
(
[bool]$theValue = $(throw('You didn't specify the value!'))
);
Are there any other tricks I can pull?
In a way a switch parameter is always mandatory. If you don't specify it, it gets a value of false. If you specify it ( -var) it gets a value true and if you specify the value too (-var:$false) it gets the value specified.
I can't really think of a situation where it is mandatory to specify a switch. If you don't specify, it is false. Simple as that.
I think what you want is to specifically mention the value of the param to be true or false? If that is the case, the bool version that you mention is what I would go for, though it works the same way with switch too:
param([switch]$a = $(throw "You didn't specify the value"))
And also regarding $example.IsPresent - I know it is not intuitive /broken , but it is the same as the value of the switch variable itself. That is how the constructor for Switch Paramater is defined and the only property that it has is the IsPresent:
Creates a new SwitchParameter object that includes a Boolean value
that identifies whether the switch is present.
http://msdn.microsoft.com/en-us/library/system.management.automation.switchparameter.ctor%28v=vs.85%29.aspx