1+ Aspect function DynamicParameter {
2+ <#
3+ . SYNOPSIS
4+ Dynamic Parameter Aspect
5+ . DESCRIPTION
6+ The Dynamic Parameter Aspect is used to add dynamic parameters, well, dynamically.
7+
8+ It can create dynamic parameters from one or more input objects or scripts.
9+ . EXAMPLE
10+ Get-Command Get-Command |
11+ Aspect.DynamicParameter
12+ . EXAMPLE
13+ Get-Command Get-Process |
14+ Aspect.DynamicParameter -IncludeParameter Name # Select -Expand Keys | Should -Be Name
15+ #>
16+ [Alias (' Aspect.DynamicParameters' )]
17+ param (
18+ # The InputObject.
19+ # This can be anything, but will be ignored unless it is a `[ScriptBlock]` or `[Management.Automation.CommandInfo]`.
20+ [vfp ()]
21+ $InputObject ,
22+
23+ # The name of the parameter set the dynamic parameters will be placed into.
24+ [string ]
25+ $ParameterSetName ,
26+
27+ # The positional offset. If this is provided, all positional parameters will be shifted by this number.
28+ # For example, if -PositionOffset is 1, the first parameter would become the second parameter (and so on)
29+ [int ]
30+ $PositionOffset ,
31+
32+ # If set, will make all dynamic parameters non-mandatory.
33+ [switch ]
34+ $NoMandatory ,
35+
36+ # If provided, will check that dynamic parameters are valid for a given command.
37+ # If the [Management.Automation.CmdletAttribute]
38+ [string []]
39+ $commandList ,
40+
41+ # If provided, will include only these parameters from the input.
42+ [string []]
43+ $IncludeParameter ,
44+
45+ # If provided, will exclude these parameters from the input.
46+ [string []]
47+ $ExcludeParameter ,
48+
49+ # If provided, will make a blank parameter for every -PositionOffset.
50+ # This is so, presumably, whatever has already been provided in these positions will bind correctly.
51+ # The name of this parameter, by default, will be "ArgumentN" (for example, Argument1)
52+ [switch ]
53+ $BlankParameter ,
54+
55+ # The name of the blank parameter.
56+ # If there is a -PositionOffset, this will make a blank parameter by this name for the position.
57+ [string []]
58+ $BlankParameterName = " Argument"
59+ )
60+
61+ begin {
62+ $inputQueue = [Collections.Queue ]::new()
63+ }
64+ process {
65+ $inputQueue.Enqueue ($InputObject )
66+ }
67+
68+ end {
69+ $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary ]::new()
70+
71+ if ($PositionOffset -and
72+ ($BlankParameter -or $PSBoundParameters [' BlankParameterName' ])) {
73+ for ($pos = 0 ; $pos -lt $PositionOffset ; $pos ++ ) {
74+ $paramName = $BlankParameterName [$pos ]
75+ if (-not $paramName ) {
76+ $paramName = " $ ( $BlankParameterName [-1 ]) $pos "
77+ }
78+ $DynamicParameters.Add ($paramName ,
79+ [Management.Automation.RuntimeDefinedParameter ]::new(
80+ $paramName ,
81+ [PSObject ],
82+ @ (
83+ $paramAttr = [Management.Automation.ParameterAttribute ]::new()
84+ $paramAttr.Position = $pos
85+ $paramAttr
86+ )
87+ )
88+ )
89+ }
90+ }
91+ while ($inputQueue.Count ) {
92+ $InputObject = $inputQueue.Dequeue ()
93+
94+ $inputCmdMetaData =
95+ if ($inputObject -is [Management.Automation.CommandInfo ]) {
96+ [Management.Automation.CommandMetaData ]$InputObject
97+ }
98+ elseif ($inputObject -is [scriptblock ]) {
99+ $function: TempFunction = $InputObject
100+ [Management.Automation.CommandMetaData ]$ExecutionContext.SessionState.InvokeCommand.GetCommand (' TempFunction' , ' Function' )
101+ }
102+
103+ continue if -not $inputCmdMetaData
104+
105+ :nextDynamicParameter foreach ($paramName in $inputCmdMetaData.Parameters.Keys ) {
106+
107+ if ($ExcludeParameter ) {
108+ foreach ($exclude in $ExcludeParameter ) {
109+ if ($paramName -like $exclude ) { continue nextDynamicParameter}
110+ }
111+ }
112+ if ($IncludeParameter ) {
113+ $shouldInclude =
114+ foreach ($include in $IncludeParameter ) {
115+ if ($paramName -like $include ) { $true ;break }
116+ }
117+ if (-not $shouldInclude ) { continue nextDynamicParameter }
118+ }
119+
120+ $attrList = [Collections.Generic.List [Attribute ]]::new()
121+ $validCommandNames = @ ()
122+ foreach ($attr in $inputCmdMetaData.Parameters [$paramName ].attributes) {
123+ if ($attr -isnot [Management.Automation.ParameterAttribute ]) {
124+ # we can passthru any non-parameter attributes
125+ $attrList.Add ($attr )
126+ # (`[Management.Automation.CmdletAttribute]` is special, as it indicates if the parameter applies to a command)
127+ if ($attr -is [Management.Automation.CmdletAttribute ] -and $commandList ) {
128+ $validCommandNames += (
129+ ($attr.VerbName -replace ' \s' ) + ' -' + ($attr.NounName -replace ' \s' )
130+ ) -replace ' ^\-' -replace ' \-$'
131+ }
132+ } else {
133+ # but parameter attributes need to copied.
134+ $attrCopy = [Management.Automation.ParameterAttribute ]::new()
135+ # (Side note: without a .Clone, copying is tedious.)
136+ foreach ($prop in $attrCopy.GetType ().GetProperties(' Instance,Public' )) {
137+ if (-not $prop.CanWrite ) { continue }
138+ if ($null -ne $attr .($prop.Name )) {
139+ $attrCopy .($prop.Name ) = $attr .($prop.Name )
140+ }
141+ }
142+
143+ $attrCopy.ParameterSetName =
144+ if ($ParameterSetName ) {
145+ $ParameterSetName
146+ }
147+ else {
148+ $defaultParamSetName = $inputCmdMetaData.DefaultParameterSetName
149+ if ($attrCopy.ParameterSetName -ne ' __AllParameterSets' ) {
150+ $attrCopy.ParameterSetName
151+ }
152+ elseif ($defaultParamSetName ) {
153+ $defaultParamSetName
154+ }
155+ elseif ($this -is [Management.Automation.FunctionInfo ]) {
156+ $this.Name
157+ } elseif ($this -is [Management.Automation.ExternalScriptInfo ]) {
158+ $this.Source
159+ }
160+ }
161+
162+ if ($NoMandatory -and $attrCopy.Mandatory ) {
163+ $attrCopy.Mandatory = $false
164+ }
165+
166+ if ($PositionOffset -and $attr.Position -ge 0 ) {
167+ $attrCopy.Position += $PositionOffset
168+ }
169+ $attrList.Add ($attrCopy )
170+ }
171+ }
172+
173+ if ($commandList -and $validCommandNames ) {
174+ :CheckCommandValidity do {
175+ foreach ($vc in $validCommandNames ) {
176+ if ($commandList -match $vc ) { break CheckCommandValidity }
177+ }
178+ continue nextDynamicParameter
179+ } while ($false )
180+ }
181+
182+ if ($DynamicParameters.ContainsKey ($paramName )) {
183+ $DynamicParameters [$paramName ].ParameterType = [PSObject ]
184+ foreach ($attr in $attrList ) {
185+ $DynamicParameters [$paramName ].Attributes.Add($attr )
186+ }
187+ } else {
188+ $DynamicParameters.Add ($paramName , [Management.Automation.RuntimeDefinedParameter ]::new(
189+ $inputCmdMetaData.Parameters [$paramName ].Name,
190+ $inputCmdMetaData.Parameters [$paramName ].ParameterType,
191+ $attrList
192+ ))
193+ }
194+ }
195+ }
196+ $DynamicParameters
197+ }
198+ }
0 commit comments