Skip to content

Instantly share code, notes, and snippets.

@rohnedwards
Created May 18, 2018 17:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rohnedwards/620e9f391b871e043f37657517b9ec2e to your computer and use it in GitHub Desktop.
Save rohnedwards/620e9f391b871e043f37657517b9ec2e to your computer and use it in GitHub Desktop.
Example of peeking into unbound parameters inside DynamicParam block. This is a bad idea, and should only be used for playing around with the PowerShell engine.
# Link to original question: https://powershell.org/forums/topic/retrieve-the-input-value-of-the-dynamic-parameter/
function Test-DynamicParamCreation {
<#
.SYNOPSIS
Example of how to make dynamic param decisions based on other dynamic params.
NOTE: This probably isn't a good idea, as reflection is used to get at private
members of the PowerShell engine.
.DESCRIPTION
This function has a dynamic parameter named '-OtherDynamicParameterName' that
takes one or more parameter names (NOTE: Breaking this is pretty easy if you
don't pass single word strings)
The dynamic parameters created based on -OtherDynamicParameterName are very
simple, and are optional params that will accept any value. This functionality
isn't particulary useful, but is simply being used as a proof of concept to
show what's possible.
The function simply returns the $PSBoundParameters dictionary.
.EXAMPLE
Test-DynamicParamCreation -OtherDynamicParamName Test1, Test2 -Test1 test1 -Test2 test2
This should return a dictionary with all three of those parameters.
.EXAMPLE
Test-DynamicParamCreation -OtherDynamicParamName Test1, Test2 -Test1 test1 -Test2
This should result in an error since -Test2 had no value provied
.EXAMPLE
Test-DynamicParamCreation -OtherDynamicParamName Test1 -Test1 test1 -Test2 test2
This should result in an error since -Test2 wasn't provided as a new dynamic parameter
to -OtherDynamicParamName
#>
[CmdletBinding()]
param(
)
DynamicParam {
$EC = $ExecutionContext.GetType().InvokeMember('_context', 'NonPublic, Instance, GetField', $null, $ExecutionContext, $null)
$CCP = $EC.GetType().InvokeMember('CurrentCommandProcessor', 'NonPublic, Instance, GetProperty', $null, $EC, $null)
$Binder = $CCP.GetType().InvokeMember('CmdletParameterBinderController', 'NonPublic, Instance, GetProperty', $null, $CCP, $null)
$ValidProperties = 'ParameterNameSpecified', 'ParameterName', 'ArgumentSpecified', 'ArgumentValue'
$UnboundArguments = $Binder.GetType().InvokeMember('UnboundArguments', 'NonPublic, Instance, GetProperty', $null, $Binder, $null) | ForEach-Object {
if (-not $ValidProperties) {
$ValidProperties = $_.GetType().GetProperties('NonPublic, Instance').Name
}
$Props = [ordered] @{}
foreach ($PropName in $ValidProperties) {
try {
$Props[$PropName] = $_.GetType().InvokeMember($PropName, 'NonPublic, Instance, GetProperty', $null, $_, $null)
}
catch {}
}
[PSCustomObject] $Props
}
$fakeBoundNamed = @{}
$fakeBoundUnNamed = New-Object System.Collections.ArrayList
$CurrentParamName = $null
foreach ($Arg in $UnboundArguments) {
if ($Arg.ParameterNameSpecified) {
if ($CurrentParamName) {
# Assume this is a switch
$fakeBoundNamed[$CurrentParamName] = $true
}
$CurrentParamName = $Arg.ParameterName
}
if ($Arg.ArgumentSpecified) {
if (-not $CurrentParamName) {
$fakeBoundUnNamed.Add($Arg.ArgumentValue) | Out-Null
}
else {
$fakeBoundNamed[$CurrentParamName] = $Arg.ArgumentValue
$CurrentParamName = $null
}
}
}
$ParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$ParamAttributes = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParamAttributes.Add((New-Object Parameter))
$ParameterName = 'OtherDynamicParamName'
$ParamDictionary[$ParameterName] = New-Object System.Management.Automation.RuntimeDefinedParameter (
$ParameterName,
[string[]],
$ParamAttributes
)
if ($NewParamNames = $fakeBoundNamed.$ParameterName) {
foreach ($NewParamName in ($NewParamNames -split '\s*\,\s*')) {
$NewParamAttributes = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$NewParamAttributes.Add((New-Object Parameter))
$ParamDictionary[$NewParamName] = New-Object System.Management.Automation.RuntimeDefinedParameter (
$NewParamName,
[object],
$NewParamAttributes
)
}
}
return $ParamDictionary
}
process {
$PSBoundParameters
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment