Pass MANY parameters to a function

Welcome Forums General PowerShell Q&A Pass MANY parameters to a function

This topic contains 9 replies, has 5 voices, and was last updated by

 
Participant
1 week ago.

  • Author
    Posts
  • #128038

    Participant
    Points: -9
    Rank: Member

    Has anyone found a way to pass 100+ arguments to a function?   This is crazy right!

    I have one high level function that determines what you want to do (taskA , taskB, taskC, taskD..etc).  Based on which task you pick there will be a set of required arguments.   So that means the high level function would need to take in ALL the possible arguments that could be needed in taskA, taskB, taskC, taskD, etc.    Has anyone come up with any tricks to do this easily without programming in a param set with 100+ args?

    Thoughts on how to do this better?

  • #128058

    Participant
    Points: 275
    Helping Hand
    Rank: Contributor

    By the sound of it, you need to break the function up into more than one function, or you could simply have it take "task parameters" as a hashtable and pass that in as a single argument.

    Your function will still need to validate the arguments, but it'll likely be simpler than doing explicit parameter sets. I would probably advise that it looks at the .Keys of the hashtable that it receives against a predefined list of required / permitted keys for the associated task. You could potentially have the tasks be arranged in a hashtable where each task name (key) maps to an array of parameter names, so you can lookup the required parameters by the task name.

  • #128065

    Participant
    Points: 76
    Rank: Member

    You can use parameter sets, so that for task A, the function user will need to pass parameters for parameter set 1, for task B user sends parameters for parameter set 2, ...

    That link is not very clear, here's an example of parameter sets:

    
    function Order-Something {
    param(
    
    [Parameter(Mandatory,ParameterSetName = 'OrderACar')]
    [Int]$NumberOfDoors,
    [Parameter(Mandatory,ParameterSetName = 'OrderACar')]
    [String]$Color,
    
    [Parameter(Mandatory,ParameterSetName = 'OrderAShirt')]
    [Int]$Count,
    [Parameter(Mandatory,ParameterSetName = 'OrderAShirt')]
    [String]$Fabric
    
    )
    
    if ($PSBoundParameters.ContainsKey('NumberOfDoors')) {
    "You ordered a '$Color' 'Car', with '$NumberOfDoors' doors"
    
    } elseif ($PSBoundParameters.ContainsKey('Fabric')) {
    "You ordered '$Count' '$Fabric' 'Shirt(s)'"
    } else {
    'huh!!??'
    }
    
    }
    
    

    Example use and output:

    
    PS Z:\scripts> Order-Something -NumberofDoors 4 -color red
    You ordered a 'red' 'Car', with '4' doors
    
    PS Z:\scripts> Order-Something -Count 3 -Fabric Cotton
    You ordered '3' 'Cotton' 'Shirt(s)'
    
    
  • #128070

    Participant
    Points: 6
    Rank: Member

    I am new to PowerShell so this might be a really stupid answer, but couldn't you just put all of the parameters into an array and pass the array as a single parameter?

    I am currently doing just that and I am passing it from AutoIT code into PowerShell code.  I don't have hundreds of values in the array(s), but I am still passing X number of values as a single parameter.

    Being totally new to PowerBuilder, it took me a bit to get it to work, but in the end it worked by defining the parameters as:

    [Parameter(Mandatory=$False)]
    [string[]] $exclusions=@(),
    [Parameter(Mandatory=$False)]
    [string[]] $inclusions=@(),

    And then calling the .ps1 script with the -Command parameter instead of the -File parameter (but that's a command line thing out in AutoIT).

    Again, this may be the totally wrong answer.  Good luck

  • #128074

    Participant
    Points: 275
    Helping Hand
    Rank: Contributor

    You absolutely could pass many arguments as an array, but it depends. If the order / name of parameters is critically important and you need to be able to access them by name, I'd stick with a hashtable. An array of 20 numbers is very hard to read and impossible to really figure out just from reading the code, you'd constantly be having to reference a cheatsheet of which index maps to which argument to keep it straight. Surefire way to buggy and unmaintainable code.

    Hashtables are much easier to work with in an instance like that.

     

  • #128077

    Participant
    Points: 6
    Rank: Member

    Joel,

    Thank you for the hashtable suggestion!!  As I said, I am knew to PowerShell.  You got me to go look up hashtables.  As my absolute favorite language (and best known language) is Python, I have a love for dictionaries.  HashTables look like a good start toward that!!

    Again, thanks!!

    • #128091

      Participant
      Points: 275
      Helping Hand
      Rank: Contributor

      No worries! Hashtables are essentially lightweight dictionaries, and PowerShell has some lovely native expression syntax for hashtables specifically, which makes them very easy to work with for PS scripting.

      If you need any other pointers or just something fun to mess around with, you might find some use in my koans. 🙂

    • #128124

      Participant
      Points: 76
      Rank: Member

      Joel,
      I'm trying the koans, the 'path thus far' progress bar is breaking:

          Welcome, seeker of enlightenment.
          Please wait a moment while we examine your karma...
      
      Describing 'Equality' has damaged your karma.
      
          You have not yet reached enlightenment.
      
          The answers you seek...
      
      Expected '__', but got 3.
      
          Please meditate on the following code:
      
      [It] expects you to fill in values
      at , C:\Users\Samb\PSKoans\Foundations\AboutAssertions.Koans.ps1: line 32
      32:         1 + 2 | Should -Be __
      
          Choosing to raise a goose in a bottle,
          How will you get it out once it is grown?
      
          Your path thus far:
      
      Specified argument was out of the range of valid values.
      Parameter name: times
      At D:\Sam\Docs\WindowsPowerShell\Modules\PSKoans\0.41.0\Private\Write-MeditationPrompt.ps1:138 char:20
      +                 "$([char]0x2015)" * ($ProgressWidth - $PortionDone)
      +                    ~~~~~~~~~~~~
          + CategoryInfo          : OperationStopped: (:) [], ArgumentOutOfRangeException
          + FullyQualifiedErrorId : System.ArgumentOutOfRangeException
       
      Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argument list..
      At D:\Sam\Docs\WindowsPowerShell\Modules\PSKoans\0.41.0\Private\Write-MeditationPrompt.ps1:139 char:17
      +                 $ProgressAmount
      +                 ~~~~~~~~~~~~~~~
          + CategoryInfo          : InvalidOperation: ( [{0}{1}] {2}:String) [], RuntimeException
          + FullyQualifiedErrorId : FormatError
       
      
      You may run 'rake -Meditate' to begin your meditation.
      
    • #128125

      Participant
      Points: 6
      Rank: Member

      Joel,

      Darn. My work blocks your koans link 🙁  I'll have to try to get to it from home.

      Thanks,

  • #128163

    Participant
    Points: 832
    Helping Hand
    Rank: Major Contributor

    @nakore53 , I have some crazy method using DynamiParameters.

    You can have a json configuration of available actions and its parameter details. Then Read the json and have the parameters dynamically created for each.

    [
        {
            "Action":  "FindLenth",
            "Parameter":  {
                              "Name":  "Item",
                              "Type":  "string",
                              "Mandatory" : "True"
                          }
        },
        {
            "Action":  "AddNumber",
            "Parameter":  [
                          {
                              "Name":  "Number1",
                              "Type":  "int",
                              "Mandatory" : "True",
                              "AllowedValues" : ["1","5"]
                          },
                          {
                            "Name":  "Number2",
                            "Type":  "int",
                            "Mandatory" : "True",
                            "AllowedValues" : ["2","3"]
                          }
                        ]
        }
    ]
    
    Function CreateDynamicParam{
    
        Param(
            [Switch]$Mandatory,
            [String]$Name,
            [String]$HelpMessage = 'No Help Message',
            [String]$ParameterSetName,
            [Type]$Type,
            [Object]$ParameterDictionary,
            [Array]$AllowedValues,
            [Switch]$AllowNull,
            [Switch]$AllowEmptingSring
        )
    
        $ParamAttribute             = New-Object -TypeName System.Management.Automation.ParameterAttribute
        $ParamAttribute.Mandatory   = $Mandatory.IsPresent
        $ParamAttribute.HelpMessage = $HelpMessage
        $AttributeCollection        = New-Object -TypeName System.Collections.ObjectModel.Collection[System.Attribute]
        if( $AllowedValues ){
            $ValidateSetAttteribute     = New-Object -TypeName System.Management.Automation.ValidateSetAttribute -ArgumentList $AllowedValues
            $AttributeCollection.Add( $ValidateSetAttteribute ) | Out-Null
        }
    
        if( $AllowNull ){
            $AttributeCollection.Add( [System.Management.Automation.AllowNullAttribute]::new() ) | Out-Null
        }
    
        if( $AllowEmptingSring ){
            $AttributeCollection.Add( [System.Management.Automation.AllowEmptyStringAttribute]::new() ) | Out-Null
        }
    
    
        $AttributeCollection.Add( $ParamAttribute ) | Out-Null
    
    
        $Param                      = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter($Name, $Type, $AttributeCollection)
        $ParameterDictionary.Add($Name,$Param) | Out-Null
        return $ParameterDictionary
    
    }
    
    function Add-Number {
        Param(
            $Number1,
            $number2
        )
    
        $Number1 + $Number2
    }
    
    Function TestFunction {
        [CMDletBinding()]
        Param(
            [string]$Action
        )
        DynamicParam{
            $ParameterDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
            $AvailableAction = Get-Content -Path C:\temp\Actionconfig.json | ConvertFrom-Json
            $ActionConfig    = $AvailableAction | Where-Object -FilterScript {$_.Action -eq $Action}
            if($Null -eq $ActionConfig){
                throw "Invalid Action mentioned, Supported actions are $S"
            }
            Foreach($Item in $ActionConfig.Parameter){
                $Name = $Item.Name
                $Mandatory = ($Item.Mandatory -as [bool])
                $Type = ($Item.Type -as [Type])
                $ParameterDictionary = CreateDynamicParam -Name $Name -Mandatory:$Mandatory -Type $Type -ParameterDictionary $ParameterDictionary
    
            }
            return $ParameterDictionary
        }
        Process{
    
            If($Action -eq 'AddNumber')
            {
                Add-Number -Number1 $PSBoundParameters.Number1 -Number2 $PSBoundParameters.Number2
            }
        }
    }
    
    TestFunction -Action AddNumber
    

You must be logged in to reply to this topic.