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?
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).