Author Posts

April 4, 2015 at 5:42 am

Hi Guys,
I need your help to write a function with dependent parameters.

In this below example, if the switch 'NO_Fav_things' is $true then the parameter 'FavoriteCar' should not come when user gives tabs; if technically this is not possible then at least it should through an error.

[CmdletBinding()] 
param( 
     [string]$Age, 
     [string]$Sex, 
     [string]$Location,
     [switch]$NO_Fav_things,      
     [string]$FavoriteCar
)

April 4, 2015 at 6:41 am

You might be able to do something with dynamic parameters, but really, what you're asking for isn't a correct pattern in PowerShell. The shell doesn't use one parameter to 'enable' another. You should provide your -FavoriteChar as an optional parameter; if it isn't provided, then internally you would set a variable to False if needed.

April 4, 2015 at 12:27 pm

Yeah it might just be easier on this one to set the default value of $FavoriteCar to something arbitrary, or empty, then just test against it, if it is the default value, basically ignore it, otherwise act upon it, and then you do not need the $NO_Fav_things switch at all.

April 4, 2015 at 12:54 pm

Actually, you don't need to use a default value. $PSBoundParameters.ContainsKey('FavoriteChar') will return True or False if the parameter was used, so you'd use that to test. That's a better pattern than testing for an arbitrary default value. Technically, if you provide a default value, then the parameter always "exists."

But you should definitely do that vs. having a second switch parameter.

April 4, 2015 at 1:02 pm

Thanks for that, looks like either I've just overlooked something or missed it in my learning on PowerShell, so now I have just another item added to my own arsenal.

April 10, 2015 at 9:51 pm

Unfortunately I am unable to understand dynamic parameters. Some how I grabbed some helpful examples and re-wrote the code to my requirements. But its not giving the required outputs. Please help me to arrange this code.

My requirement is :

I have 3 parameters. (1) DAG (2) ExcludeNode (3) Node. The below are the conditions
1. DAG can take inputs alone, i.e., with out ExcludeNode and Node parameter should be $Null
2. ExcludeNode should accept input only if DAG != $null and Node=$Null
3. Node should accept inputs only if DAG, ExcludeNode 's are $Null

The problem with the below code, after executing the code I am able to see only one parameter that is DAG. But cannot find any further parameters.

Function check
{
	[CMDLetBinding()]
	param()
	#		[parameter(MAndatory=$False,ValueFromPipeline=$False,Position=0)][String[]]$DAG,
	#		[parameter(MAndatory=$False,ValueFromPipeline=$False,Position=1)][String[]]$ExcludeNode,
	#		[parameter(MAndatory=$False,ValueFromPipeline=$False,Position=2)][String[]]$Node		
	#)
	DynamicParam
    {
        if ($Node -eq $Null)
        {
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false
            $attributeCollection = new-object `
                -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)

            $dynParam1 = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameter("DAG", [String[]], $attributeCollection)

            $paramDictionary = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add("DAG", $dynParam1)
            return $paramDictionary
        }
		if ($Node -eq $Null -and $DAG -ne $Null)
        {
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false
            $attributeCollection = new-object `
                -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)

            $dynParam1 = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameter("ExcludeNode", [String[]], $attributeCollection)

            $paramDictionary = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add("ExcludeNode", $dynParam2)
            return $paramDictionary
        }
		if ($DAG -eq $Null -and $ExcludeNode -eq $Null)
        {
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false
            $attributeCollection = new-object `
                -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)

            $dynParam1 = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameter("Node", [String[]], $attributeCollection)

            $paramDictionary = new-object `
                -Type System.Management.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add("Node", $dynParam3)
            return $paramDictionary
        }
    }
	Begin
	{
	}
	PROCESS
	{
		$DAG[0]
		$ExcludeNode[0]
		$Node[0]
	}
	END{}
}

April 11, 2015 at 1:33 am

So one thing you are doing wrong is that your param () statement does not encapsulate all the static and dynamic parameters. Further more based on what you are saying you don't need dynamic parameters you could simply use parameter sets. So what I have done is the following:

    Created two parameters sets, DAG and Node (names are cosmetic feel free to change it
    For the DAG parameter set I have set -Dag as mandatory and -ExcludeNode as non-mandatory
    The second parameter set only has node and the function will fail if either Dag or ExcludeNode are included

Here is the code I created for you, let me know if it makes sense and if it works as expected:


Function Test-Param {
[CMDLetBinding()]
param(
[parameter(ParameterSetName="DAG",
MAndatory=$true,
ValueFromPipeline=$False,
Position=0)]
[String[]]$DAG,
[parameter(ParameterSetName="DAG",
MAndatory=$False,
ValueFromPipeline=$False,
Position=1)]
[String[]]$ExcludeNode,
[parameter(ParameterSetName="Node",
MAndatory=$False,
ValueFromPipeline=$False,
Position=0)]
[String[]]$Node
)
}

April 11, 2015 at 2:26 am

Superb !! that worked fine in PowerShell 4.0 but not working as expected in 2.0. Any alternate or work around by changing the code for this pls..?
The target machines cannot be upgraded to PS version >2.0

On other hand if we cannot write the code in 2.0 to make it work like 4.0, then I am okay even if we can capture and condition the error and then produce my own write-error text. here I am not sure where to try-catch the error ! 🙁 . PFA error.

April 11, 2015 at 6:52 pm

That is because parameter sets as well as dynamic parameters were introduced in PowerShell version 3, so if you would like to support this in PowerShell 2.0 you would have to write it yourself. As for dynamic parameters, this is when you want parameters or arguments for your parameter to be dependent on an outside source. For example if the arguments for the -DAG parameter are stored in an external csv which changes on a regular basis then you could populate the potential arguments using dynamic parameters.

To write this in PowerShell 2.0 it would be something along these lines, I use a switch statement here in which I use the -and and the -not operators to match your logic:

Function Test-Param {
    [CMDLetBinding()]
    param(
        [String[]]$DAG,
        [String[]]$ExcludeNode,
        [String[]]$Node
    )

$CustomErrorMessage = "1. DAG can take inputs alone, i.e., with out ExcludeNode and Node parameter should be $Null
2. ExcludeNode should accept input only if DAG != $null and Node=$Null
3. Node should accept inputs only if DAG, ExcludeNode 's are $Null"

    switch ($true) {
        {($DAG) -and (-not $Node)} {'yay'}
        {($ExcludeNode) -and ($DAG) -and (-not $Node)} {'yay2'}
        {($Node) -and (-not $DAG) -and (-not $ExcludeNode)} {'yay3'}
        Default {Write-Warning $CustomErrorMessage}
    }
}

April 11, 2015 at 8:34 pm

thnx bro, thnx a lot. let me implement and see if I need anything else. at a glance its good now.

April 12, 2015 at 12:04 am

No problem, let me know if you need any additional help with any of this.