Last active
August 1, 2019 16:30
-
-
Save gaelcolas/704e33fedbcd548c9e42 to your computer and use it in GitHub Desktop.
PowerShell Generating dynamic parameters and parameter sets to wrap around a Class for easy instantiation such as new-Type -ctorArg1 $val -property $val2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region Get-TypeDynamicParam | |
function Get-DynamicParamFromTypeName { | |
Param( | |
[string] | |
$TypeName | |
) | |
function New-ParamAttribute { | |
Param( | |
[Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipelineByPropertyName=$true, position=0)] | |
[string] | |
$ParameterSetName, | |
[Parameter(Mandatory=$true,ValueFromPipeLine=$false,ValueFromPipelineByPropertyName=$true, position=1)] | |
[int] | |
$paramPosition, | |
[Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipelineByPropertyName=$true, position=2)] | |
[switch] | |
$DontShow, | |
[bool] | |
[Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipelineByPropertyName=$true, position=3)] | |
$mandatory = $true | |
) | |
$newAttribute = New-Object System.Management.Automation.ParameterAttribute | |
$newAttribute.Mandatory = $mandatory | |
if($DontShow) {$newAttribute.DontShow = $false} | |
$newAttribute.Position = $paramPosition #This is new attribute, so always 1 (first parameter defining type - non dynamic) | |
$newAttribute.ParameterSetName = $ParameterSetName | |
return $newAttribute | |
} | |
$paramRuntimeCollection = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary | |
$type = $TypeName -as [type] | |
foreach($constructorDefinition in $type.GetConstructors().Where({($_.GetParameters().ParameterType.name -join '') -notmatch '\*'})) { | |
$paramListForParamSet = @() | |
$ParamsInCtor = $constructorDefinition.GetParameters() | |
$constructorIndex = $ParamsInCtor.Name -join '.' | |
foreach ($ParamDefinition in $ParamsInCtor) { | |
$paramPosition = 1 | |
if ($paramRuntimeCollection.keys -notcontains $ParamDefinition.Name) { | |
$newRuntimeDefinedParameter = New-Object System.Management.Automation.RuntimeDefinedParameter | |
$newRuntimeDefinedParameter.Name = $ParamDefinition.Name | |
$newRuntimeDefinedParameter.ParameterType = $ParamDefinition.ParameterType | |
$newRuntimeDefinedParameter.Attributes.Add((New-ParamAttribute -ParameterSetName "ctor_$constructorIndex" -paramPosition $paramPosition)) | |
if ($ParamDefinition.HasDefaultValue) { | |
$newRuntimeDefinedParameter.Value = $ParamDefinition.DefaultValue | |
} | |
$paramRuntimeCollection.Add($newRuntimeDefinedParameter.Name,$newRuntimeDefinedParameter) | |
} | |
else { | |
"$($ParamDefinition.Name) already present in Attribute collection" | Write-Debug | |
"Adding Attribute definition for ParameterSet $($constructorIndex) for Parameter $($ParamDefinition.Name)" | Write-Debug | |
$paramRuntimeCollection[$ParamDefinition.Name].Attributes.Add((New-ParamAttribute -ParameterSetName "ctor_$constructorIndex" -paramPosition $paramPosition)) | |
} | |
$paramListForParamSet+= $ParamDefinition.Name | |
} | |
$paramPosition++ | |
} | |
$writeableProperties = $type.GetProperties().Where({$_.CanWrite -and $_.Name -notin $paramRuntimeCollection.keys}) | |
foreach($propertyArgument in $writeableProperties){ | |
$newRuntimeDefinedParameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter | |
$newRuntimeDefinedParameter.Name = $propertyArgument.Name | |
$newRuntimeDefinedParameter.ParameterType = $propertyArgument.PropertyType | |
$newRuntimeDefinedParameter.Attributes.Add((New-ParamAttribute -ParameterSetName '__AllParameterSets' -paramPosition -2147483648 -mandatory $false)) | |
$paramRuntimeCollection.Add($newRuntimeDefinedParameter.Name,$newRuntimeDefinedParameter) | |
} | |
return $paramRuntimeCollection | |
} | |
#endregion | |
#region New-ObjectInstanceFromTypeNameAndBoundParams | |
function New-ObjectInstanceFromTypeNameAndBoundParams { | |
Param ( | |
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$false)] | |
#[validateScript({if($_ -as [type]){$true}else{$false}})] | |
[string] | |
$TypeName, | |
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$false)] | |
[string[]] | |
$StaticArgumentName, | |
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$false)] | |
[string] | |
$ParameterSetName, | |
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$false)] | |
[validateNotNullOrEmpty()] | |
[hashtable] | |
$BoundParameters | |
) | |
Process { | |
$ConstructorParameterNames = @() | |
if($ParameterSetName -match '^ctor_') { | |
$ConstructorParameterNames = $ParameterSetName -replace '^ctor_' -split '\.' | |
$parameters = @() | |
$ConstructorParameterNames.ForEach({$parameters+=$BoundParameters[$_];$BoundParameters.Remove($_)}) | |
$instanceOfObject = New-Object -TypeName $typeName -ArgumentList $parameters | |
} else { | |
$instanceOfObject = New-Object -TypeName $typeName | |
} | |
$setProperties = $BoundParameters.Keys.Where({$_ -notin $StaticArgumentName -and $_ -notin [System.Management.Automation.PSCmdlet]::CommonParameters -and $_ -notin [System.Management.Automation.PSCmdlet]::OptionalCommonParameters}) | |
foreach ($ParamPropKey in $setProperties) { | |
$instanceOfObject.($ParamPropKey) = $BoundParameters.($ParamPropKey) | |
} | |
$instanceOfObject | |
} | |
} | |
#endregion | |
function New-DateTime { | |
[cmdletBinding()] | |
Param ( | |
[Parameter(Mandatory=$false,ValueFromPipeLine=$false,ValueFromPipelineByPropertyName=$true, position=0)] | |
[ValidateSet('datetime','System.datetime')] | |
[type] | |
$typename = 'datetime' | |
) | |
DynamicParam { | |
if ($PSBoundParameters.Keys -notcontains 'typename') | |
{ | |
$typename = 'datetime' | |
} | |
$type = ($typename -as [Type]) | |
Get-DynamicParamFromTypeName -TypeName $type.ToString() | |
} | |
Process { | |
New-ObjectInstanceFromTypeNameAndBoundParams -TypeName $type.ToString() -StaticArgumentName 'TypeName' -ParameterSetName $PSCmdlet.ParameterSetName -BoundParameters $PSBoundParameters | |
} | |
} | |
#when the above is loaded, try to type New-Datetime - and see the magic happening! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment