Dynamic parameters in PowerShell executes before you know it

When creating script cmdlets in PowerShell you can use dynamic parameters to create some advanced parameters. A few months back I was playing around a bit with dynamic parameters to see how it works and I noticed that the logic for the dynamic parameters is executed as soon as the verb is written in the console within PowerShell ISE.

Dynamic parameters in PowerShell

Let's create a cmdlet to prove this theory. The cmdlet below will simply open a text file in the PowerShell ISE from the folder C:\temp\. The advanced parameter will show the available text files in the folder when using the console in PowerShell ISE.
Function Open-TextFile {
    [CmdletBinding()]
    Param()
    DynamicParam {
        $attributes = new-object System.Management.Automation.ParameterAttribute
        $attributes.ParameterSetName = "__AllParameterSets"
        $attributes.Mandatory = $true
        
        $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
        $attributeCollection.Add($attributes)
        
        $folder = 'C:\temp'
        $_Values = (Get-ChildItem -Path $folder -Name *.txt).PSChildName
                
        $ValidateSet = new-object System.Management.Automation.ValidateSetAttribute($_Values)
                
        $attributeCollection.Add($ValidateSet)
        
        
        $dynParam1 = new-object -Type System.Management.Automation.RuntimeDefinedParameter("File", [string], $attributeCollection)
        
        $paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
        $paramDictionary.Add("File", $dynParam1)
        return $paramDictionary
    }

    Process 
    {
        $file = $PSBoundParameters.file
        ise "$folder\$file"
    }
}
What if we add an extra line in there to add a new file in that folder when the dynamic parameter logic is executed, like this:
Function Open-TextFile {
    [CmdletBinding()]
    Param()
    DynamicParam {
        $attributes = new-object System.Management.Automation.ParameterAttribute
        $attributes.ParameterSetName = "__AllParameterSets"
        $attributes.Mandatory = $true
        
        $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
        $attributeCollection.Add($attributes)
        
        $folder = 'C:\temp'
        # write a timestamp to a file. This will be executed as soon as you write "Open-" in the console without having to complete the full cmdlet name.
        Get-Date | Out-File -FilePath "$folder\test.txt" -Append
        $_Values = (Get-ChildItem -Path $folder -Name *.txt).PSChildName
                
        $ValidateSet = new-object System.Management.Automation.ValidateSetAttribute($_Values)
                
        $attributeCollection.Add($ValidateSet)
        
        
        $dynParam1 = new-object -Type System.Management.Automation.RuntimeDefinedParameter("File", [string], $attributeCollection)
        
        $paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
        $paramDictionary.Add("File", $dynParam1)
        return $paramDictionary
    }

    Process 
    {
        $file = $PSBoundParameters.file
        ise "$folder\$file"
    }
}
Now load this cmdlet into memory and then write only "open-" in the console. Now check the folder c:\temp\ and you will find that a file has been created containing the timestamp for when the code was executed.

This means that the logic for dynamic parameters are executed at the same time as when the PowerShell ISE is trying to find which cmdlets are matching the verb you have written. I would have thought that the dynamic parameter logic would be executed when I have written the entire name of the cmdlet, but that is not the case.

No comments

Post a Comment