PowerShell is perhaps the coolest thing to have happened for Windows Administrators in the recent past. I must admit I am a bit new to PowerShell, somehow I never got the opportunity to work on PowerShell part of the product at my work. Tinkering with it for a few days, it seems to be well thought out and easy to use.
PowerShell has evolved since the first version, the latest is V4.0 present in Windows 10 family of operating systems. This article will discuss how to create a cmdlet and use it in PowerShell version 1.0 and assumes that you have fair knowledge of PowerShell and related terms.
We will develop a cmdlet which prints a greeting like 'Good evening!' or 'Hello!' depending on the time of the day. It will also be possible to specify an hour value (in 24 hour form) to the Cmdlet.
In V1.0, a cmdlet must be implemented as a .NET assembly, so create an .NET Class Library in your favorite IDE; call the project SampleSnapIn. Just for your information, I am using Visual Studio 2015 Community Edition in this example.
At this point you should have a Class1.cs; if you do, rename it to GetGreetingCommand. For a class to act as a cmdlet it must derive from System.Management.Automation.Cmdlet class. This class is present in System.Management.Automation.dll and this assembly should be located at C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0. If you have a different version of PowerShell say 3.0, it would be C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0.
The Cmdlet class has a number of methods which can be overridden which will give it the behavior you want. In this case, we need to override the ProcessRecord() method. This is the method which PowerShell runtime will call. The entire class' source code is here:
using System; using System.Management.Automation; namespace Siddharth.Powershell { [Cmdlet(VerbsCommon.Get, "Greeting")] public class GetGreetingCommand : Cmdlet { protected override void ProcessRecord() { int hour; if (!string.IsNullOrEmpty(m_time)) { hour = int.TryParse(m_time, out hour) ? hour : DateTime.Now.Hour; } else { hour = DateTime.Now.Hour; } string ret; if (hour < 4) ret = "Hello!"; else if (hour < 12) ret = "Good Morning!"; else if (hour < 17) ret = "Good afternoon!"; else ret = "Good evening!"; WriteObject(ret); } private string m_time = null; [Parameter(Position = 0)] public string Time { get { return m_time; } set { m_time = value; } } } }
Building the project gives us SampleSnapIn.dll. This is the name of the PowerShell snapin. To use it,it must be registered with PowerShell. This is done using the "installutil" tool.
Open an Administrative Cmd prompt and navigate to:
C:\>CD C:\Windows\Microsoft.NET\Framework64\v4.0.30319 C:\Windows\Microsoft.NET\Framework64\v4.0.30319>installutil "D:\My Stuff\My Projects\Csharp\PSHello\PSHello\bin\Debug\SampleSnapIn.dll"
Note: If you are using a different version of .NET change the path accordingly. Also, note since my version of Windows is a 64-bit one, I am using the tools from Framework64 folder.
Let's check if the SnapIn is registered. Open a PowerShell window and type:
Get-PSSnapIn -registeredThe output should be something like:
Name : SampleSnapIn PSVersion : 5.0
To use the SnapIn, we need to import it using:
> Add-PsSnapIn SampleSnapIn > Get-Greeting > Hello! > Get-Greeting 21 Good evening!
Now to add a final finish, we'll create some help content for the cmdlet. Add a new XML file named 'SampleSnapIn.dll-help.xml' to the project and paste the following:
<!--?xml version="1.0" encoding="utf-8" ?--> <helpitems xmlns="http://msh" schema="maml"> <command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10"> <command:details> <command:name>Get-Greeting</command:name> <maml:description> <maml:para>Returns a greeting string based on the time of the day.</maml:para> </maml:description> <command:verb>Get</command:verb> <command:noun>Greeting</command:noun> </command:details> <command:syntax> <command:syntaxitem> <maml:name>Get-Greeting</maml:name> <command:parameter aliases="" position="0" pipelineinput="True" globbing="false" variablelength="true" required="false"> <maml:name>Hour</maml:name> <maml:description> <maml:para>Specifies the hour on the basis of which a greeting is returned.</maml:para> </maml:description> <command:parametervalue variablelength="true" required="false">System.Int32</command:parametervalue> </command:parameter> </command:syntaxitem> </command:syntax> <command:parameters> <command:parameter required="false" globbing="true" pipelineinput="false" position="0"> <maml:name>Hour</maml:name> <dev:type>System.Int32</dev:type> <dev:defaultvalue>DateTime.Now.Hour</dev:defaultvalue> </command:parameter> </command:parameters> <command:returnvalues> <command:returnvalue> <dev:type> <maml:name>String</maml:name> </dev:type> </command:returnvalue> </command:returnvalues> <command:examples> <command:example> <maml:title>--- Example 1 ---</maml:title> <maml:introduction> <maml:param>Calling it without any parameters.</maml:param> </maml:introduction> <dev:code>PS C:\>Get-Greeting</dev:code> <dev:remarks> <maml:para>The current time is used to return a greeting message.</maml:para> </dev:remarks> </command:example> <command:example> <maml:title>--- Example 2 ---</maml:title> <maml:introduction> <maml:param>Calling it with one parameter specfying the hour.</maml:param> </maml:introduction> <dev:code>PS C:\>Get-Greeting 8</dev:code> <dev:remarks> <maml:para>The specified hour is used to return a greeting message, in this case will return good morning.</maml:para> </dev:remarks> </command:example> </command:examples> <maml:relatedlinks> <maml:navigationlink> <maml:linktext>Explanation can be found at</maml:linktext> <maml:uri>http://sbytestream.net</maml:uri> </maml:navigationlink> </maml:relatedlinks> </command:command> </helpitems>Typing PS C:\Users\Siddharth> help Get-Greeting -full
gives us: