Friday, December 19, 2008

Writing PowerShell cmdlets in F#

Note: This issue was resolved by the May 2009 CTP. The cmdlet code is unchanged in the Feb 2010 (v 1.9.9.9) CTP.

There's a catch to this, as I discovered today. You can't -- or to be accurate, you can't inherit PSSnapIn in F# yet. As also noted here, the F# compiler gets its knickers in a twist about the internal abstract members higher up the inheritance chain, culminating in an error stating that PSInstaller.get_RegKey() and PSInstaller.get_RegValues() are not implemented.

You can't fix this with cunning reflection tricks (if you make an override method to call via reflection into the base class, you get told that there's nothing public to override; if you make it a member, you get back to the same error as before). And you can't fix it by delegating the install to a PSSnapIn subclass in a different assembly, because that just registers the delegated assembly (which probably contains no cmdlets at all).

But you can use a CustomPSSnapIn subclass in an assembly that references the F# code. For a very simple "Hello World", based on the code samples from the Wrox PowerShell Programming book we do something like

in the custom snap-in subclass, which is the only class needed in a C# project, which generates the assembly that you actually register via installutil. This project references your F# module for the cmdlet classes that do the real work, and just does the work of publishing them to the PoSh infrastructure. The essentials of the F# code are (in the .fsi file):

where the constructor declaration is essential for the cmdlet to work, and in the .fs file:

And then we can write F# cmdlets as we wish...

No comments :