Blog Archives

PowerShell: Simple way to add dynamic parameters to advanced function


I’ve been working on a module for Nimble Storage and I’ve been creating dynamic parameters for some of the functions and I thought, why not just create a helper function for this? So I did, here it is with a simple example. The code is actually not too bad once you look through it, mostly just populating some objects and dumping them in the DynamicParam block.

Thanks Bart for the initial help! :)

Two important notes about this:
1) You have to supply Begin/Process/End (dont need all, but need at least 1)
2) It does not populate the variable as you’d expect it to, you have to pull it from $PSBoundParameters

Function New-DynamicParam {
param(
[string]
$Name,
[string[]]
$Options,
[switch]
$mandatory,
[string]
$SetName="__AllParameterSets",
[int]
$Position,
[switch]
$ValueFromPipelineByPropertyName,
[string]
$HelpMessage

)
    #param attributes   
    $ParamAttr = New-Object System.Management.Automation.ParameterAttribute
    $ParamAttr.ParameterSetName = $SetName
    if($mandatory){ $ParamAttr.Mandatory = $True }
    if($Position -ne $null){$ParamAttr.Position=$Position}
    if($ValueFromPipelineByPropertyName){$ParamAttr.ValueFromPipelineByPropertyName = $True}
    if($HelpMessage){$ParamAttr.HelpMessage = $HelpMessage}

    ##param validation set
    $ParamOptions = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList $options

    $AttributeCollection = New-Object 'Collections.ObjectModel.Collection[System.Attribute]' 
    $AttributeCollection.Add($ParamAttr)
    $AttributeCollection.Add($ParamOptions)

    $Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter `
    -ArgumentList @($Name, [string], $AttributeCollection)
            
    $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
    $Dictionary.Add($Name, $Parameter)
    $Dictionary
}

Here is an example of how you would use it.

function Show-Free
{
    [CmdletBinding()]
    Param()
    DynamicParam {
    New-DynamicParam -name Drive -options @(gwmi win32_volume |%{$_.driveletter}|sort) -Position 0 
    }
    begin{
    #have to manually populate
    $drive = $PSBoundParameters.drive
    }
    process{
    $vol = gwmi win32_volume -Filter "driveletter='$drive'"
    "{0:N2}% free on {1}" -f ($vol.Capacity / $vol.FreeSpace),$drive
    }
}

I’ve set this up to only work with strings, but if you look at the code there is actually nothing forcing you to use strings, just makes most sense for this.

Enjoy!

File to function / String to ScriptBlock


Someone asked a question in forum that got me thinking about PS1 files and functions. The problem was they couldn’t run PS1 files due to the security on the machine. Mostly they wanted to do this to learn, and I suspect it was just from running files they’ve download.

At any rate, this got me thinking, how could I import a PS1 in to my session as a function? Well after a little tinkering, I found a way.

###create ps1 file for test

Set-Content -path testadd.ps1 -value ‘
    param (
    [int] $variable1,
    [int] $variable2
    )
    $variable3=$variable1+$variable2;
    $variable3
    ‘

##create a function from our testadd.ps1 script

New-Item -Path function: -Name SimpleAdd -ItemType function -Value ([scriptblock]::create((gc .\testadd.ps1) -join [environment]::newline))

SimpleAdd 1 2

That’s all there is to it! Not really sure how useful this is, but was a neat little experiment.

Enjoy!