Reputation: 339
Given this basic function-skeleton:
Function Set-FruitSupply {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$False)][ValidateSet('Apples','Pears','Oranges')][String]$City,
[Parameter(Mandatory=$False)][ValidateSet('Apples','Pears','Oranges')][String]$County,
[Parameter(Mandatory=$False)][ValidateSet('Apples','Pears','Oranges')][String]$State
)
Begin {}
Process {
Switch ($PSBoundParameters.Keys) {
'City' { Write-Output -InputObject "The city has $City" }
'County' { Write-Output -InputObject "The city has $County" }
'State' { Write-Output -InputObject "The city has $State" }
}
}
End {}
}
I don't like the idea of having to repeat myself, so I would like to replace those 3 ValidateSets with a placeholder so I only have to type Apples, Pears and Oranges once. A variable doesn't work as far as I know.
Since I'm using PwSh 7, I tried creating a class.
class Fruit : System.Management.Automation.IValidateSetValuesGenerator {
[System.String[]] GetValidValues() {
$Fruits = @('Apples', 'Pears', 'Oranges')
Return $Fruits
}
}
Placing that above the function in question and using ValidateSet([Fruit])
. This doesn't seem to work. I figured it ought to work with static data as well as dynamic data, maybe I'm just doing something wrong.
Does anybody know the correct way of doing this so I only have to write my set once?
Upvotes: 0
Views: 288
Reputation: 174475
I can't seem to reproduce your issue with IValidateSetValuesGenerator
, this works perfectly in 7.0 for me (I couldn't resist the temptation to make the parameters mutually exclusive), alternatives below:
class Fruit : System.Management.Automation.IValidateSetValuesGenerator {
[System.String[]] GetValidValues() {
$Fruits = @('Apples', 'Pears', 'Oranges')
Return $Fruits
}
}
Function Set-FruitSupply {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$False, ParameterSetName='City')]
[ValidateSet([Fruit])]
[String]$City,
[Parameter(Mandatory=$False, ParameterSetName='County')]
[ValidateSet([Fruit])]
[String]$County,
[Parameter(Mandatory=$False, ParameterSetName='State')]
[ValidateSet([Fruit])]
[String]$State
)
Begin {}
Process {
Switch ($PSCmdlet.ParameterSetName) {
'City' { Write-Output -InputObject "The city has $City" }
'County' { Write-Output -InputObject "The county has $County" }
'State' { Write-Output -InputObject "The state has $State" }
}
}
End {}
}
But if you can't get it to work (or you need a 5.1-compatible alternative), here are two options:
enum
enum Fruit {
Apples
Bananas
Pears
}
function Set-FruitSupply
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$False, ParameterSetName='City')]
[Fruit]$City,
[Parameter(Mandatory=$False, ParameterSetName='County')]
[Fruit]$County,
[Parameter(Mandatory=$False, ParameterSetName='State')]
[Fruit]$State
)
# ...
}
In this example we've avoided the duplicate list by validating against the defined Fruit
enum type instead
function Set-FruitSupply
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$False, ParameterSetName='City')]
[switch]$City,
[Parameter(Mandatory=$False, ParameterSetName='County')]
[switch]$County,
[Parameter(Mandatory=$False, ParameterSetName='State')]
[switch]$State,
[Parameter(Mandatory=$true, Position = 0, DontShow = $true)]
[ValidateSet('Apples','Pears','Oranges')]
[string]$Fruit
)
# use `$Fruit` in here regardless of paramset
}
In this case, -Fruit
itself won't autocomplete thanks to the DontShow
flag, but it's values will, given that no other positional parameter exists, allowing you to complete and pass values with the same syntax: ie. Set-FruitSupply -City Apples
.
Nice thing about this is that it works with version older than PowerShell 5 as well
Upvotes: 2