Skip to content

Instantly share code, notes, and snippets.

@joeypiccola
Last active January 25, 2024 01:40
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joeypiccola/75cd1f4fd5c2e5f429d7dc580ce6b420 to your computer and use it in GitHub Desktop.
Save joeypiccola/75cd1f4fd5c2e5f429d7dc580ce6b420 to your computer and use it in GitHub Desktop.
sample powershell function with multiple dynamic parameters
Function New-VMDeploy {
[CmdletBinding()]
Param()
DynamicParam {
# Set the dynamic parameters' name
$ParamName_portgroup = 'PortGroup'
# Create the collection of attributes
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
# Create and set the parameters' attributes
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
$ParameterAttribute.Position = 1
# Add the attributes to the attributes collection
$AttributeCollection.Add($ParameterAttribute)
# Create the dictionary
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
# Generate and set the ValidateSet
$arrSet = (Get-VDPortgroup | ?{$_.name -like "*VLAN*"}).name
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
# Add the ValidateSet to the attributes collection
$AttributeCollection.Add($ValidateSetAttribute)
# Create and return the dynamic parameter
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_portgroup, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParamName_portgroup, $RuntimeParameter)
# Set the dynamic parameters' name
$ParamName_datastore = 'Datastore'
# Create the collection of attributes
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
# Create and set the parameters' attributes
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
$ParameterAttribute.Position = 2
# Add the attributes to the attributes collection
$AttributeCollection.Add($ParameterAttribute)
# Generate and set the ValidateSet
$arrSet = (Get-Datastore).name
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
# Add the ValidateSet to the attributes collection
$AttributeCollection.Add($ValidateSetAttribute)
# Create and return the dynamic parameter
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_datastore, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParamName_datastore, $RuntimeParameter)
return $RuntimeParameterDictionary
}
begin{}
process {
$portgroup = $PsBoundParameters[$ParamName_portgroup]
$datastore = $PsBoundParameters[$ParamName_datastore]
}
end {}
}
@nguyenl95
Copy link

nguyenl95 commented Dec 1, 2017

This worked great, I tried Register-ArgumentCompleter, ArgumentCompleter but those seems working only on ISE.

@CrazyJDrone
Copy link

This was the golden ticket for my custom VM deployment function! I no longer have to maintain a static list inside the parameter's validateset for hundreds of VM templates, networks, portgroups, etc.

Setting the ParameterAttribute.Postition = 0 on all the dynamic params allows intelisense to work (not setting will break intelisense).

There is also considerable lag when pulling info from vCenter (we have a big environment) so I made a scheduled task to keep the info in simple txt files that the function can quickly read from. I may switch that over to a SQL DB later.

Copy link

ghost commented Jan 25, 2024

Hey Joey,

This code helped me a lot. I tried to solve the slow tab completion when enumerating information via Microsoft Graph, like getting the displayname for 3000+ users.

When the variables $TenantId, $ApplicationClientId and $CertificateThumbprint are set with the correct values, then the variable $FilterUserName will be available. I still search for a better solution. I saw that when the variable, like '$TabCompletionFunctionGetMgUsers=EnumerateWithPaging -Data ((Get-MgUser -All -Property DisplayName).DisplayName)' is set, that each time I use the tab completion it first executes the command (Get-MgUser -All...).
If hope you have a solution for this problem, like that DynamicParam only executes the variable once...this is for now the best that I could do...

[CmdLetBinding(DefaultParameterSetName="Default",
SupportsPaging
)]

Param (
[Parameter( ParameterSetName = "Default",Position = 0 , Mandatory )]$TenantId,
[Parameter( ParameterSetName = "Default",Position = 1 , Mandatory )]$ApplicationId,
[Parameter( ParameterSetName = "Default",Position = 2 , Mandatory )]$CertificateThumbprint
)

DynamicParam {

Function EnumerateWithPaging {
    Param (
      $Data 
    )
    Begin {
    }
    Process {
    }
    End{
      If ( $Data.count -Gt 0 ) {
        $First = $PSCmdlet.PagingParameters.Skip
        $Last = $First + 
        [Math]::Min( $PSCmdlet.PagingParameters.First, $Data.Count - $PSCmdlet.PagingParameters.Skip ) - 1    
        If( $Last -Le 0 ) { $Data = $Null } Else { $Data = $Data[$First..$last]
        Write-Output $Data
        }
      }
      If ( $PSCmdlet.PagingParameters.IncludeTotalCount ) {
        [double]$Accuracy = 1.0
        $PSCmdlet.PagingParameters.NewTotalCount( $Data.count , $Accuracy )
      }
    }
}

Function ConnectMgGraph {
  Try {
    Connect-MgGraph -TenantId $TenantId -ApplicationId $ApplicationClientId -CertificateThumbprint $CertificateThumbprint -ClientTimeout 120 -NoWelcome -ErrorAction Stop
  } Catch {
    EXIT
  }
}

ConnectMgGraph

  # TabCompletion GetMgUsers parameters
  $TabCompletionNameGetMgUsers='FilterUserName'
  $TabCompletionFunctionGetMgUsers=EnumerateWithPaging -Data ((Get-MgUser -All -Property DisplayName).DisplayName)
  $TabCompletionPositionGetMgusers=3
  $TabCompletionMandatoryGetMgusers=$False
  $TabCompletionTypeGetMgUsers=[String]
  $TabCompletionParameterSetNameGetMgusers='__AllParameterSets'

  # Add additional TabCompletion parameters block here... (copy from above, adjust)

  # Begin TabCompletion
  $RuntimeParameterDictionary=New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

  # TabCompletion GetMgUsers add to dictionary
  $A=New-Object System.Collections.ObjectModel.Collection[System.Attribute]
  $P=New-Object System.Management.Automation.ParameterAttribute
  $P.Mandatory=$TabCompletionMandatoryGetMgUsers
  $P.ParameterSetName=$TabCompletionParameterSetNameGetMgusers
  $P.Position=$TabCompletionPositionGetMgUsers
  $A.Add($P)
  $V=New-Object System.Management.Automation.ValidateSetAttribute($TabCompletionFunctionGetMgUsers)
  $A.Add($V)
  $R=New-Object System.Management.Automation.RuntimeDefinedParameter($TabCompletionNameGetMgUsers,$TabCompletionTypeGetMgUsers,$A)
  $RuntimeParameterDictionary.Add($TabCompletionNameGetMgUsers,$R)

  # Add additional TabCompletion dictionary preparation here... (copy from above, adjust)

  # End TabCompletion
  Return $RuntimeParameterDictionary

}

Begin {}
Process{}
End{}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment