Advertisement
Old-Lost

New-DynamicParameter

May 3rd, 2017
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. .SYNOPSIS
  3.     Helper function to simplify creating dynamic parameters
  4.  
  5. .DESCRIPTION
  6.     Helper function to simplify creating dynamic parameters.
  7.  
  8.     Example use cases:
  9.         Include parameters only if your environment dictates it
  10.         Include parameters depending on the value of a user-specified parameter
  11.         Provide tab completion and intellisense for parameters, depending on the environment
  12.  
  13.     Please keep in mind that all dynamic parameters you create, will not have corresponding variables created.
  14.         Use New-DynamicParameter with 'CreateVariables' switch in your main code block,
  15.         ('Process' for advanced functions) to create those variables.
  16.         Alternatively, manually reference $PSBoundParameters for the dynamic parameter value.
  17.  
  18.     This function has two operating modes:
  19.  
  20.     1. All dynamic parameters created in one pass using pipeline input to the function. This mode allows to create dynamic parameters en masse,
  21.     with one function call. There is no need to create and maintain custom RuntimeDefinedParameterDictionary.
  22.  
  23.     2. Dynamic parameters are created by separate function calls and added to the RuntimeDefinedParameterDictionary you created beforehand.
  24.     Then you output this RuntimeDefinedParameterDictionary to the pipeline. This allows more fine-grained control of the dynamic parameters,
  25.     with custom conditions and so on.
  26.  
  27. .NOTES
  28.     Credits to jrich523 and ramblingcookiemonster for their initial code and inspiration:
  29.         https://github.com/RamblingCookieMonster/PowerShell/blob/master/New-DynamicParam.ps1
  30.         http://ramblingcookiemonster.wordpress.com/2014/11/27/quick-hits-credentials-and-dynamic-parameters/
  31.         http://jrich523.wordpress.com/2013/05/30/powershell-simple-way-to-add-dynamic-parameters-to-advanced-function/
  32.  
  33.     Credit to BM for alias and type parameters and their handling
  34.  
  35. .PARAMETER Name
  36.     Name of the dynamic parameter
  37.  
  38. .PARAMETER Type
  39.     Type for the dynamic parameter.  Default is string
  40.  
  41. .PARAMETER Alias
  42.     If specified, one or more aliases to assign to the dynamic parameter
  43.  
  44. .PARAMETER Mandatory
  45.     If specified, set the Mandatory attribute for this dynamic parameter
  46.  
  47. .PARAMETER Position
  48.     If specified, set the Position attribute for this dynamic parameter
  49.  
  50. .PARAMETER HelpMessage
  51.     If specified, set the HelpMessage for this dynamic parameter
  52.  
  53. .PARAMETER DontShow
  54.     If specified, set the DontShow for this dynamic parameter.
  55.     This is the new PowerShell 4.0 attribute that hides parameter from tab-completion.
  56.     http://www.powershellmagazine.com/2013/07/29/pstip-hiding-parameters-from-tab-completion/
  57.  
  58. .PARAMETER ValueFromPipeline
  59.     If specified, set the ValueFromPipeline attribute for this dynamic parameter
  60.  
  61. .PARAMETER ValueFromPipelineByPropertyName
  62.     If specified, set the ValueFromPipelineByPropertyName attribute for this dynamic parameter
  63.  
  64. .PARAMETER ValueFromRemainingArguments
  65.     If specified, set the ValueFromRemainingArguments attribute for this dynamic parameter
  66.  
  67. .PARAMETER ParameterSetName
  68.     If specified, set the ParameterSet attribute for this dynamic parameter. By default parameter is added to all parameters sets.
  69.  
  70. .PARAMETER AllowNull
  71.     If specified, set the AllowNull attribute of this dynamic parameter
  72.  
  73. .PARAMETER AllowEmptyString
  74.     If specified, set the AllowEmptyString attribute of this dynamic parameter
  75.  
  76. .PARAMETER AllowEmptyCollection
  77.     If specified, set the AllowEmptyCollection attribute of this dynamic parameter
  78.  
  79. .PARAMETER ValidateNotNull
  80.     If specified, set the ValidateNotNull attribute of this dynamic parameter
  81.  
  82. .PARAMETER ValidateNotNullOrEmpty
  83.     If specified, set the ValidateNotNullOrEmpty attribute of this dynamic parameter
  84.  
  85. .PARAMETER ValidateRange
  86.     If specified, set the ValidateRange attribute of this dynamic parameter
  87.  
  88. .PARAMETER ValidateLength
  89.     If specified, set the ValidateLength attribute of this dynamic parameter
  90.  
  91. .PARAMETER ValidatePattern
  92.     If specified, set the ValidatePattern attribute of this dynamic parameter
  93.  
  94. .PARAMETER ValidateScript
  95.     If specified, set the ValidateScript attribute of this dynamic parameter
  96.  
  97. .PARAMETER ValidateSet
  98.     If specified, set the ValidateSet attribute of this dynamic parameter
  99.  
  100. .PARAMETER Dictionary
  101.     If specified, add resulting RuntimeDefinedParameter to an existing RuntimeDefinedParameterDictionary.
  102.     Appropriate for custom dynamic parameters creation.
  103.  
  104.     If not specified, create and return a RuntimeDefinedParameterDictionary
  105.     Aappropriate for a simple dynamic parameter creation.
  106.  
  107. .EXAMPLE
  108.     Create one dynamic parameter.
  109.  
  110.     This example illustrates the use of New-DynamicParameter to create a single dynamic parameter.
  111.     The Drive's parameter ValidateSet is populated with all available volumes on the computer for handy tab completion / intellisense.
  112.  
  113.     Usage: Get-FreeSpace -Drive <tab>
  114.  
  115.     function Get-FreeSpace
  116.     {
  117.         [CmdletBinding()]
  118.         Param()
  119.         DynamicParam
  120.         {
  121.             # Get drive names for ValidateSet attribute
  122.             $DriveList = ([System.IO.DriveInfo]::GetDrives()).Name
  123.  
  124.             # Create new dynamic parameter
  125.             New-DynamicParameter -Name Drive -ValidateSet $DriveList -Type ([array]) -Position 0 -Mandatory
  126.         }
  127.  
  128.         Process
  129.         {
  130.             # Dynamic parameters don't have corresponding variables created,
  131.             # you need to call New-DynamicParameter with CreateVariables switch to fix that.
  132.             New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
  133.  
  134.             $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object {$Drive -contains $_.Name}
  135.             $DriveInfo |
  136.                 ForEach-Object {
  137.                     if(!$_.TotalFreeSpace)
  138.                     {
  139.                         $FreePct = 0
  140.                     }
  141.                     else
  142.                     {
  143.                         $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2)
  144.                     }
  145.                     New-Object -TypeName psobject -Property @{
  146.                         Drive = $_.Name
  147.                         DriveType = $_.DriveType
  148.                         'Free(%)' = $FreePct
  149.                     }
  150.                 }
  151.         }
  152.     }
  153.  
  154. .EXAMPLE
  155.     Create several dynamic parameters not using custom RuntimeDefinedParameterDictionary (requires piping).
  156.  
  157.     In this example two dynamic parameters are created. Each parameter belongs to the different parameter set, so they are mutually exclusive.
  158.  
  159.     The Drive's parameter ValidateSet is populated with all available volumes on the computer.
  160.     The DriveType's parameter ValidateSet is populated with all available drive types.
  161.  
  162.     Usage: Get-FreeSpace -Drive <tab>
  163.         or
  164.     Usage: Get-FreeSpace -DriveType <tab>
  165.  
  166.     Parameters are defined in the array of hashtables, which is then piped through the New-Object to create PSObject and pass it to the New-DynamicParameter function.
  167.     Because of piping, New-DynamicParameter function is able to create all parameters at once, thus eliminating need for you to create and pass external RuntimeDefinedParameterDictionary to it.
  168.  
  169.     function Get-FreeSpace
  170.     {
  171.         [CmdletBinding()]
  172.         Param()
  173.         DynamicParam
  174.         {
  175.             # Array of hashtables that hold values for dynamic parameters
  176.             $DynamicParameters = @(
  177.                 @{
  178.                     Name = 'Drive'
  179.                     Type = [array]
  180.                     Position = 0
  181.                     Mandatory = $true
  182.                     ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name
  183.                     ParameterSetName = 'Drive'
  184.                 },
  185.                 @{
  186.                     Name = 'DriveType'
  187.                     Type = [array]
  188.                     Position = 0
  189.                     Mandatory = $true
  190.                     ValidateSet = [System.Enum]::GetNames('System.IO.DriveType')
  191.                     ParameterSetName = 'DriveType'
  192.                 }
  193.             )
  194.  
  195.             # Convert hashtables to PSObjects and pipe them to the New-DynamicParameter,
  196.             # to create all dynamic paramters in one function call.
  197.             $DynamicParameters | ForEach-Object {New-Object PSObject -Property $_} | New-DynamicParameter
  198.         }
  199.         Process
  200.         {
  201.             # Dynamic parameters don't have corresponding variables created,
  202.             # you need to call New-DynamicParameter with CreateVariables switch to fix that.
  203.             New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
  204.  
  205.             if($Drive)
  206.             {
  207.                 $Filter = {$Drive -contains $_.Name}
  208.             }
  209.             elseif($DriveType)
  210.             {
  211.                 $Filter =  {$DriveType -contains  $_.DriveType}
  212.             }
  213.  
  214.             $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter
  215.             $DriveInfo |
  216.                 ForEach-Object {
  217.                     if(!$_.TotalFreeSpace)
  218.                     {
  219.                         $FreePct = 0
  220.                     }
  221.                     else
  222.                     {
  223.                         $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2)
  224.                     }
  225.                     New-Object -TypeName psobject -Property @{
  226.                         Drive = $_.Name
  227.                         DriveType = $_.DriveType
  228.                         'Free(%)' = $FreePct
  229.                     }
  230.                 }
  231.         }
  232.     }
  233.  
  234. .EXAMPLE
  235.     Create several dynamic parameters, with multiple Parameter Sets, not using custom RuntimeDefinedParameterDictionary (requires piping).
  236.  
  237.     In this example three dynamic parameters are created. Two of the parameters are belong to the different parameter set, so they are mutually exclusive.
  238.     One of the parameters belongs to both parameter sets.
  239.  
  240.     The Drive's parameter ValidateSet is populated with all available volumes on the computer.
  241.     The DriveType's parameter ValidateSet is populated with all available drive types.
  242.     The DriveType's parameter ValidateSet is populated with all available drive types.
  243.     The Precision's parameter controls number of digits after decimal separator for Free Space percentage.
  244.  
  245.     Usage: Get-FreeSpace -Drive <tab> -Precision 2
  246.         or
  247.     Usage: Get-FreeSpace -DriveType <tab> -Precision 2
  248.  
  249.     Parameters are defined in the array of hashtables, which is then piped through the New-Object to create PSObject and pass it to the New-DynamicParameter function.
  250.     If parameter with the same name already exist in the RuntimeDefinedParameterDictionary, a new Parameter Set is added to it.
  251.     Because of piping, New-DynamicParameter function is able to create all parameters at once, thus eliminating need for you to create and pass external RuntimeDefinedParameterDictionary to it.
  252.  
  253.     function Get-FreeSpace
  254.     {
  255.         [CmdletBinding()]
  256.         Param()
  257.         DynamicParam
  258.         {
  259.             # Array of hashtables that hold values for dynamic parameters
  260.             $DynamicParameters = @(
  261.                 @{
  262.                     Name = 'Drive'
  263.                     Type = [array]
  264.                     Position = 0
  265.                     Mandatory = $true
  266.                     ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name
  267.                     ParameterSetName = 'Drive'
  268.                 },
  269.                 @{
  270.                     Name = 'DriveType'
  271.                     Type = [array]
  272.                     Position = 0
  273.                     Mandatory = $true
  274.                     ValidateSet = [System.Enum]::GetNames('System.IO.DriveType')
  275.                     ParameterSetName = 'DriveType'
  276.                 },
  277.                 @{
  278.                     Name = 'Precision'
  279.                     Type = [int]
  280.                     # This will add a Drive parameter set to the parameter
  281.                     Position = 1
  282.                     ParameterSetName = 'Drive'
  283.                 },
  284.                 @{
  285.                     Name = 'Precision'
  286.                     # Because the parameter already exits in the RuntimeDefinedParameterDictionary,
  287.                     # this will add a DriveType parameter set to the parameter.
  288.                     Position = 1
  289.                     ParameterSetName = 'DriveType'
  290.                 }
  291.             )
  292.  
  293.             # Convert hashtables to PSObjects and pipe them to the New-DynamicParameter,
  294.             # to create all dynamic paramters in one function call.
  295.             $DynamicParameters | ForEach-Object {New-Object PSObject -Property $_} | New-DynamicParameter
  296.         }
  297.         Process
  298.         {
  299.             # Dynamic parameters don't have corresponding variables created,
  300.             # you need to call New-DynamicParameter with CreateVariables switch to fix that.
  301.             New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
  302.  
  303.             if($Drive)
  304.             {
  305.                 $Filter = {$Drive -contains $_.Name}
  306.             }
  307.             elseif($DriveType)
  308.             {
  309.                 $Filter = {$DriveType -contains  $_.DriveType}
  310.             }
  311.  
  312.             if(!$Precision)
  313.             {
  314.                 $Precision = 2
  315.             }
  316.  
  317.             $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter
  318.             $DriveInfo |
  319.                 ForEach-Object {
  320.                     if(!$_.TotalFreeSpace)
  321.                     {
  322.                         $FreePct = 0
  323.                     }
  324.                     else
  325.                     {
  326.                         $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), $Precision)
  327.                     }
  328.                     New-Object -TypeName psobject -Property @{
  329.                         Drive = $_.Name
  330.                         DriveType = $_.DriveType
  331.                         'Free(%)' = $FreePct
  332.                     }
  333.                 }
  334.         }
  335.     }
  336.  
  337. .Example
  338.     Create dynamic parameters using custom dictionary.
  339.  
  340.     In case you need more control, use custom dictionary to precisely choose what dynamic parameters to create and when.
  341.     The example below will create DriveType dynamic parameter only if today is not a Friday:
  342.  
  343.     function Get-FreeSpace
  344.     {
  345.         [CmdletBinding()]
  346.         Param()
  347.         DynamicParam
  348.         {
  349.             $Drive = @{
  350.                 Name = 'Drive'
  351.                 Type = [array]
  352.                 Position = 0
  353.                 Mandatory = $true
  354.                 ValidateSet = ([System.IO.DriveInfo]::GetDrives()).Name
  355.                 ParameterSetName = 'Drive'
  356.             }
  357.  
  358.             $DriveType =  @{
  359.                 Name = 'DriveType'
  360.                 Type = [array]
  361.                 Position = 0
  362.                 Mandatory = $true
  363.                 ValidateSet = [System.Enum]::GetNames('System.IO.DriveType')
  364.                 ParameterSetName = 'DriveType'
  365.             }
  366.  
  367.             # Create dictionary
  368.             $DynamicParameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
  369.  
  370.             # Add new dynamic parameter to dictionary
  371.             New-DynamicParameter @Drive -Dictionary $DynamicParameters
  372.  
  373.             # Add another dynamic parameter to dictionary, only if today is not a Friday
  374.             if((Get-Date).DayOfWeek -ne [DayOfWeek]::Friday)
  375.             {
  376.                 New-DynamicParameter @DriveType -Dictionary $DynamicParameters
  377.             }
  378.  
  379.             # Return dictionary with dynamic parameters
  380.             $DynamicParameters
  381.         }
  382.         Process
  383.         {
  384.             # Dynamic parameters don't have corresponding variables created,
  385.             # you need to call New-DynamicParameter with CreateVariables switch to fix that.
  386.             New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
  387.  
  388.             if($Drive)
  389.             {
  390.                 $Filter = {$Drive -contains $_.Name}
  391.             }
  392.             elseif($DriveType)
  393.             {
  394.                 $Filter =  {$DriveType -contains  $_.DriveType}
  395.             }
  396.  
  397.             $DriveInfo = [System.IO.DriveInfo]::GetDrives() | Where-Object $Filter
  398.             $DriveInfo |
  399.                 ForEach-Object {
  400.                     if(!$_.TotalFreeSpace)
  401.                     {
  402.                         $FreePct = 0
  403.                     }
  404.                     else
  405.                     {
  406.                         $FreePct = [System.Math]::Round(($_.TotalSize / $_.TotalFreeSpace), 2)
  407.                     }
  408.                     New-Object -TypeName psobject -Property @{
  409.                         Drive = $_.Name
  410.                         DriveType = $_.DriveType
  411.                         'Free(%)' = $FreePct
  412.                     }
  413.                 }
  414.         }
  415.     }
  416. #>
  417. Function New-DynamicParameter {
  418.     [CmdletBinding(PositionalBinding = $false, DefaultParameterSetName = 'DynamicParameter')]
  419.     Param
  420.     (
  421.         [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  422.         [ValidateNotNullOrEmpty()]
  423.         [string]$Name,
  424.  
  425.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  426.         [System.Type]$Type = [int],
  427.  
  428.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  429.         [string[]]$Alias,
  430.  
  431.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  432.         [switch]$Mandatory,
  433.  
  434.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  435.         [int]$Position,
  436.  
  437.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  438.         [string]$HelpMessage,
  439.  
  440.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  441.         [switch]$DontShow,
  442.  
  443.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  444.         [switch]$ValueFromPipeline,
  445.  
  446.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  447.         [switch]$ValueFromPipelineByPropertyName,
  448.  
  449.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  450.         [switch]$ValueFromRemainingArguments,
  451.  
  452.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  453.         [string]$ParameterSetName = '__AllParameterSets',
  454.  
  455.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  456.         [switch]$AllowNull,
  457.  
  458.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  459.         [switch]$AllowEmptyString,
  460.  
  461.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  462.         [switch]$AllowEmptyCollection,
  463.  
  464.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  465.         [switch]$ValidateNotNull,
  466.  
  467.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  468.         [switch]$ValidateNotNullOrEmpty,
  469.  
  470.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  471.         [ValidateCount(2,2)]
  472.         [int[]]$ValidateCount,
  473.  
  474.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  475.         [ValidateCount(2,2)]
  476.         [int[]]$ValidateRange,
  477.  
  478.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  479.         [ValidateCount(2,2)]
  480.         [int[]]$ValidateLength,
  481.  
  482.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  483.         [ValidateNotNullOrEmpty()]
  484.         [string]$ValidatePattern,
  485.  
  486.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  487.         [ValidateNotNullOrEmpty()]
  488.         [scriptblock]$ValidateScript,
  489.  
  490.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  491.         [ValidateNotNullOrEmpty()]
  492.         [string[]]$ValidateSet,
  493.  
  494.         [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DynamicParameter')]
  495.         [ValidateNotNullOrEmpty()]
  496.         [ValidateScript({
  497.             if(!($_ -is [System.Management.Automation.RuntimeDefinedParameterDictionary]))
  498.             {
  499.                 Throw 'Dictionary must be a System.Management.Automation.RuntimeDefinedParameterDictionary object'
  500.             }
  501.             $true
  502.         })]
  503.         $Dictionary = $false,
  504.  
  505.         [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CreateVariables')]
  506.         [switch]$CreateVariables,
  507.  
  508.         [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CreateVariables')]
  509.         [ValidateNotNullOrEmpty()]
  510.         [ValidateScript({
  511.             # System.Management.Automation.PSBoundParametersDictionary is an internal sealed class,
  512.             # so one can't use PowerShell's '-is' operator to validate type.
  513.             if($_.GetType().Name -ne 'PSBoundParametersDictionary')
  514.             {
  515.                 Throw 'BoundParameters must be a System.Management.Automation.PSBoundParametersDictionary object'
  516.             }
  517.             $true
  518.         })]
  519.         $BoundParameters
  520.     )
  521.  
  522.     Begin
  523.     {
  524.         Write-Verbose 'Creating new dynamic parameters dictionary'
  525.         $InternalDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
  526.  
  527.         Write-Verbose 'Getting common parameters'
  528.         function _temp { [CmdletBinding()] Param() }
  529.         $CommonParameters = (Get-Command _temp).Parameters.Keys
  530.     }
  531.  
  532.     Process
  533.     {
  534.         if($CreateVariables)
  535.         {
  536.             Write-Verbose 'Creating variables from bound parameters'
  537.             Write-Debug 'Picking out bound parameters that are not in common parameters set'
  538.             $BoundKeys = $BoundParameters.Keys | Where-Object { $CommonParameters -notcontains $_ }
  539.  
  540.             foreach($Parameter in $BoundKeys)
  541.             {
  542.                 Write-Debug "Setting existing variable for dynamic parameter '$Parameter' with value '$($BoundParameters.$Parameter)'"
  543.                 Set-Variable -Name $Parameter -Value $BoundParameters.$Parameter -Scope 1 -Force
  544.             }
  545.         }
  546.         else
  547.         {
  548.             Write-Verbose 'Looking for cached bound parameters'
  549.             Write-Debug 'More info: https://beatcracker.wordpress.com/2014/12/18/psboundparameters-pipeline-and-the-valuefrompipelinebypropertyname-parameter-attribute'
  550.             $StaleKeys = @()
  551.             $StaleKeys = $PSBoundParameters.GetEnumerator() |
  552.                         ForEach-Object {
  553.                             if($_.Value.PSobject.Methods.Name -match '^Equals$')
  554.                             {
  555.                                 # If object has Equals, compare bound key and variable using it
  556.                                 if(!$_.Value.Equals((Get-Variable -Name $_.Key -ValueOnly -Scope 0)))
  557.                                 {
  558.                                     $_.Key
  559.                                 }
  560.                             }
  561.                             else
  562.                             {
  563.                                 # If object doesn't has Equals (e.g. $null), fallback to the PowerShell's -ne operator
  564.                                 if($_.Value -ne (Get-Variable -Name $_.Key -ValueOnly -Scope 0))
  565.                                 {
  566.                                     $_.Key
  567.                                 }
  568.                             }
  569.                         }
  570.             if($StaleKeys)
  571.             {
  572.                 [string[]]"Found $($StaleKeys.Count) cached bound parameters:" +  $StaleKeys | Write-Debug
  573.                 Write-Verbose 'Removing cached bound parameters'
  574.                 $StaleKeys | ForEach-Object {[void]$PSBoundParameters.Remove($_)}
  575.             }
  576.  
  577.             # Since we rely solely on $PSBoundParameters, we don't have access to default values for unbound parameters
  578.             Write-Verbose 'Looking for unbound parameters with default values'
  579.  
  580.             Write-Debug 'Getting unbound parameters list'
  581.             $UnboundParameters = (Get-Command -Name ($PSCmdlet.MyInvocation.InvocationName)).Parameters.GetEnumerator()  |
  582.                                         # Find parameters that are belong to the current parameter set
  583.                                         Where-Object { $_.Value.ParameterSets.Keys -contains $PsCmdlet.ParameterSetName } |
  584.                                             Select-Object -ExpandProperty Key |
  585.                                                 # Find unbound parameters in the current parameter set
  586.                                                 Where-Object { $PSBoundParameters.Keys -notcontains $_ }
  587.  
  588.             # Even if parameter is not bound, corresponding variable is created with parameter's default value (if specified)
  589.             Write-Debug 'Trying to get variables with default parameter value and create a new bound parameter''s'
  590.             $tmp = $null
  591.             foreach($Parameter in $UnboundParameters)
  592.             {
  593.                 $DefaultValue = Get-Variable -Name $Parameter -ValueOnly -Scope 0
  594.                 if(!$PSBoundParameters.TryGetValue($Parameter, [ref]$tmp) -and $DefaultValue)
  595.                 {
  596.                     $PSBoundParameters.$Parameter = $DefaultValue
  597.                     Write-Debug "Added new parameter '$Parameter' with value '$DefaultValue'"
  598.                 }
  599.             }
  600.  
  601.             if($Dictionary)
  602.             {
  603.                 Write-Verbose 'Using external dynamic parameter dictionary'
  604.                 $DPDictionary = $Dictionary
  605.             }
  606.             else
  607.             {
  608.                 Write-Verbose 'Using internal dynamic parameter dictionary'
  609.                 $DPDictionary = $InternalDictionary
  610.             }
  611.  
  612.             Write-Verbose "Creating new dynamic parameter: $Name"
  613.  
  614.             # Shortcut for getting local variables
  615.             $GetVar = {Get-Variable -Name $_ -ValueOnly -Scope 0}
  616.  
  617.             # Strings to match attributes and validation arguments
  618.             $AttributeRegex = '^(Mandatory|Position|ParameterSetName|DontShow|HelpMessage|ValueFromPipeline|ValueFromPipelineByPropertyName|ValueFromRemainingArguments)$'
  619.             $ValidationRegex = '^(AllowNull|AllowEmptyString|AllowEmptyCollection|ValidateCount|ValidateLength|ValidatePattern|ValidateRange|ValidateScript|ValidateSet|ValidateNotNull|ValidateNotNullOrEmpty)$'
  620.             $AliasRegex = '^Alias$'
  621.  
  622.             Write-Debug 'Creating new parameter''s attirubutes object'
  623.             $ParameterAttribute = New-Object -TypeName System.Management.Automation.ParameterAttribute
  624.  
  625.             Write-Debug 'Looping through the bound parameters, setting attirubutes...'
  626.             switch -regex ($PSBoundParameters.Keys)
  627.             {
  628.                 $AttributeRegex
  629.                 {
  630.                     Try
  631.                     {
  632.                         $ParameterAttribute.$_ = . $GetVar
  633.                         Write-Debug "Added new parameter attribute: $_"
  634.                     }
  635.                     Catch
  636.                     {
  637.                         $_
  638.                     }
  639.                     continue
  640.                 }
  641.             }
  642.  
  643.             if($DPDictionary.Keys -contains $Name)
  644.             {
  645.                 Write-Verbose "Dynamic parameter '$Name' already exist, adding another parameter set to it"
  646.                 $DPDictionary.$Name.Attributes.Add($ParameterAttribute)
  647.             }
  648.             else
  649.             {
  650.                 Write-Verbose "Dynamic parameter '$Name' doesn't exist, creating"
  651.  
  652.                 Write-Debug 'Creating new attribute collection object'
  653.                 $AttributeCollection = New-Object -TypeName Collections.ObjectModel.Collection[System.Attribute]
  654.  
  655.                 Write-Debug 'Looping through bound parameters, adding attributes'
  656.                 switch -regex ($PSBoundParameters.Keys)
  657.                 {
  658.                     $ValidationRegex
  659.                     {
  660.                         Try
  661.                         {
  662.                             $ParameterOptions = New-Object -TypeName "System.Management.Automation.${_}Attribute" -ArgumentList (. $GetVar) -ErrorAction Stop
  663.                             $AttributeCollection.Add($ParameterOptions)
  664.                             Write-Debug "Added attribute: $_"
  665.                         }
  666.                         Catch
  667.                         {
  668.                             $_
  669.                         }
  670.                         continue
  671.                     }
  672.  
  673.                     $AliasRegex
  674.                     {
  675.                         Try
  676.                         {
  677.                             $ParameterAlias = New-Object -TypeName System.Management.Automation.AliasAttribute -ArgumentList (. $GetVar) -ErrorAction Stop
  678.                             $AttributeCollection.Add($ParameterAlias)
  679.                             Write-Debug "Added alias: $_"
  680.                             continue
  681.                         }
  682.                         Catch
  683.                         {
  684.                             $_
  685.                         }
  686.                     }
  687.                 }
  688.  
  689.                 Write-Debug 'Adding attributes to the attribute collection'
  690.                 $AttributeCollection.Add($ParameterAttribute)
  691.  
  692.                 Write-Debug 'Finishing creation of the new dynamic parameter'
  693.                 $Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection)
  694.  
  695.                 Write-Debug 'Adding dynamic parameter to the dynamic parameter dictionary'
  696.                 $DPDictionary.Add($Name, $Parameter)
  697.             }
  698.         }
  699.     }
  700.  
  701.     End
  702.     {
  703.         if(!$CreateVariables -and !$Dictionary)
  704.         {
  705.             Write-Verbose 'Writing dynamic parameter dictionary to the pipeline'
  706.             $DPDictionary
  707.         }
  708.     }
  709. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement