I'm trying to use Parameter Sets to replicate this functionality:
if (($hostName) -or ($databaseName) -and (!$databasePassword)) {
throw "If hostName or databaseName specified, you must use databasePassword parameter."
}
Simple example of what I have so far:
[Parameter(Mandatory=$false, ParameterSetName="Test")]
[string]$hostName,
[Parameter(Mandatory=$false, ParameterSetName="Test")]
[string]$databaseName,
[Parameter(Mandatory=$false, ParameterSetName="Test")]
[string]$databasePassword
This is not working. I can supply $hostName without $databasePassword for example, or $dataBasename without $databasePassword and the function runs.
What am I missing?
Make two parameter sets, make $Hostname mandatory in the first, make $DatabaseName optional in the first and mandatory in the other, make $DatabasePassword mandatory in both.
[CmdletBinding(DefaultParameterSetName='host')]
Param(
[Parameter(ParameterSetName='host', Mandatory=$true)]
[string]$Hostname,
[Parameter(ParameterSetName='host', Mandatory=$false)]
[Parameter(ParameterSetName='dbname', Mandatory=$true)]
[string]$DatabaseName,
[Parameter(ParameterSetName='host', Mandatory=$true)]
[Parameter(ParameterSetName='dbname', Mandatory=$true)]
[string]$DatabasePassword
)
Set databasePassword to be mandatory?
[Parameter(Mandatory=$true, ParameterSetName="Test")]
[string]$databasePassword
Related
ex: suppose I have
[Parameter(Mandatory=$true)]
[ValidateSet("UP","DOWN")]
$Direction,
[Parameter(Mandatory=$true)]
[string]$AssertBytes,
[ValidateScript({
if($_ -notmatch "(\.json)"){
throw "The file specified in the path argument must be of type json"
}
return $true
})]
$JsonMappingsFilePath,
If I have $AssertBytes equal true then I want $JsonMappingsFilePath to be mandatory. Otherwise I want it ignored.
This does not seem to work :
[Parameter(Mandatory=$true)]
[ValidateSet("UP","DOWN")]
$Direction,
[Parameter(ParameterSetName='AssertBytes', Mandatory=$False)]
[switch]$AssertBytes,
[Parameter(ParameterSetName='AssertBytes', Mandatory=$False)]
[ValidateScript({
if($_ -notmatch "(\.json)"){
throw "The file specified in the path argument must be of type json"
}
return $true
})]
$JsonMappingsFilePath,
Make AssertBytes a member of two distinct parameter sets - one in which it's mandatory, another in which it is not - the use the CmdletBinding attribute to specify the one in which the parameter is optional as the default parameter set:
[CmdletBinding(DefaultParameterSetName = 'NoAssertBytes')]
param(
[Parameter(Mandatory=$true)]
[ValidateSet("UP","DOWN")]
$Direction,
[Parameter(ParameterSetName='AssertBytes', Mandatory=$False)]
[switch]$AssertBytes,
[Parameter(ParameterSetName='AssertBytes', Mandatory=$True)]
[Parameter(ParameterSetName='NoAssertBytes', Mandatory=$False)]
[ValidateScript({
if($_ -notmatch "(\.json)"){
throw "The file specified in the path argument must be of type json"
}
return $true
})]
$JsonMappingsFilePath
)
I have a switch mechanism in my script and as can be seen,
Add, RemoveRole, and RemoveMmember
I would like for them to REQUIRE the input of $ROLE and $MEMBER, which i know how to do with a conditional if statement, and would exit if nothing is entered. however, it would mean for View, which no input is necessary, to bypass this input requirement.
[CmdletBinding()]
Param(
[Parameter(ParameterSetName='Add', Mandatory=$true)]
[Switch]$Add,
[Parameter(ParameterSetName='RemoveRole', Mandatory=$true)]
[Switch]$RemoveRole,
[Parameter(ParameterSetName='RemoveMember', Mandatory=$true)]
[Switch]$RemoveMember,
[Parameter(ParameterSetName='View', Mandatory=$true)]
[Switch]$View,
[Parameter(ParameterSetName='Add', Mandatory=$true)]
[Parameter(ParameterSetName='RemoveRole', Mandatory=$true)]
[Parameter(ParameterSetName='RemoveMember', Mandatory=$true)]
[Parameter(ParameterSetName='View', Mandatory=$false)]
$ROLE = (Read-Host -prompt "Role"),
$MEMBER = (Read-Host -prompt "Member")
)
How can I make it such that input is required for the first 3 choices, but for view its not? also, how can i make View the default parameter choice if none of the choices is entered by the user?
Setting Default parameter by specify:
[CmdletBinding(DefaultParameterSetName='View')]
You can try the code below:
[CmdletBinding(DefaultParameterSetName='View')]
Param(
[Parameter(ParameterSetName='Add', Mandatory=$true)]
[Switch]$Add,
[Parameter(ParameterSetName='RemoveRole', Mandatory=$true)]
[Switch]$RemoveRole,
[Parameter(ParameterSetName='RemoveMember', Mandatory=$true)]
[Switch]$RemoveMember,
[Parameter(ParameterSetName='View', Mandatory=$false)]
[Switch]$View
)
if ($Add -or $RemoveRole -or $RemoveMember) {
$ROLE = (Read-Host -prompt "Role")
$MEMBER = (Read-Host -prompt "Member")
}
So I have this script that creates a snap mirror on our dr server based on its location. Below is just a small part of a the script. I need to write an if statement so if location='uk' then to not run the below function otherwise if location='us' then create snap-mirror.
function Create-SnapMirror {
[CmdletBinding(PositionalBinding=$false,
HelpUri='http://www.microsoft.com/',
ConfirmImpact='Medium')]
[OutputType([Boolean])]
Param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[String]$SourcePath,
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[String]$DestinationPath,
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=2)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[String]$LogName
)
$success = $null
$error.Clear()
}
Assuming that the logic is required outside of the function you can achieve this by simply encapsulating the function call within the if statement as follows:
if($Location -eq 'us') { Create-SnapMirror -SourcePath $MySourcePath -DestinationPath $MyDestinationPath -LogName $MyLogName }
If however you want to check the location within the function you will first need to receive the location either from the input parameters or some other method. Assuming that you have the location in a variable named $Location you can simply add the following within your function before any other action:
if($Location -ne 'us') { return }
This will exit the function; you can add other actions, for instance logging within the parenthesis.
How can I make PowerShell script to accept 0 or 3 params? All or nothing.
[CmdletBinding()]
Param(
# Name of VPN connection
[Parameter(Mandatory=$False,ValueFromPipeline=$True,Position=1)]
[string]$vpn_name,
# Server URL or IP
[Parameter(Mandatory=$False,ValueFromPipeline=$True,Position=2)]
[string]$vpn_server,
# 192.168.72.0/24
[Parameter(Mandatory=$False,ValueFromPipeline=$True,Position=3)]
[string[]]$target_nets
)
try this
Param(
[Parameter(Mandatory=$True, Position=0, ParameterSet="FirstSet")]
[string]FirstRequiredParam,
[Parameter(Mandatory=$False, Position=0, ParameterSet="SecondSet")]
[string]FirstNotRequiredParam
)
Here is simplified snippet
[CmdletBinding()]
Param(
# Name of VPN connection
[Parameter(Mandatory=$True, ParameterSetName="WithParams")]
[string]$name,
# Server URL or IP
[Parameter(Mandatory=$True, ParameterSetName="WithParams"))]
[string]$vpn_server,
# No params
[Parameter(Mandatory=$False,ValueFromPipeline=$True,Position=0, ParameterSetName="NoParams")]
[string]$none
)
# Then check what parameters set was passed
switch ($PsCmdlet.ParameterSetName){
"WithParams" { Write-Host $name; break}
"NoParams" { Write-Host "No params passed."; break }
}
I was struggling in a situation where I need to make some parameters mandatory ONLY if a switch or combination of switches is used. Below is the example of what I am trying to do:
[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(
[Parameter(Mandatory=$true)][String]$Location,
[Parameter(Mandatory=$true)][String]$DPMServername,
[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[Switch]$CustomizeDPMSubscriptionSettings,
[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[String]$StagingAreaPath,
[Parameter(Mandatory=$False, ParameterSetName='EncryptionSettings')]
[Parameter(ParameterSetName='CustomConfiguration')]
[Switch]$SetEncryption,
[Parameter(Mandatory=$true, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[String]$EncryptionPassPhrase,
[Parameter(Mandatory=$False, ParameterSetName='ProxyEnabled')]
[Parameter(ParameterSetName='CustomConfiguration')]
[Switch]$SetProxy,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(ParameterSetName='CustomConfiguration')]
[String]$ProxyServerAddress,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$False, ParameterSetName='CustomConfiguration')]
[String]$ProxyServerPort
)
Here, I need to follow below conditions:
If -CustomizeDPMSubscriptionSettings (Switch) parameter is used,
it must ask for the Staging AreaPath ---- This is Working fine
ONLY when -CustomizeDPMSubscriptionSettings (Switch) parameter is
used with -SetEncryption, it must ask for -EncryptionPassPhrase
And ONLY when -CustomizeDPMSubscriptionSettings (Switch) parameter is
used with -SetProxy, it must ask for -ProxyServerAddress and -ProxyServerPort
Sorry if this sounds like a repeated question but other posts I found here are not helping me solve my issue. I am confused :-(
NOTE: Above code is part of what I was trying with different combinations. Please correct as necessary.
Here is a solution that seems to do what you expect.
What I did was create a parameter set for each possible combination.
- CustomConfiguration
- EncryptionSettings
- ProxyEnabled
- EncryptionAndProxy
One limitation is that it will not prompt for specific missing parameters unless using EncryptionAndProxy, but will instead state that it cannot resolve the parameter set.
[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(
[Parameter(Mandatory=$true)][String]$Location,
[Parameter(Mandatory=$true)][String]$DPMServername,
[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$CustomizeDPMSubscriptionSettings,
[Parameter(Mandatory=$True, ParameterSetName='CustomConfiguration')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$StagingAreaPath,
[Parameter(Mandatory=$True, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$SetEncryption,
[Parameter(Mandatory=$true, ParameterSetName='EncryptionSettings')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$EncryptionPassPhrase,
[Parameter(Mandatory=$True, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[Switch]$SetProxy,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$ProxyServerAddress,
[Parameter(Mandatory=$true, ParameterSetName='ProxyEnabled')]
[Parameter(Mandatory=$True, ParameterSetName='EncryptionAndProxy')]
[String]$ProxyServerPort
)
I'm looking into a second potential solution based on dynamic parameters.
Edit: As promised, here's a solution based on dynamic parameters
[CmdletBinding(DefaultParameterSetName='DefaultConfiguration')]
Param
(
[Parameter(Mandatory=$true)][String]$Location,
[Parameter(Mandatory=$true)][String]$DPMServername,
[Switch]$CustomizeDPMSubscriptionSettings,
[Switch]$SetEncryption,
[Switch]$SetProxy
)
DynamicParam
{
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = "__AllParameterSets"
$attributes.Mandatory = $true
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
# If "-SetEncryption" is used, then add the "EncryptionPassPhrase" parameter
if($SetEncryption)
{
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("EncryptionPassPhrase", [String], $attributeCollection)
$paramDictionary.Add("EncryptionPassPhrase", $dynParam1)
}
# If "-SetProxy" is used, then add the "ProxyServerAddress" "ProxyServerPort" and parameters
if($SetProxy)
{
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("ProxyServerAddress", [String], $attributeCollection)
$paramDictionary.Add("ProxyServerAddress", $dynParam1)
$dynParam2 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("ProxyServerPort", [String], $attributeCollection)
$paramDictionary.Add("ProxyServerPort", $dynParam2)
}
# If "-CustomizeDPMSubscriptionSettings" is used, then add the "StagingAreaPath" parameter
if($CustomizeDPMSubscriptionSettings)
{
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("StagingAreaPath", [String], $attributeCollection)
$paramDictionary.Add("StagingAreaPath", $dynParam1)
}
return $paramDictionary
}
Process{
foreach($key in $PSBoundParameters.keys)
{
Set-Variable -Name $key -Value $PSBoundParameters."$key" -Scope 0
}
}
What this one does is dynamically add parameters to your function based on the presence of each switch.
This supports autocompletion, and has better support for missing parameters. It will explicitly ask for missing parameters if the corresponding switch is used.
Second edit: I added the Process section that's mandatory with this construct, as well as the variable creation bit, which makes things much easier.