Private/PivTool/Get-PWSHYBKPIVActionParameter.ps1

function Get-PWSHYBKPIVActionParameter {
    <#
    .SYNOPSIS
        Builds the RuntimeDefinedParameterDictionary for one cmdletWrapping action.
    .DESCRIPTION
        Called from a public cmdlet's DynamicParam block. Reads
        CmdletWrapping.actions.<Action> to find the option names the action accepts, then for
        each one reads CmdletWrapping.options.<name> to build a RuntimeDefinedParameter:
        - type: string/int/switch/secureString map to [string]/[int]/[switch]/[SecureString].
        - Mandatory: true when the option is in the action's requiredOptions list.
        - allowedValues only: a ValidateSet.
        - allowedPattern only: a ValidatePattern.
        - both allowedValues and allowedPattern (e.g. slot: named slots 9a/9c/9d/9e/f9 OR the
          hex range 82-95): a single ValidateScript expressing that OR - ValidateSet and
          ValidatePattern combined on one parameter are ANDed by PowerShell, which would wrongly
          reject every legal value here, so they cannot be used together for this case.

        An option name with no matching entry in CmdletWrapping.options is skipped rather than
        throwing, so a typo'd catalog reference degrades to "parameter not offered" instead of
        breaking every cmdlet for the affected action.
    .PARAMETER Action
        The action name to look up in CmdletWrapping.actions, e.g. 'generate'.
    .PARAMETER CmdletWrapping
        The CmdletWrapping section of the parsed configuration (Read-PWSHYBKPIVConfigFile
        output's .cmdletWrapping property).
    .OUTPUTS
        System.Management.Automation.RuntimeDefinedParameterDictionary
    .EXAMPLE
        Get-PWSHYBKPIVActionParameter -Action 'generate' -CmdletWrapping $config.cmdletWrapping
        Returns the dynamic parameter dictionary for the "generate" action.
    #>

    [CmdletBinding()]
    [OutputType([System.Management.Automation.RuntimeDefinedParameterDictionary])]
    param(
        [Parameter(Mandatory)]
        [string] $Action,

        [Parameter(Mandatory)]
        [PSCustomObject] $CmdletWrapping
    )

    $actionConfig = $CmdletWrapping.actions.$Action
    if (-not $actionConfig) {
        throw "Unknown yubico-piv-tool action '$Action'."
    }

    $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
    $requiredNames   = @($actionConfig.requiredOptions)
    $optionNames     = $requiredNames + @($actionConfig.optionalOptions)

    foreach ($optionName in $optionNames) {
        $optionDef = $CmdletWrapping.options.$optionName
        if (-not $optionDef) { continue }

        $type = switch ($optionDef.type) {
            'int'          { [int] }
            'switch'       { [switch] }
            'secureString' { [System.Security.SecureString] }
            default        { [string] }
        }

        $attributes = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()

        $paramAttribute = [System.Management.Automation.ParameterAttribute]::new()
        $paramAttribute.Mandatory = $requiredNames -contains $optionName
        $attributes.Add($paramAttribute)

        $hasAllowedValues  = [bool]$optionDef.allowedValues
        $hasAllowedPattern = [bool]$optionDef.allowedPattern

        if ($hasAllowedValues -and $hasAllowedPattern) {
            $capturedValues  = [string[]]$optionDef.allowedValues
            $capturedPattern = [string]$optionDef.allowedPattern
            $validateScript  = {
                ($capturedValues -contains $_) -or ($_ -match $capturedPattern)
            }.GetNewClosure()
            $attributes.Add([System.Management.Automation.ValidateScriptAttribute]::new($validateScript))
        } elseif ($hasAllowedValues) {
            $attributes.Add([System.Management.Automation.ValidateSetAttribute]::new([string[]]$optionDef.allowedValues))
        } elseif ($hasAllowedPattern) {
            $attributes.Add([System.Management.Automation.ValidatePatternAttribute]::new([string]$optionDef.allowedPattern))
        }

        $parameterName = ConvertTo-PWSHYBKPIVParameterName -Name $optionName
        $runtimeParam  = [System.Management.Automation.RuntimeDefinedParameter]::new($parameterName, $type, $attributes)
        $paramDictionary.Add($parameterName, $runtimeParam)
    }

    $paramDictionary
}