Is it possible to reuse the "param" block for several functions?

Suppose I have a script with several functions taking the same parameters, in the same positions and with the same types and restrictions, like this:

function Verb1-MyValue { [CmdletBinding()] param ( [parameter(Mandatory = $true)][String]$Param1, [parameter(Mandatory = $true)][String]$Param2, [ValidateSet("Value1","Value2")][String]$Param3 = "Value1" ) # code ... } function Verb2-MyValue { [CmdletBinding()] param ( [parameter(Mandatory = $true)][String]$Param1, [parameter(Mandatory = $true)][String]$Param2, [ValidateSet("Value1","Value2")][String]$Param3 = "Value1" ) # code ... } # and so on ... 

I wanted to split the param block with all the functions in order to avoid potential problems (they should be the same for everyone) and avoid redundancy.

Is there a way in PowerShell to split a param block into multiple functions in the same script? If not, are there any alternatives to it?

+7
parameters powershell
source share
2 answers

If you are able, I would recommend going with the β€œC # project, which builds the PowerShell module. There are various advantages depending on your situation, including:

  • Security at compile time. I know that some developers would prefer compiled / strongly typed languages ​​due to extra security
  • Easier to write automated tests. This may be controversial, but in my opinion having libraries like nUnit and other testing structures are a huge plus.
  • Knowledge of languages. I came across many who are familiar with C #, but not powershell, and therefore they are a struggle.

To get started, I found in this article . Basically, he says, to add a link to System.Management.Automation.dll to your project, and then a very simple cmdlet would look like this:

 using System; using System.Collection.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Management.Automation; namespace MyModule { [Cmdlet(VerbsCommon.Get, "Saluation")] public class GetSaluation : PSCmdlet { private string[] nameCollection; [Parameter( Mandatory = true, ValueFromPipelineByPropertyName = true, ValueFromPipelin = true, Position = 0, HelpMessage = "Name to get salutation for." )] [Alias("Person", "FirstName")] public string[] Name { get { return nameCollection;} set { nameCollection = value;} } protected override void BeginProcessing() { base.BeginProcessing(); } protected override void ProcessRecord() { foreach (string name in nameCollection) { WriteVerbose("Creating salutation for " + name); string salutation = "Hello, " + name; WriteObject(salutation); } } protected override void EndProcessing() { base.EndProcessing(); } } 

Then, to use this module, open a command prompt, go to where your dll is built, and use the Import-Module cmdlet.

And then for your specific question ( How to reuse parameter pairs with different cmdlets? ), You can have a base cmdlet that defines parameters, and all cmdlets that you want to write can inherit from the base class.

+3
source share

I would recommend using Travis's suggestion and moving on to a compiled cmdlet. You asked in one of your comments if this was possible only with a script, so I will try to give an example of this. Advanced functions support the creation of dynamic parameters, and you can combine this feature with the Get-Command cmdlet to create dynamic versions of the specified command parameters:

 function GetDynamicParamDictionary { [CmdletBinding()] param( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] [string] $CommandName ) begin { # Get a list of params that should be ignored (they're common to all advanced functions) $CommonParameterNames = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([type] [System.Management.Automation.Internal.CommonParameters]) | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name } process { # Create the dictionary that this scriptblock will return: $DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Convert to object array and get rid of Common params: (Get-Command $CommandName | select -exp Parameters).GetEnumerator() | Where-Object { $CommonParameterNames -notcontains $_.Key } | ForEach-Object { $DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter ( $_.Key, $_.Value.ParameterType, $_.Value.Attributes ) $DynParamDictionary.Add($_.Key, $DynamicParameter) } # Return the dynamic parameters $DynParamDictionary } } function TestFunction { # Create some dummy params param( [string] $StringParam, [switch] $Switch1, [switch] $Switch2, [int] $IntParam ) } function MimicTestFunction { [CmdletBinding()] # Empty param block (you could add extra params here) param() # Mimic TestFunction parameters dynamicparam { GetDynamicParamDictionary TestFunction } process { $PSBoundParameters } } function MimicGetChildItem { [CmdletBinding()] param() dynamicparam { GetDynamicParamDictionary Get-ChildItem } process { $PSBoundParameters } } 

This should work, unless the reference command also has dynamic parameters.

+2
source share

All Articles