Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide Linux-style parameter names in a powershell script

Tags:

powershell

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?

like image 539
Permaquid Avatar asked Sep 21 '13 15:09

Permaquid


2 Answers

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.

like image 180
BartekB Avatar answered Oct 13 '22 15:10

BartekB


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.

like image 24
Adi Inbar Avatar answered Oct 13 '22 14:10

Adi Inbar