powershellsyntaxparameter-passingpositional-parameter

Powershell A positional parameter cannot be found that accepts argument '10'. While not even using a positional parameter


Note that the example code is contrived and is meant for illustration of the problem only.

I wanted to make a function in powershell to get some random numbers but i'm running into the very weird issue that when i dont use the position defining of the paramater i still get a error about it.

My code is:

function select-random {

  param(
    [Parameter(Position = 0, Mandatory)]
    [int]$min,
    [Parameter(Position = 1, Mandatory)]
    [int]$max
  )

  Get-Random $min $max

}

The error this script gets with the command: select-random 5 10

A positional parameter cannot be found that accepts argument '10'.

And with the command: select-random -min 5 -max 10

A positional parameter cannot be found that accepts argument '10'.`

The weirdest thing is that the ISE detects the manualy defined paramater in the tab menu.

Is my syntax wrong or is it a powershell bug but mainly how do i fix this?


Solution

  • Theo and JosefZ have provided the crucial pointers in the comments on the question:

    You're trying to pass both the $min and $max arguments positionally to Get-Random, yet Get-Random supports only one positional argument, namely for the -Maximum parameter.

    Thus, at least the $min value must be passed as a named argument, i.e. as -Minimum $min for your command to work syntactically. However, for symmetry and readability it is better to pass $max as a named argument as well:

    # Use *named* arguments.
    Get-Random -Minimum $min -Maximum $max
    

    How to determine a command's positional arguments:

    The about_Command_Syntax conceptual help topic describes the notation used in PowerShell's so-called syntax diagrams.

    To display the syntax diagrams (only), use Get-Command -Syntax (or pass -? / use Get-Help, which shows additional information):

    PS> & { Get-Command -Syntax $args[0] } Get-Random
    
    Get-Random [[-Maximum] <Object>] [-SetSeed <int>] [-Minimum <Object>] [-Count <int>] [<CommonParameters>]
    
    Get-Random [-InputObject] <Object[]> -Shuffle [-SetSeed <int>] [<CommonParameters>]
    
    Get-Random [-InputObject] <Object[]> [-SetSeed <int>] [-Count <int>] [<CommonParameters>]
    

    Only parameters whose names alone are enclosed in [...][1] are positional - e.g. [-Maximum] - and, if multiple ones are supported, they are listed in the order in which they must be passed on invocation.

    Note that each output line represents a separate parameter set (see about_Parameter_Sets), but since you're passing a minimum and maximum value, only the first one is of interest here:

    As you can see, only -Maximum is positional in the first parameter set, -Minimum and all the other parameters are not.


    Here's helper function Get-PositionalParameter, which makes it easier to determine a command's positional parameters:

    Function Get-PositionalParameter {
    <#
    .SYNOPSIS
    Outputs a given command's positional parameters, if any.
    #>
      param(
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [string] $Name
      )
      Set-StrictMode -Version 1; $ErrorActionPreference = 'Stop'
      # Resolve the name to a cmdlet first, if necessary
      $cmd = (Get-Command $Name)
      if ($cmd.ResolvedCommand) { $cmd = $cmd.ResolvedCommand }
    
      $cmd.ParameterSets | ForEach-Object {
        if ($posParams = $_.Parameters.Where( { $_.Position -ge 0 })) {
          [pscustomobject] @{
            PositionalParams = $posParams.Name
            ParameterSet     = $_.Name
          }
        }
      }
    }
    

    Applied to Get-Random:

    PS> Get-PositionalParameter Get-Random
    
    PositionalParams ParameterSet
    ---------------- ------------
    Maximum          RandomNumberParameterSet
    InputObject      ShuffleParameterSet
    InputObject      RandomListItemParameterSet
    

    Note that the parameter set names do not surface in the help topics and when you use Get-Command -Syntax, because they aren't really meant for public display, but their names are usually descriptive enough to infer their purpose.


    [1] Contrast this with the parameter specification as a whole being enclosed in [...] - e.g. [-Minimum <Object>] - which independently indicates that the parameter as a whole is optional (not mandatory, i.e. passing an argument is not required).