There are several reasons why use PowerShell. The most significant advantage is ability to use script instead of user interface. PowerShell is for administrator almost the same environment as a console application for developer. When the core of your application is highly independent so it is extreme easy build a console application based on it consider using PowerShell layer.
Why should I use a PowerShell interface in my application instead of direct referencing library? When developer wants to explore a library the first step is usually console application. It is developer’s sandbox with quick graphical output because every object has a ToString method. No everyone knows how to write a console application. Administrators like PowerShell where write-compile-run loop is much faster. Developers like code where a breakpoint can be set on every command. So again – why PowerShell interface? The answer is not surprising – because it is very useful for a specific kind of applications.
When the code configures something there is clear that implementing PowerShell support is a great investment. In my case I used a PowerShell interface for a cryptanalysis library. There are many algorithms, but I didn’t want to hardcode steps how to decrypt an encrypted message. I wanted give ability to user use algorithms and decide based on heuristics and own judgment which ones put together. It is similar approach like workflow defined in XAML. What PowerShell can do best is a fast user interaction and, of course, IntelliSense is not lost because PowerShell has autocomplete capability.
Architecture is simple. Library implements PowerShell interface. User interface runs a PowerShell host, generating commands to it and receiving objects from it to fill ViewModels with. Implementation of this pattern is not trivial for many reasons. First of all, there are basically two versions of .NET – 2.0 and 4.0 (1.0 is obsolete, 3.0 and 3.5 are extensions of 2.0). PowerShell has 2 versions, third is currently in a beta stage. Another complication is dual environment – 32 bit and 64 bit. I spent many hours solving issues causing these aspects. When I was finally done I felt duty to write an article about it.
Let’s talk about library point of view first. Library has to reference System.Management.Automation library which is part of PowerShell SDK. There are two important classes – PSCmdlet and CustomPSSnapIn. PSCmdlet is a command which PowerShell can execute and optionally return an object or collection. CustomPSSnapIn is a set of PowerShell commands with vendor information in one pack. Your classes must derivate from them. Cmdlet classes must be decorated by Cmdlet attribute and the SnapIn class muse be decorated by RunInstaller attribute. It is required for reflection because that’s how PowerShell finds cmdlets in your library. Library is compiled to MSIL, so when you keep Any CPU configuration, it works both in 32 bit and 64 bit environment. You should choose .NET Framework 3.5 against PowerShell 2 and .NET Framework 4 against PowerShell 3. SnapIn assembly compiled as .NET 3.5 should works fine in PowerShell 3, but not vice versa.
The library containing cmdlets must be registered. There is an InstallUtil.exe doing this job for you. The problem is this utility is platform dependent. Avoiding guessing which framework version run or whenever use 32 bit or 64 bit variant requires knowledge that this utility is just a wrapper of AssemblyInstaller class. This means that during application launch the library can be easily registered so hosting PowerShell knows about its existence. During application exit the library is unregistered so its location can be changed in future without causing any errors. This registration approach doesn’t fit all scenarios at all. Library registration should be made by installer rather that application itself, but who likes installers? Users who use PowerShell have often User Account Protection turned off because they know really well what they are doing.
User interface point of view is more difficult. First of all it is worth to know that even 64 bit application runs 32 bit PowerShell instance. Application .NET Framework version is not important. What is important is ability to reference System.Management.Automation library. This library is located in v1.0 directory but it doesn’t mean that PowerShell 1 is used. Latest available version is always used.
When user interface launches a PowerShell host it must load the SnapIn first using AddPSSnapIn class in RunspaceConfiguration. Then application can call PowerShell.Create method and use PowerShell commands defined in the library. Advantage of PowerShell 3 is that is built on the top of Dynamic Language Runtime. This means you can type PSObject as dynamic and shorten your code.
Hope this helps building friendly configured environments. When you know how to do that you will find it’s really easy. Just follow the naming conventions.