This post is an extension from the post I did earlier this week on the Powershell Course. Found here: http://www.brianlockwood.info/2012/01/11/powershell/
Quick summary from my previous post: “Powershell is a scripting language that is deeply engrained in windows operating systems. It is a programming language for powerful automation, it can be used to interrogate and manipulate windows operating systems in a robust and scalable way.”
At the time of this writing, I’m unsure of the best practices so this is my “gut feeling”. If you have feedback I’d love to hear it.
All Microsoft products have or will have a Powershell layer that will allow IT professionals to automate those Microsoft products. As a developer I need to make sure my applications have this abstraction layer as well. I should not rely on or require administrators to interact with my application GUI to execute some functionality. They need to be able to automate not only the capabilities of my application but potentially some of the business logic as well.
Building a snapin for an application that manages courses at Benchmark Learning.
Objectives:
- Add a powershell abstraction layer for an application that manages courses
- Create a custom powershell snapin
- Add the custom snapin (aligning to framework version) to powershell
- Call the cmdlet’s for my application from within powershell
Adding a powershell abstraction layer
Most tiered applications leverage the downward stream of calls to lower layers. In this project I decided to add a class library in Visual Studio to provide my powershell abstraction. See code here:
In order to derive my custom commandlet from the framework using System.Management.Automation dll and namespace needed to be added to the project. This dll was found in the powershell reference assemblies folder: [C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0]. From here it is required to override the ProcessRecord method as it is called by powershell when the commandlet is used.
In the example above, I wanted to give my administrator the ability to find course information by supplying a name parameter of the course. By annotating the Name property with the Parameter attribute it provides the meta data needed for powershell to understand its use. If the property was not annotated with this attribute the property would be encapsulated within the object itself.
In addition to the name parameter the actual data used will be returned as a collection of custom educator objects. The definition of the educator class contains a firstname and lastname, as see here:
By using WriteObject the results of my commandlet can be returned to Powershell. In this scenario I’m returning the collection of educators to Powershell. Although returning a string is straight forward and easy, I have decided to return a collection of educators so we can use powershell commands such as Get-Member, Format-Table, Format-List etc.
Create a custom powershell snapin
The next step is to create a custom powershell snapin that will allow powershell to leverage the commandlet created earlier. Below is what was required to do so. It is required to override the description, name, vendor and cmdlets properties.
Two notes about the custom snapin.
- It is possible to add multiple commandlets in one snapin by using the cmdlets collection property.
- In order to register the assembly to the system we need the RunInstaller attribute defined in the custom snapin
Start off by deriving the custom snapin from the CustomPSSnapIn class found in the System.Management.Automation namespace. Define the values for the vendor, description, and name. In addition to this, it is possible to add an xml file reference that describes the help documentation for the commandlets defined within the snapin (this has not been done in this example). When adding the commandlet to the cmdlet collection provide the command name such as Get-Course in the constructor of the CmdletConfigurationEntry object.
Add the custom snapin to powershell
Before adding the snapin to powershell the assembly needs to be registered to the system. To do this, in the console window navigate to your framework version folder for example: [C:\Windows\Microsoft.NET\Framework\v4.0.30319] and run the installutil executable.
Note: Make sure it run successfully. It will generate a log file for review if necessary to troubleshoot the installation.
Once the assembly is registered in the system Powershell needs to know it can use it. This is where the custom snap in can be built into the user profile of Powershell or for one time use only (as seen in this sample). To make sure the assembly is registered, open powershell, and use the Get-PSSnapIn -Registered command in powershell. The commandlet should be listed:
Note: In the configuration used for this sample, Powershell by default, knew to use the 2.0 version of the .NET framework however the application/commandlet is a 4.0 version commandlet. In order for Powershell to recognize the latest version of the framework to use with the custom snapin the following step needed to be completed:
Navigate to [C:\Windows\System32\WindowsPowerShell\v1.0] and there should be a Powershell.exe.config file. If there is not, create one.
Contents of Powershell.exe.config:
<?xml version=”1.0″?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy=”true”>
<supportedRuntime version=”v4.0.30319″/>
<supportedRuntime version=”v2.0.50727″/>
</startup>
</configuration>
Call the commandlet
Within powershell add the custom snap in via the name (as seen in the results of Get-PSSnapin -Registered). Use the command Add-PSSnapIn GetCourse and then use powershell to call the custom commandlet. In this scenario it is possible to use the -Name parameter of the course as well as piping the results into a formatted table.
Get-Help is available on the custom commandlet. The details of Get-Help will depend on the detail provided by the developer in the attributes of the commandlet.
Summary
Creating a custom powershell commandlet required some work but now this abstraction layer can be used by powershell to call into the business logic of the application. I would consider this internal integration with powershell with my .NET application. Remember that we can also use powershell to automate the installation and configuration of the custom applications as well.






