Mandatory only in a specific parameterset

Let’s say I have some params like this:

[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$Param1,
[Parameter(Mandatory)]
[string]$Param2,
[Parameter(ParameterSetName = 'Set1',
[switch]$Param3,
[Parameter(ParameterSetName = 'Set1',
Mandatory)]
[string]$Param4
)

I’m forced to set params $Param1 and $Param2 always which I understand. However, I want to make the $Param4 only mandatory if I’ve used the $Param3 switch param. Is this possible? I’m trying this and finding that if I use Mandatory on the $Param4 switch, it’s enforcing this all the time regardless of which params I choose. Am I going to have to go to dynamic params for this?

The main problem with your example is that you haven’t defined a default parameter set, and PowerShell sometimes get confused there. If you add DefaultParameterSetName = ‘AnyStringOtherThanSet1’ to your CmdletBinding attribute, it’ll work as you expect. Though there may not be any point in having a $Param3 switch, at that point; if you specify $Param4, you’re in the Set1 parameter set, and the switch isn’t really doing anything extra anyway.

Keep in mind, though, that you also wind up in Set1 if someone calls your command with -Param3:$false . If you need to modify Param4’s behavior based on the value of Param3, rather than on its presence, then you need to use dynamic parameters.

You can decorate the parameters like this

function test {

[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$Param1,

[Parameter(Mandatory)]
[string]$Param2,

[Parameter(ParameterSetName = 'Set1')]
[switch]$Param3,

[Parameter(ParameterSetName = 'Set1',Mandatory)]
[Parameter(ParameterSetName = 'Set2')]
[string]$Param4,

[Parameter(ParameterSetName = 'Set2')]
[string]$param5
)


}

£> test -Param1 xx -Param2 yy -Param3
cmdlet test at command pipeline position 1
Supply values for the following parameters:
Param4:

£> test -Param1 x -Param2 y -param5 z

Dave,

I did try to add a default parameter set with no parameters in it as well but the same behavior persisted. However, you do have a point where I didn’t even really need $Param3 at all. I removed it and by doing that negated my reason for using parameter sets in the first place so I’ve removed the parameter set as well and it’s now working as I need. Thanks!

Adam, see if this helps, this is the param set I ended up with when doing my inactive computer script. I’m not a fan of the massive param set, but when I got done with the whole ordeal it produced what I needed. What you’ll notice is I have things set in a default, but then also in the email param set.

Param
(
	# Machines older than this date will be included on the report
	[Parameter(Mandatory = $false, Position = 0, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[datetime] $ReportDate = (get-date).AddDays(-45),
	# Machines older than this date will be moved to the Holding OU
	[Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[datetime] $MoveDate = (get-date).AddDays(-60),
	# Machines older than this date will be disabled if within the proper Holding OU
	[Parameter(Mandatory = $false, Position = 2, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[datetime] $DisableDate = (get-date).AddDays(-60),
	# Machines older than this date, previously disabled, and in the Holding OU will be removed
	[Parameter(Mandatory = $false, Position = 3, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[datetime] $RemoveDate = (get-date).AddDays(-90),
	# Name of OU to place machines in to older than the MoveDate, will be found with Get-ADOrganizationUnit -Filter {name -eq $HoldingOU}
	[Parameter(Mandatory = $false, Position = 4, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[string] $HoldingOU = $null,
	# Text that will be used to exclude computers by name from the 'To be reviewed' portion of the report.
	[Parameter(Mandatory = $false, Position = 5, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[string[]] $IgnoreComputerName = '',
	# Text that will be used to exclude computers by description from the 'To be reviewed' portion of the report.
	[Parameter(Mandatory = $false, Position = 6, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[string[]] $IgnoreComputerDescription = '',
	# The output path of the HTML report document
	[Parameter(Mandatory = $false, Position = 7, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[string] $OutFilePath = $null,
	# If the report should be sent out as an email
	[Parameter(Mandatory = $false, Position = 8, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Email Param Set")]
	[switch] $SendEmail,
	# Used with $SendEmail, determines the SMTP server to use for relaying the email message
	[Parameter(Mandatory = $true, Position = 9, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Email Param Set")]
	[string] $SMTPServer,
	# Sets the EMail Subject line
	[Parameter(Mandatory = $false, Position = 10, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Email Param Set")]
	[string] $EmailSubject = "Inactive Computer Report",
	# List of Email Recpients in the form of NAME 
	[Parameter(Mandatory = $true, Position = 11, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Email Param Set")]
	[string[]] $EmailRecpients,
	# Sets the Sender information for the email in the form of NAME 
	[Parameter(Mandatory = $false, Position = 12, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Email Param Set")]
	[string] $EmailSender = "Do Not Reply ",
	# Will not move the machines to the Active Directory specified holding OU, but will include them on the report.
	[Parameter(Mandatory = $false, Position = 13, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[switch] $DoNotMove = $false,
	# Will not disable machines in Active Directory, but will include them on the report.
	[Parameter(Mandatory = $false, Position = 14, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[switch] $DoNotDisable = $false,
	# Will not delete machines from Active Directory, but will include them on the report.
	[Parameter(Mandatory = $false, Position = 15, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default Param Set")]
	[Parameter(ParameterSetName = "Email Param Set")]
	[switch] $DoNotDelete = $false
)

edit: some how entirely skipped over the fact that Richard answered in the same way already.