Reputation: 31672
If param One is set to bbb then I want to make param Two mandatory. Is it possible to do this with parameter sets somehow or will I just have to add this logic to the script itself?
Example idea of what I need:
param (
[Parameter(Mandatory, ParameterSetName = 'default')]
[ValidateSet(“aaa”, ”bbb”, ”ccc”, "ddd")]
[String]
$One,
[Parameter(ParameterSetName = 'default')]
[ValidateScript( { $One -eq 'bbb'; THEN MAKE THIS PARAM MANDATORY! })]
[String]
$Two
)
The value of $One seems to not be set yet as I tried doing this and one.txt is empty
[ValidateScript( { $One > One.txt; $true })]
While there is DynamicParam{} that looks like its only if you have begin,process,end, etc setup. This is a simple function that I don't want to add that to it. Also DynamicParam seems to require a bizarre amount of boilerplate code to work
It looks like DynamicParam is the only way, but I think it crazy. It's weird and not readable, but I'd still prefer Powershell to handle validation for me.
Doing it myself though is still pretty simple:
if ($One -eq 'bbb' -and -not $Two) {
ThrowError Param Two required when One set to $One
}
Upvotes: 4
Views: 1293
Reputation: 440337
Use the default value for parameter -Two
to enforce the desired logic, via an if
statement that uses Throw
:
param (
[Parameter(Mandatory, ParameterSetName = 'default')]
[ValidateSet('aaa', 'bbb', 'ccc', 'ddd')]
[String]
$One,
[Parameter(ParameterSetName = 'default')]
[String]
$Two = $(if ($One -eq 'bbb') { Throw "-Two must be passed if -One equals 'bbb'." })
)
"-One: $One; -Two: $Two"
Note: Emulating a (conditionally) mandatory parameter with Throw
means that the behavior differs from a regular Mandatory
parameter in that the latter prompts when a value isn't given.
A solution based on validation attributes would be preferable, but validation attributes aren't designed for cross-parameter validation, and no particular order of their evaluation is guaranteed.
The above solution relies on the fact that default values are evaluated after explicitly passed arguments have been bound.
The much more verbose alternative is to use a dynamic parameter, as shown in Wasif Hasan's answer, relies on the same timing, though it does have the advantage of exhibiting normal prompt-for-a-missing-mandatory-value behavior.
As of this writing, Wasif's answer doesn't work as posted, so here's a working solution; note how the use of DynamicParam
syntactically requires (at least one of) the begin
, process
and end
blocks.
# Syntax requires PSv5+:
using namespace System.Management.Automation
param(
[Parameter(Mandatory, ParameterSetName='default')]
[ValidateSet('aaa', 'bbb', 'ccc', 'ddd')]
[String]$One
)
# Define parameter -Two *dynamically*, so that its Mandatory property
# can be based on the specific value of the already-bound static -One parameter.
DynamicParam {
# Create a the dictionary of dynamic parameters.
$dict = [RuntimeDefinedParameterDictionary]::new()
# Define and add the -Two parameter
$paramName = 'Two'
$dict.Add(
$paramName,
[RuntimeDefinedParameter]::new(
$paramName,
[string],
[ParameterAttribute] @{
ParameterSetName = 'default'
# *Conditionally* make the parameter mandatory, depending on the value
# of the already-bound static -One parameter.
Mandatory = $One -eq 'bbb'
}
)
)
# Return the dictionary
return $dict
}
begin {
# NOTE: Dynamic parameter values do not become local variables the way
# they do for static parameters; the value must be accessed via the
# automatic $PSBoundParameters dictionary.
$Two = $PSBoundParameters['Two']
"-One: $One; -Two: $Two"
}
Upvotes: 5
Reputation: 15518
You are looking for dynamic parameters: Conditional PowerShell parameters
param(
[String]$One
)
DynamicParam {
# Create a parameter dictionary
$runtimeParams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
# Populate it with parameters, with optional attributes
$attribs = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$mandatoryAttrib = New-Object System.Management.Automation.ParameterAttribute
$mandatoryAttrib.Mandatory = ($one -eq "bbb")
$attribs.Add($mandatoryAttrib)
$param = New-Object System.Management.Automation.RuntimeDefinedParameter('Two', String, $attribs)
}
Begin {
# If desired, move dynamic parameter values to variables
$ParameterName = $PSBoundParameters['Two']
}
# Do like regular
Without process block it will work.
Upvotes: 0