Dynamic Parameter IP Messing Things Up

Dynamic parameter disappears, but only if typed second.

I'm writing a function with a DynamicParam code block defining a parameter attribute, but there is very definitely strange behavior going on. In the following function I have three separate parameter attribute definitions for the $Subnet mask parameter. The first one is what I want in the end. The second one is a short list just to see if the length of the list changed things (spoiler alert; it didn't). The third one was a test to see if the data within it changed things (spoiler alert; it DID).

All right. The bottom line is that this function works with the any of these parameter attribute definitions so long as you type the Application parameter first when using the function. If you type the SubnetMask parameter first, then the dynamic parameter called Application is no longer available. But here’s where it gets interesting. Change the list of values from IPs to anything else (I used fruit) and it stays visible and the function works great.

Is there something I need to change to make sure my Application parameter doesn’t disappear?

$TheseApps = @('this','that','other')
function Get-This {
[CmdletBinding()]
param(

[ValidateSet('255.0.0.0','255.128.0.0','255.192.0.0','255.224.0.0','255.252.0.0','255.254.0.0','255.255.0.0','255.255.128.0','255.255.192.0','255.255.224.0','255.255.240.0','255.255.248.0','255.255.252.0','255.255.254.0','255.255.255.0','255.255.255.128','255.255.255.192','255.255.255.224','255.255.255.240','255.255.255.248','255.255.255.252','255.255.255.254','255.255.255.255')]
#[ValidateSet('255.0.0.0','255.128.0.0')]
#[ValidateSet('banana','cherry','apple','kiwi','peach')]
[string]
$SubnetMask

)
DynamicParam 
{
# Parameter Attribute
$AppAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{
Mandatory = $true
Position = 0
HelpMessage = 'Select from the list of applications'
ValueFromPipeline = $false
ValueFromPipelineByPropertyName = $false
DontShow = $false
}

# Values Collection
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add( $AppAttribute )
$ValidateSet = New-Object System.Management.Automation.ValidateSetAttribute( $TheseApps )
$attributeCollection.Add( $ValidateSet )

# Runtime Defined Parameter
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter( "Application", [string], $attributeCollection )

# Runtime Defined Parameter Dictionary
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add( "Application", $dynParam1 )

return $paramDictionary
}
Begin{}
Process
{
foreach( $Key in $PSBoundParameters.Keys )
{
Write-Host "$Key is $( $PSBoundParameters.Item($Key) )"
}
}
End{}
}

Replying to my own post here. I figured out a way to get it to work, but only by creating both parameters listed as dynamic parameters. I’d still love to know why IPs put in as strings into an array mess up the whole ValidateSet() piece of all this.

 

Cheers to all who stumble upon this.

I still haven’t found the answer, but I have found out that using anything that starts out like an IP seems to cause the second parameter to disappear. It appears to need only the first two octets to throw off the second parameter.

So in the example code below, starting the function call with anything like these make the Application parameter disappear:
<p style=“padding-left: 40px;”>Get-This -SubnetMask ‘10.20.10.10’</p>
<p style=“padding-left: 40px;”>Get-This -SubnetMask ‘255.255.p’</p>
These examples; however, let you still use the Application parameter:
<p style=“padding-left: 40px;”>Get-This -SubnetMask ‘p.192.250.250’</p>
<p style=“padding-left: 40px;”>Get-This -SubnetMask ‘p’</p>
<p style=“padding-left: 40px;”>Get-This -SubnetMask ‘192.p’</p>
I gave the following list for the validated set. The first two cause the missing parameter, but the rest don’t.

‘10.20.10.10’

‘255.255.p’

‘p.192.250.250’

‘p’

‘192.p’

 

The full code follows if you want to try it out. Anyone who knows why, please let me know. I’ll start looking through classes and interfaces next.

$TheseApps = @('this','that','other')
function Get-This {
  [CmdletBinding()]
  param(
    [ValidateSet('10.20.10.10','255.255.p','p.192.250.250','p','192.p')]
    [string]
    $SubnetMask
  )
  DynamicParam 
  {
    # Parameter Attribute
    $AppAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{
      Mandatory = $true
      Position = 0
      HelpMessage = 'Select from the list of applications'
      ValueFromPipeline = $false
      ValueFromPipelineByPropertyName = $false
      DontShow = $false
    }

    # Values Collection
    $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
    $attributeCollection.Add( $AppAttribute )
    $ValidateSet = New-Object System.Management.Automation.ValidateSetAttribute( $TheseApps )
    $attributeCollection.Add( $ValidateSet )

    # Runtime Defined Parameter
    $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter( "Application", [string], $attributeCollection )

    # Runtime Defined Parameter Dictionary
    $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
    $paramDictionary.Add( "Application", $dynParam1 )

    return $paramDictionary
  }
  Begin{}
  Process
  {
    foreach( $Key in $PSBoundParameters.Keys )
    {
      Write-Host "$Key is $( $PSBoundParameters.Item($Key) )"
    }
  }
  End{}
}

A friend just pointed out that the IPs get strings added around them, but the other values do not. So after letting intellisense (tab-complete), if you remove the quotes from the IP, then it evaluates correctly and the second parameter shows up.

Is there a reason you are using string vs specify the type as an IPAddress

PS C:\WINDOWS\system32> [System.Net.IPAddress]"1.1.1."
Cannot convert value "1.1.1." to type "System.Net.IPAddress". Error: "An invalid IP address was specified."
At line:1 char:1
+ [System.Net.IPAddress]"1.1.1."
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastParseTargetInvocation
 param(
    [ValidateSet('10.20.10.10','255.255.p','p.192.250.250','p','192.p')]
    [IPAddress]
    $SubnetMask
  )

What does ‘p’ represent?

Thanks for the response Rob.

I’ve tried both and string was the only way to demonstrate how some values work and others don’t. The second parameter goes missing for all values when using System.Net.IPAddress. I definitely agree that IPAddress would be the ideal type to provide, though, and would like to go back to if it would only work the way I want it to.

Also, nearly everything about the function I’m using at the office is different from this example. I made up this example in hopes of finding the root cause and to demonstrate the strange behavior.