Tuesday, August 24, 2010

Create custom Powershell snapin

One of the exciting extension mechanism for powershell is custom cmdlets. The idea of writing .net code and plugging that in to powershell as a custom cmdlet is truly exciting. I am often tempted to write cmdlets instead of powershell scripts/functions.. if you are writing your own set of cmdlets you would want to group them in your own custom snapin. This post will take you through the step by step process of writing your own custom snapin and registering it with powershell engine.

In Short this is a three step process
CREATE YOUR SNAPIN
REGISTER YOUR SNAPIN
LOAD YOUR SNAPIN and USE IT

METASTEP I - CREATE YOUR SNAPIN

Step 1: Create a new visual studio class library project

Step 2: Reference the following dlls
System.Management.Automation  (you will find it at C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\)
System.Configuration.Install

The automation dll has the classes your custom snapin and cmdlet extends

Step 3: Create a class that extends pssnapin class (System.Management.Automation.PSSnapin)

e.g.

 [RunInstaller(true)]
    public class SnapIn : PSSnapIn
    {
        public override string Description
        {
            get { return "Snapin has cmdlets and custom powershell implementations"; }
        }

        public override string Name
        {
            get { return "Buddhian.Powershell.SnapInDemo"; }
        }

        public override string Vendor
        {
            get { return "Buddhian"; }
        }

      
    }

Remember to add the custom attribute RunInstaller - I spent 1/2 day figuring out why my snapin did not get registered thru InstallUtil.exe (covered later) when I missed this.

you may add cmdlets to snapin as well.. for testing I added the following one 


 [Cmdlet(VerbsCommon.Get, "WebAppCount")]
    public class GetNumberofWebApps : Cmdlet
    {
    
        protected override void ProcessRecord()
        {
            int webAppCount = getWebAppCount();
            if (webAppCount < 2)
            {
                WriteObject("Count:" + webAppCount + ", what is the point of installing SP");
            }
            else if (webAppCount < 10)
            {
                WriteObject("Count:" + webAppCount + ", seems to be well maintained, good!!");
            }
            else 
            {
                WriteObject("Count:" + webAppCount + ", is this a developer machine??? time to clear up");
            }

            base.ProcessRecord();
        }

        private int getWebAppCount()
        {
            Random randWebAppCount = new Random();
            return randWebAppCount.Next(1, 50);
        }
    }

The cmdlet attribute is for naming your cmdlet - remember that cmdlet names should have verb-noun pattern 

Step 4: Once you have created your snapin and cmdlet like above, compile it. 
Note here that the dll need not be strongly signed and added to GAC, it can be in your physical folder

METASTEP II - REGISTER YOUR SNAPIN

Now the you have created the snap in, you would want to register it, Registering will only add entries in registry so that powershell is informed of the presence of a snapin, the snapin will not be immediately available for use

Step 5: Close and open powershell.exe console as an administrator (if u r in vista)

Step 6: Identify where your installutil.exe is present. 
Here is a powershell cmd to find that 


PS C:\Windows\system32> Get-ChildItem -path ${env:systemroot} -recurse -include installutil.exe


    Directory: C:\Windows\Microsoft.NET\Framework\v2.0.50727


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         3/29/2009   9:42 PM      28672 InstallUtil.exe

Step 7: move to the path and run installutil passing your compiled dll as argument. For people familiar with com, this is similar to calling regsvr32


PS C:\Windows\Microsoft.NET\Framework\v2.0.50727> .\InstallUtil.exe C:\sss\powershellcode\BuddSnapIn\BuddSnapIn\bin\Debu
g\BuddhianSnapIn.dll


The output you would get will be similar to this in figure



Step 8: Verify if the snapin is registered


PS C:\Windows\Microsoft.NET\Framework\v2.0.50727> get-pssnapin -registered


Name        : Buddhian.Powershell.SnapInDemo
PSVersion   : 2.0
Description : Snapin has cmdlets and custom powershell implementations

If the above command returns nothing, it means the snapin is not registered. In such a case have a closer look at the output of step 7 and compare it with the figure above (word by word) to identify problems. In my case, InstallUtil returned almost similar output but did not register the snapin as I had missed the RunInstaller attribute for snapin class (step 3).

Your metastep 2 is complete if the snapin is registerd. To use the cmdlets inside the snapin, everytime you open powershell.exe console you have to load the snapin using add-pssnapin cmdlet

METASTEP III: LOAD YOUR SNAPIN

PS C:\Users\Partha> Add-PSSnapin Buddhian.Powershell.Snapindemo

that is it you are all set to start using your cmdlets, see example below


PS C:\Users\Partha> Get-WebAppCount
Count:1, what is the point of installing SP

you can check if the snapin is available by calling Get-PSSnapin cmdlet

To complete your understanding of snapin creation and use have a look at  custompssnapin class. Additionally, loading the snapin everytime you open powershell can be circumvented by configuring the powershell profile. In case many snapins are to be loaded everytime you can save the information in a configuration file and load that instead.



No comments: