Below is a typical OptionSet construction code:
var p = new OptionSet {
{ "h|help", "Show this help", v => { isHelp = (v != null); } },
};
var extra = p.Parse(args);
My Powershell version of the same code is:
$p = New-Object NDesk.Options.OptionSet
$p.Add("h|help", "Show this help", { param([string]$v) $global:isHelp = $true })
$extra = $p.Parse($args)
Unfortunately, it has two problems. When I execute the second line I get this:
Multiple ambiguous overloads found for "Add" and the argument count: "3".
At C:\Work\hg\utils\HgTagPromotedBuild.ps1:62 char:7
+ $p.Add <<<< ("h|help", "Show this help message", { param([string]$v) $global:isHelp =
$true })
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
then executing the next line results in:
Cannot convert argument "0", with value: "System.Object[]", for "Parse" to type "System
.Collections.Generic.IEnumerable`1[System.String]": "Cannot convert the "System.Object[
]" value of type "System.Object[]" to type "System.Collections.Generic.IEnumerable`1[Sy
stem.String]"."
At C:\Work\hg\utils\HgTagPromotedBuild.ps1:63 char:18
+ $extra = $p.Parse <<<< ($args)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
The relevant portion of OptionSet declaration is:
public OptionSet Add(Option option);
public OptionSet Add(string prototype, OptionAction<string, string> action);
public OptionSet Add<TKey, TValue>(string prototype, OptionAction<TKey, TValue> action);
public OptionSet Add<T>(string prototype, Action<T> action);
public OptionSet Add(string prototype, Action<string> action);
public OptionSet Add<TKey, TValue>(string prototype, string description, OptionAction<TKey, TValue> action);
public OptionSet Add(string prototype, string description, OptionAction<string, string> action);
public OptionSet Add<T>(string prototype, string description, Action<T> action);
public OptionSet Add(string prototype, string description, Action<string> action);
I do not understand what is going on in the first error at all.
The second is clear – apparently $args is typed as object[], while OptionSet.Parse expects IEnumerable<string>, but I cannot find how to cast to string[].
So, my question is how do I translate the original C# code to Powershell without these nasty exceptions?
Thanks.
EDIT
Thanks to all the folks who have made me understand that PowerShell has a well defined methodology for working with command line arguments. I have acknowledged this fact and have even created a dedicated SO question – Is there a decent command line parser for powershell?, which I have already marked as answered. Again, thanks to all.
Now, I am still interested to know how do I invoke particular .NET code from PowerShell, if at all possible. No connection to command line argument parsing. Just pure quest for knowledge.
PowerShell has its own native argument/parameter parser/binder for functions and cmdlets. You can’t override this with NDesk.Options, so you’re pissing in the wind here I’m afraid my good man. Before you say “jeez, that sucks” you should think a bit about the larger goals of powershell. By coming with a baked-in parameter binder, function/command invocation styles are invariant: no wondering if it’s slash or hyphen, doubleslash, equals, colon etc. This is the same reason why cmdlets and functions use familiar verb-noun notation in naming. Instead of guessing how to invoke things and getting it wrong, you can actually get down to the more useful activity of discovering what you can do.
What are you trying to achieve from a broader perspective? Post the desired parameter binding semantics and I will show you how to declare this in a powershell function.
Update: if you want to learn more about powershell, have a read through my good friend Keith Hill’s free ebook: Effective Windows PowerShell, available free in PDF: http://rkeithhill.wordpress.com/2009/03/08/effective-windows-powershell-the-free-ebook/