Named Parameters not working as expected
-
Monday, May 23, 2011 1:36 PMHi,Using PowerShell 2.0At start of script .\PsMyScript.ps1Param{[string]$p1,[string]$p2,[string]$p3}Call the script - works as expected..\PsMyScript.ps1 -p2 "two" -p3 "three" -p1 "one"Call the script - NOT working as expected.\PsMyScript.ps1 "one" "two" "three"The problem is that the parameters are still being populated even though Ididn't supply their names. I'd like to force the parameters to be NAMEDparameters, but I don't need them to be mandatory.
Answers
-
Tuesday, May 24, 2011 1:55 PM
You can do something like this in your script:
param(
$bad_param,
[string]$p1,
[string]$p2,
[string]$p3
)if ($bad_param){write-host "Bad parameter";exit}
Any unnamed parameter will get picked up by $bad_param.
[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
- Edited by mjolinor Tuesday, May 24, 2011 3:07 PM
- Proposed As Answer by jrich Thursday, May 26, 2011 12:53 PM
- Marked As Answer by Alan ZhuModerator Friday, May 27, 2011 3:25 AM
All Replies
-
Monday, May 23, 2011 1:59 PM
Try using - Position.
Param ( [parameter(Position=0)] [String[]] $p1 )
get-help about_Functions_Advanced_Parameters
-
Monday, May 23, 2011 2:50 PM"Kazun" wrote in messagenews:fc48f2fe-9e2a-4395-aff7-7954915439af@communitybridge.codeplex.com...> Try using - Position.>> Param ( [parameter(Position=0)] [String[]] $p1 )>> get-help about_Functions_Advanced_ParametersThanks, I did read about_Functions_Advanced_Parameters, but didn'tunderstand it.Are you saying to use [parameter(Position=0)] for all parameters? I thoughtit was forcing a positional parameter, which sounded like the opposite towhat I wanted...
-
Monday, May 23, 2011 2:57 PM
No for all:Param( [parameter(Position=0)] [string]$p1, [parameter(Position=1)] [string]$p2, [parameter(Position=2)] [string]$p3 )
-
Monday, May 23, 2011 3:30 PM"Kazun" wrote in messagenews:6f5c009f-0688-4b39-aabb-3dcb4218c064@communitybridge.codeplex.com...> No for all:> Param(> [parameter(Position=0)]> [string]$p1,> [parameter(Position=1)]> [string]$p2,> [parameter(Position=2)]> [string]$p3> )So it looks like I'm forcing them to be positional, but I'd like to be ableto call them in any order, as long as the names are correct. e.g..\PsMyScript.ps1 -p2 "two" -p3 "three" -p1 "one"
-
Monday, May 23, 2011 3:46 PM
Then show on a concrete example of what is not working?"Kazun" wrote in messagenews:6f5c009f-0688-4b39-aabb-3dcb4218c064@communitybridge.codeplex.com...> No for all:> Param(> [parameter(Position=0)]> [string]$p1,> [parameter(Position=1)]> [string]$p2,> [parameter(Position=2)]> [string]$p3> )So it looks like I'm forcing them to be positional, but I'd like to be ableto call them in any order, as long as the names are correct. e.g..\PsMyScript.ps1 -p2 "two" -p3 "three" -p1 "one" -
Tuesday, May 24, 2011 9:39 AMThanks for the help. The goal is to only set a parameter when it's name hasbeen specified on the command line. This doesn't seem to be working.#PsTest.ps1param([parameter(position=0)][string]$p1,[parameter(position=1)][string]$p2,[parameter(position=2)][string]$p3)write-host p1 : $p1write-host p2 : $p2write-host p3 : $p3Now call it with three unamed params.\PsTest.ps1 two one threeIn my test, the params will be populated, even though I didn't supply theirnames! I want to force the caller to use this notation..\PsTest.ps1 -p2 two -p1 one -p3 threeFurther to this, the documentation seems wrong. It statesabout_Functions_Advanced_ParametersPosition Named Argument"If this argument is NOT specified, the parameter name or its alias MUST beexplicitly specified when the parameter is set".This implies that there's no way the param can be populated unless you'venamed it?
-
Tuesday, May 24, 2011 11:04 AM
You may use old style as in the others language is parse $args.
Example for C++ - http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
-
Tuesday, May 24, 2011 12:20 PM"Kazun" wrote in messagenews:0b5ee9d4-3691-4059-aea2-1d11fbbed197@communitybridge.codeplex.com...> You may use old style as in the others language is parse $args.>> Example for C++ - http://msdn.microsoft.com/en-us/library/17w5ykft.aspxThanks, but I was hoping the new facilities in PowerShell 2.0 would haveeverything needed for accurate passing of parameters. No one has actuallyconfirmed whether my test script is behaving as expected, or whether thedocumentation is correct (see above).
-
Tuesday, May 24, 2011 1:02 PMModeratorWhy would you want to do that?
By nature all parameters are positional even if not explicitly declared as such.
This allows you to specify just the arguments (values will bound to the respective parameters by the order they were written on the command line).
You cannot disable positional parameter binding or force the command to accept only parameters that were specified by their names.
Can you clarify your needs?
Shay Levy [MVP]
PowerShay.com
PowerShell Toolbar -
Tuesday, May 24, 2011 1:04 PMfrom: get-help about_Functions_Advanced_Parameters<#Position Named ArgumentThe Position argument specifies the position of the parameter.If this argument is not specified, the parameter name or itsalias must be explicitly specified when the parameter is set.Also, if none of the parameters of a function have positions,the Windows PowerShell runtime assigns positions to each parameterbased on the order in which the parameters are received.#>That last sentence about the runtime assignment of positions iswhat is complicating creating the scenario of making all parametersto a script be named only.
-
Tuesday, May 24, 2011 1:15 PMYou can come close to requiring all parameters to be named,but apparently you are required to allow for at least onepositional parameter.Consider for example,param([parameter(Position=0)]$first, $a, $b);$first;$a;$bas the content of test.ps1Then you getC:..\WindowsPowerShell> test.ps1 0 1 2C:\Documents and Settings\Larry\My Documents\WindowsPowerShell\test.ps1: A positional parameter cannot be found that accepts argument '1'.C:..\WindowsPowerShell> test.ps1 0 -a 1 2C:\Documents and Settings\Larry\My Documents\WindowsPowerShell\test.ps1: A positional parameter cannot be found that accepts argument '2'.C:..\WindowsPowerShell> test.ps1 0 -a 1 -b 2012
-
Tuesday, May 24, 2011 1:25 PM"Shay Levi [MVP]" wrote in messagenews:175101bd-56b3-4f88-8ac8-dd4f8caf5061@communitybridge.codeplex.com...> Why would you want to do that?> By nature all parameters are positional even if not explicitly declared as> such.> This allows you to specify just the arguments (values will bound to the> respective parameters by the order they were written on the command line)..\PsMyScript.ps1 -p2 "two" -p1 "one" -p3 "three" # good.\PsMyScript.ps1 "two" "one" "three" # not good!Why do I want to force named parameters? Because it's a good way ofpreventing mistakes made by the caller. Microsoft use it in their owncommand line tools (Vista and above). e.g. the Tasklist command does notaccept positional parameters. In WSH you can do this. I'd be surprised ifit's not possible in PowerShell.> You cannot disable positional parameter binding or force the command to> accept only parameters that were specified by their names.>> Can you clarify your needs?> --------------------------------------------------------------------------------> Shay Levy [MVP]> PowerShay.com> PowerShell Toolbar
-
Tuesday, May 24, 2011 1:41 PMModerator
You'll have to implement it yourself, here's an example
function Test-NamedParameters
{
Param(
[string]$p1,
[string]$p2,
[string]$p3
)
$p = [System.Management.Automation.PsParser]::Tokenize($MyInvocation.Line,[ref]$null) | ? {$_.Type -match 'CommandParameter|CommandArgument'} | group type -NoElement
$hash = @{}
if($p) { $p | foreach {$hash[$_.Name]=$_.Count} }
# disable calling the function without any parameters
if(!$hash.CommandParameter -and !$hash.CommandArgument)
{
Write-Error "no parameters nor arguments were found"
return
}
if($hash['CommandParameter'] -ne $hash['CommandArgument'])
{
Write-Error "parameter count doesn't match argument count"
return
}
$p1
$p2
$p3
}
Test-NamedParameters #not allowed
Test-NamedParameters -p1 one two three #not allowed
Test-NamedParameters -p1 one -p2 two -p3 three #works
Test-NamedParameters -p2 two -p3 three -p1 one #works
Test-NamedParameters -p3 three #works
Shay Levy [MVP]
PowerShay.com
PowerShell Toolbar -
Tuesday, May 24, 2011 1:55 PM
You can do something like this in your script:
param(
$bad_param,
[string]$p1,
[string]$p2,
[string]$p3
)if ($bad_param){write-host "Bad parameter";exit}
Any unnamed parameter will get picked up by $bad_param.
[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "
- Edited by mjolinor Tuesday, May 24, 2011 3:07 PM
- Proposed As Answer by jrich Thursday, May 26, 2011 12:53 PM
- Marked As Answer by Alan ZhuModerator Friday, May 27, 2011 3:25 AM
-
Tuesday, May 24, 2011 2:43 PMGood idea (but did you mean to code parenthesis insteadof braces in the param block?)
-
Tuesday, May 24, 2011 2:58 PMDidn't mean to (copied from the OPs original post).
[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " " -
Tuesday, May 24, 2011 3:21 PM
-
Wednesday, May 25, 2011 7:52 PMmjolinor wrote:> Didn't mean to (copied from the OPs original post).Oops. Sorry about that. I'm used to typing curly brackets in PowerShell.> --------------------------------------------------------------------------------> [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775> 0645570").substring(($_*2),2))})-replace " "
-
Wednesday, May 25, 2011 10:35 PMThis reminds me of a PowerShell inconsistency.Parentheses and commas are used for both ways that are provided toassociate formal parameters with functions in PowerShell, yet when youcall that function, you do not use parentheses to wrap the list ofactual parameters. For example:function args_form1($a1, $a2){ '>'+$a1+'<';'>'+$a2+'<'}function args_form2{param($a1, $a2);'>'+$a1+'<';'>'+$a2+'<'}args_form1 1 2>1<>2<args_form1(1, 2)>1 2<><args_form2 1 2>1<>2<args_form2(1, 2)>1 2<><Perhapsfunction args_form1 $a1 $a2 { '>'+$a1+'<';'>'+$a2+'<'}function args_form2{param $a1 $a2; '>'+$a1+'<';'>'+$a2+'<'}would have been better as the starting point for the argumentdeclaration syntax. Oh well; it is what it is.On 5/25/2011 2:52 PM, Gerry Hickman wrote:> Oops. Sorry about that. I'm used to typing curly brackets in PowerShell.
-
Thursday, May 26, 2011 6:40 AMModerator
-
Wednesday, June 01, 2011 8:51 AM"mjolinor" wrote in messagenews:cf01c476-1831-4270-b462-ac7612240a56@communitybridge.codeplex.com...> You can do something like this in your script:>> param(> $bad_param,> [string]$p1,> [string]$p2,> [string]$p3> )>> if ($bad_param){write-host "Bad parameter";exit}>> Any unnamed parameter will get picked up by $bad_param.Thanks, this is a good work-around!
-
Monday, September 19, 2011 6:18 PMModerator
FYI
http://blogs.microsoft.co.il/blogs/scriptfanatic/archive/2011/09/19/how-to-disable-positional-parameter-binding-in-powershell.aspx
Shay Levy [MVP]
PowerShay.com
PowerShell Toolbar

