5

Trying to get a better understanding of Dynamic Parameters, but something keeps bothering me. All examples I've found across the outer-webs (internet), the parameter attributes are always defined/included.

Here's what I'm working with:

Function Test-DynamicParameters {
[cmdletbinding()]
    Param (
        [System.IO.DirectoryInfo]$Path
    )
    DynamicParam
    {
        if ($Path.Extension) {
              $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
                  Mandatory = $false
              }

              $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
              $attributeCollection.Add($parameterAttribute)

              $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
                'TestSwitch', [switch], $attributeCollection
              )

              $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
              $paramDictionary.Add('TestSwitch', $dynParam1)
              $paramDictionary
        }
    }
    Begin { }
    Process
    {
        $PSBoundParameters
    }
    End { }
}

. . .currently have tried numerous combinations of removing certain lines/code to see what would make my Dynamic Parameter show, but nothing works without the attributes being declared. Is this necessary?

Question: what is the simplest form of Dynamic Parameter declaration that I would need for it to work?

For Example - can it just be shortened to where I only define just the name? Or, would PowerShell insist a type is specified instead of defaulting to [object]? Something like:

$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('TestSwitch')
$paramDictionary
Abraham Zinala
  • 4,267
  • 3
  • 9
  • 24

2 Answers2

3

What kind of behavior are you looking for? Because dynamic parameters are usually not needed, even if the auto-completion is dynamic.

For example you could do

  • autocomplete module names for Get-Command -Module
  • or search for files by filetype, only complete filetypes if they exist in that directory

Windows Powershell

You can use DynamicValidateSet pattern in WindowsPowershell

gif using DynamicValidateSet

https://i.stack.imgur.com/nnLBS.gif

New in PowerShell

6 adds Suggestions

New: [IValidateSetValuesGenerator] and [ArgumentCompletions]

It autocompletes like [ValidateSet], but the user is still free to enter others.

Note, [ArgumentCompletions] and [ArgumentCompleter] are two different classes.

[Parameter(Mandatory)]
[ArgumentCompletions('Fruits', 'Vegetables')]
[string]$Type,

7.2 Generic Completers

New [ArgumentCompleter] attribute with the [IArgumentCompleterFactory] interface

from the docs:

[DirectoryCompleter(ContainingFile="pswh.exe", Depth=2)]

[DateCompleter(WeekDay='Monday', From="LastYear")]

[GitCommits(Branch='release')]
ninMonkey
  • 7,211
  • 8
  • 37
  • 66
  • Very neat stuff, wasn't aware of such a feature; PowerShell is just so cool. Unfortunately, what I'm looking for is certain parameters (*not values*) to become available based on certain conditions from other parameters. In this case though, I'm just looking to see what it takes to initialize a dynamic parameter with the least amount of code. I.e. what classes do I need to instantiate so my parameter becomes available at runtime. Hopefully this makes some sense. – Abraham Zinala Dec 30 '21 at 16:55
1

You can’t as the function add of the type System.Management.Automation.RuntimeDefinedParameterDictionary require to provide a key and value which is exactly a String (key) and a System::Management::Automation::RuntimeDefinedParameter for the value. For more information you can check the class documentation here https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.runtimedefinedparameterdictionary?view=powershellsdk-7.0.0.

I have tested on my side and you need at least the ParameterAttribute Mandatory set to true in order to make it run, and the key/name used in the RuntimeDefinedParameter must match the key used in the dictionary when you add it.

So the minimum code that you need should be like this:

Function Test-DynamicParameters {
[cmdletbinding()]
    Param (
        [System.IO.FileSystemInfo ]$Path
    )
    DynamicParam
    {
        if ($Path.Extension) {
              $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
               Mandatory = $true
              }

              $attributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
              $attributeCollection.Add($parameterAttribute)

              $dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new("TestSwitch", [string], $attributeCollection)

              $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
              $paramDictionary.Add('TestSwitch', $dynParam1)
              $paramDictionary
        }
    }
    Begin { }
    Process
    {
        $PSBoundParameters
    }
    End { }
}
$FileNamePath = "C:\tmp\stackoverflow\test.txt";
$path = (Get-Item $FileNamePath )
Test-DynamicParameters -Path $path
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
BETOMBO
  • 174
  • 5
  • 1
    Hello! My current code works without the need to set the mandatory property to `$true`, but I think you may be right as far as this being the least amount of code need to initialize a Dynamic Parameter. I think the objects instantiated are dependent on one another. – Abraham Zinala Dec 30 '21 at 17:00