5

I would like to create a Powershell script that takes parameters in the standard Linux style, i.e., --my-param, with a leading --. I thought this might be possible using the alias parameter attribute, as in

Param (
    [parameter(Mandatory=$true)]
    [alias("-my-param","p")]
    [String]
    $param
)

What I hoped with this was that the call

c:\src\ps\params.ps1 --my-param "x"

would be recognized as referring to the alias -my-param. Unfortunately, what I get is

C:\src\ps\params.ps1 : A positional parameter cannot be found that accepts argument 'x'.
At line:1 char:21
+ c:\src\ps\params.ps1 <<<<  --my-param1 "x"
    + CategoryInfo          : InvalidArgument: (:) [params.ps1], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,params.ps1

On the other hand, using the alias my-param in this lets me call the script with -my-param. Is there a way of specifying parameter names with leading -- in Powershell?

Permaquid
  • 1,950
  • 1
  • 14
  • 15
  • 3
    What problem are you trying to solve? If you want a shell that behaves like a Linux shell, install Cygwin or some other Unix shell that's been ported to Windows? Otherwise, stick with the conventions of PowerShell or you'll risk confusing people who are familiar with PowerShell. IOW, stick with the idioms of the environment, don't attempt to graft the idioms of other environments onto it. – alroc Sep 21 '13 at 17:59
  • 1
    possible duplicate of [Powershell command line parameters and '--'](http://stackoverflow.com/questions/15780174/powershell-command-line-parameters-and) – alroc Sep 21 '13 at 18:01
  • @alroc Totally different issue. That question was about problems invoking an external program (something written in C# in this case) with -- parameters from a PowerShell prompt (where those parameters *are* legitimate for that external program, but PowerShell isn't passing them to the program). This one is about having a PowerShell script accept parameters beginning with --. Which is also why anything like Cygwin isn't a solution. He doesn't want the *shell* to behave like a Unix shell. Presumably he wants to invoke his PS script at a PS prompt, he just wants it to accept -- parameters. – Adi Inbar Sep 21 '13 at 21:39
  • @alroc, Adi Inbar is correct. I wanted to know if the automatic parameter processing provided by Powershell had a way to recognize '--' parameters. The reason is that I have scripts on Windows and Linux that do the same thing, Linux is dominant where I work, and it seemed reasonable that all the scripts use the parameter conventions of the dominant platform, if this could be done easily and naturally. It seems that '--' is specially processed by Powershell, so I will do as you suggest and stick with the conventions of each platform. – Permaquid Sep 21 '13 at 23:56
  • Various previous answers I found refer to Bruce Payette's book. But it refers to '--' occurring by itself as a kind of parameter stopper, not to the case of '--' at the beginning of a larger token. – Permaquid Sep 22 '13 at 00:00

2 Answers2

5

Your syntax fails at tokenizer level. Compare:

[Management.Automation.PSParser]::Tokenize(
    'Command -parameter',
    [ref]$null
)

...and...

[Management.Automation.PSParser]::Tokenize(
    'Command --parameter',
    [ref]$null
)

As you can see former is seen by parser as parameter, latter - as argument. So the only way would be parsing all arguments "internally" and guessing what is parameter (from your perspective), and what is argument.

BartekB
  • 8,492
  • 32
  • 33
2

I'm not aware of any libraries that will parse Unix-style parameters for you (which doesn't necessarily mean there isn't one...), but you could just not declare any parameters, and parse the parameters yourself in the body of the script.

This will create a hashtable of the parameters, where they keys are the parameter names and the values are the parameter values. Switch parameters will have null values.

$params = @{}
$MyInvocation.Line.Substring(($MyInvocation.Line.IndexOf('--') + 2)) -split ' --' | %{
  $_ -match '(\S+) ?(.+)?' | Out-Null
  $params.($matches[1]) = $matches[2]
}
  • $MyInvocation.Line gives you the command line that was used to invoke the script. $MyInvocation.Line.Substring(($MyInvocation.Line.IndexOf('--') + 2)) gives you everything following the first --.
  • $_ -match '(\S+) ?(.+)?' assigns the parameter name to the first match group, and the value to the second match group. The Out-Null prevents PowerShell from printing True for each iteration.
  • The reason I used (.+)? rather than (.*) is to make the values of switch parameters null. (.*) will match an empty string if there is nothing to match, making the value of $matches[2] an empty string, whereas (.+)? won't match, making $matches[2] null.

This is assuming that all parameters begin with --. If you want to allow a single hyphen, restrict single-dash parameter names to a single letter, or check for incorrectly declared parameters (for example throw an error if there's a triple-hyphen), you'll have to account for that in your code, but this is the basic idea.

Adi Inbar
  • 12,097
  • 13
  • 56
  • 69