Public/Get-ADTBoundParametersAndDefaultValues.ps1
#--------------------------------------------------------------------------- # # MARK: Get-ADTBoundParametersAndDefaultValues # #--------------------------------------------------------------------------- function Get-ADTBoundParametersAndDefaultValues { <# .SYNOPSIS Returns a hashtable with the output of $PSBoundParameters and default-valued parameters for the given InvocationInfo. .DESCRIPTION This function processes the provided InvocationInfo and combines the results of $PSBoundParameters and default-valued parameters via the InvocationInfo's ScriptBlock AST (Abstract Syntax Tree). .PARAMETER Invocation The script or function's InvocationInfo ($MyInvocation) to process. .PARAMETER ParameterSetName The ParameterSetName to use as a filter against the Invocation's parameters. .PARAMETER HelpMessage The HelpMessage field to use as a filter against the Invocation's parameters. .PARAMETER Exclude One or more parameter names to exclude from the results. .INPUTS None You cannot pipe objects to this function. .OUTPUTS System.Collections.Generic.Dictionary[System.String, System.Object] Get-ADTBoundParametersAndDefaultValues returns a dictionary of the same base type as $PSBoundParameters for API consistency. .EXAMPLE Get-ADTBoundParametersAndDefaultValues -Invocation $MyInvocation Returns a $PSBoundParameters-compatible dictionary with the bound parameters and any default values. .NOTES An active ADT session is NOT required to use this function. Tags: psadt Website: https://psappdeploytoolkit.com Copyright: (C) 2024 PSAppDeployToolkit Team (Sean Lillis, Dan Cunningham, Muhammad Mashwani, Mitch Richters, Dan Gough). License: https://opensource.org/license/lgpl-3-0 .LINK https://psappdeploytoolkit.com #> [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ParameterSetName', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'HelpMessage', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Exclude', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = "This function is appropriately named and we don't need PSScriptAnalyzer telling us otherwise.")] [CmdletBinding()] [OutputType([System.Collections.Generic.Dictionary[System.String, System.Object]])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.InvocationInfo]$Invocation, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.String]$ParameterSetName, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.String]$HelpMessage, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.String[]]$Exclude ) begin { # Initialize function. Initialize-ADTFunction -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState # Internal function for testing parameter attributes. function Test-NamedAttributeArgumentAst { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Argument', Justification = "This parameter is used within delegates that PSScriptAnalyzer has no visibility of. See https://github.com/PowerShell/PSScriptAnalyzer/issues/1472 for more details.")] [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.ParameterAst]$Parameter, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String]$Argument, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String]$Value ) # Test whether we have AttributeAst objects. if (!($attributes = $Parameter.Attributes | & { process { if ($_ -is [System.Management.Automation.Language.AttributeAst]) { return $_ } } })) { return $false } # Test whether we have NamedAttributeArgumentAst objects. if (!($namedArguments = $attributes.NamedArguments | & { process { if ($_.ArgumentName.Equals($Argument)) { return $_ } } })) { return $false } # Test whether any NamedAttributeArgumentAst objects match our value. return $namedArguments.Argument.Value.Contains($Value) } } process { try { try { # Get the parameters from the provided invocation. This can vary between simple/advanced functions and scripts. $parameters = if ($Invocation.MyCommand.ScriptBlock.Ast -is [System.Management.Automation.Language.FunctionDefinitionAst]) { # Test whether this is a simple or advanced function. if ($Invocation.MyCommand.ScriptBlock.Ast.Parameters -and $Invocation.MyCommand.ScriptBlock.Ast.Parameters.Count) { $Invocation.MyCommand.ScriptBlock.Ast.Parameters } elseif ($Invocation.MyCommand.ScriptBlock.Ast.Body.ParamBlock -and $Invocation.MyCommand.ScriptBlock.Ast.Body.ParamBlock.Parameters.Count) { $Invocation.MyCommand.ScriptBlock.Ast.Body.ParamBlock.Parameters } } elseif ($Invocation.MyCommand.ScriptBlock.Ast.ParamBlock -and $Invocation.MyCommand.ScriptBlock.Ast.ParamBlock.Parameters.Count) { $Invocation.MyCommand.ScriptBlock.Ast.ParamBlock.Parameters } # Throw if we don't have any parameters at all. if (!$parameters -or !$parameters.Count) { $naerParams = @{ Exception = [System.InvalidOperationException]::new("Unable to find parameters within the provided invocation's scriptblock AST.") Category = [System.Management.Automation.ErrorCategory]::InvalidResult ErrorId = 'InvocationParametersNotFound' TargetObject = $Invocation.MyCommand.ScriptBlock.Ast RecommendedAction = "Please verify your function or script parameter configuration and try again." } throw (New-ADTErrorRecord @naerParams) } # Open dictionary to store all params and their values to return. $obj = [System.Collections.Generic.Dictionary[System.String, System.Object]]::new() # Inject our already bound parameters into above object. $Invocation.BoundParameters.GetEnumerator() | & { process { # Filter out excluded values. if (!$Exclude -or !$Exclude.Contains($_.Key)) { $obj.Add($_.Key, $_.Value) } } } # Build out the dictionary for returning. $parameters | & { process { # Filter out parameters without a default value. if ($null -eq $_.DefaultValue) { return } # Filter out parameters already bound. if ($obj.ContainsKey($_.Name.VariablePath.UserPath)) { return } # Filter out excluded values. if ($Exclude -and $Exclude.Contains($_.Name.VariablePath.UserPath)) { return } # Filter out values based on the specified parameter set. if ($ParameterSetName -and !(Test-NamedAttributeArgumentAst -Parameter $_ -Argument ParameterSetName -Value $ParameterSetName)) { return } # Filter out values based on the specified help message. if ($HelpMessage -and !(Test-NamedAttributeArgumentAst -Parameter $_ -Argument HelpMessage -Value $HelpMessage)) { return } # Add the parameter and its value. $obj.Add($_.Name.VariablePath.UserPath, $_.DefaultValue.SafeGetValue()) } } # Return dictionary to the caller, even if it's empty. return $obj } catch { # Re-writing the ErrorRecord with Write-Error ensures the correct PositionMessage is used. Write-Error -ErrorRecord $_ } } catch { # Process the caught error, log it and throw depending on the specified ErrorAction. Invoke-ADTFunctionErrorHandler -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState -ErrorRecord $_ } } end { # Finalize function. Complete-ADTFunction -Cmdlet $PSCmdlet } } |