Reuse parameters among multiple powershell functions

Consider two powershell functions:

function A {
params(
    [Parameter()]$x,
    [Parameter()]$y
)
Write-Host $x $y
}

function B {
params(
    [Parameter()]$x,
    [Parameter()]$z
)
Write-Host $x $z
}

I'd like to define a single parameter $x once (which could have fairly complex attributes that must be kept identical for both functions) and re-use it in both functions, so something like:

$x = {[Parameter()]$x}
function A {
params(
    $x,
    [Parameter()]$y
)
Write-Host $x $y
}

function B {
params(
    $x,
    [Parameter()]$z
)
Write-Host $x $z
}

(How) is this possible?


Solution 1:

  • To reuse parameter declarations across functions - as requested in your question - see the following section.

  • To reuse parameter values (arguments) across functions, by way of presets (default value), see the bottom section.


In order to reuse parameter declarations - short of using design-time templating to generate source code - you need to to define a script block that creates a dynamic parameter that can be passed to the dynamicparam block of multiple advanced functions:

using namespace System.Management.Automation

# The script block that declares the dynamic parameter to be shared
# across functions.
$sharedDynParam = {
  
    # Define the -x parameter dynamically.
    $paramName = 'x'
    $dict = [RuntimeDefinedParameterDictionary]::new()
    $dict.Add(
      $paramName,
      [RuntimeDefinedParameter]::new(
        $paramName,
        [datetime],              # Type the parameter [datetime]. for instance.
        [ParameterAttribute] @{
          Mandatory = $true      # Make the parameter mandatory, for instance.
          # ParameterSetName = 'default' # Assign it to a parameter set, if neeeded.
        }
      )
    )

    # Return the dictionary
    return $dict
}

function A {
  [CmdletBinding()]
  param(
    $y
  )
  
  # Assign the shared dynamic parameter.
  dynamicparam { & $sharedDynParam } 

  # The use of `dynamicparam { ... }` requires use of an explicit
  # `process { ... }` block (and optionally `begin { ... }` and
  # `end { ... }`, as needed).
  process {
    # Note: A dynamic -x parameter cannot be accessed as $x
    #       Instead, it must be accessed via the $PSBoundParameters dictionary.
    "[$($PSBoundParameters['x'])] - [$y]"
  }

}

function B {
  [CmdletBinding()]
  param(
    $z
  )

  # Assign the shared dynamic parameter.
  dynamicparam { & $sharedDynParam } 

  process {
    "[$($PSBoundParameters['x'])] - [$z]"
  }

}


# Sample calls, 
A -x '1970-01-01' -y yval
B -x '1970-01-02' -z zval

Output:

[01/01/1970 00:00:00] - [yval]
[01/02/1970 00:00:00] - [zval]

To preset the value of a parameter by a given name across commands, use the $PSDefaultParameterValues preference variable:

# Preset a parameter value for all commands ('*') that have
# an -x ('x') parameter.
$PSDefaultParameterValues = @{ '*:x' = [pscustomobject] @{ foo = 1; bar = 2 } }

function A {  
  [CmdletBinding()] # This makes the function an *advanced* one, which respects 
                    # $PSDefaultParameterValues; similarly, at least one
                    # parameter-individual [Parameter()] attribute does the same.
  param(
    $x,
    $y
  )
  "[$x] - [$y]"
}
  
function B {
  [CmdletBinding()]
  param(
    $x,
    $z
  )
  "[$x] - [$z]"
}

# Sample calls, without an -x argument, relying on
# $PSDefaultParameterValues to provide it automatically.
A -y yval
B -z zval

Output, showing that parameter -x was automatically bound via $PSDefaultParameterValues:

[@{foo=1; bar=2}] - [yval]
[@{foo=1; bar=2}] - [zval]