0

I have a dynamically loaded PowerShell script block that accepts multiple parameters (including Mandatory, type, default value,...). I also have a function that has its own parameter sets and internally, it calls the script block. The script block is dynamically loaded based on other parameters, and I'd like to allow the user to pass the parameters to my function and forward them to script block. For that, I'd like to read the possible parameters from the script block, which I can do using $block.Ast.ParamBlock.Parameters and then create matching parameters for my function using DynamicParam.

Example:

Script block:

$block = {
  param([Parameter(Mandatory)][string]$test = 10)
  echo $test
}

Function:

function Fn {
  param($FnParam1, $FnParam2)

  DynamicParam {
    // what to write here
  }

  & $block // how to efficiently forward the parameters here?
}

It should be possible to call Fn like this:

Fn -FnParam1 value -FnParam2 value -test 20

However, DynamicParam is created using RuntimeDefinedParameter and related classes, and AST of the script block returns Management.Automation.Language.ParameterAst and other instances from the same namespace. I could manually create the DynamicParam parameters by converting the AST node-by-node, but it seems like there should be a simpler way to automatically convert these.

user2486570
  • 902
  • 8
  • 14

1 Answers1

0

I know this is old, but it wasn't clear if anyone actually answered this. Since I had to do this for a project of my own, I thought I would chime in.

First, this can absolutely be done, though it can be a tad tricky. You will need a 'trigger' parameter on your main cmdlet that can be used to fire the dynamicparam block. The next thing you will need is the details on the parameters to be surfaced. While this can theoretically be collected at runtime, I would recommend against this as it could be overhead intensive, resulting in either an extended pause of the shell when the user attempts tab completion, or the process not completing before the user goes to execute.

I recently had to figure this myself for a module that I am building. The main module leverages 'nested modules' that are only visible in the private scope of the module. My main cmdlet needed to call a cmdlet from the nested module, along with any parameters required.

So solve the performance hits, I have all of my 'nested' modules in a specific folder, though you could also use specific filters from a list as well. During the import process, I use AST and the ParameterAST subclass to inventory the parameters and notations (Parameter block, validate blocks, object class, param name, etc). The data for each cmdlet is stored in an array. The main cmdlet has a primary pseudo statically defined parameter that is my 'trigger', which allows tab completion of the cmdlet names from the nested modules. I populate this via a dynamically generated Enum so I can use it as both a type on the parameter, and for registering an argument completer. Once the user specifies the child cmdlet to be called, the DynamicParam block fires and filters the array collected on import. The collected parameter details are then turned into an object and fed to a 'New-DynamicParameter' cmdlet that creates the required parameters.

I wrote about all the elements in more detail on my blog, in case you'd like to read up on things - https://mer-bach.com/2023/05/10/promoting-external-parameters/