Creating a C# CmdLet

So Powershell comes with a lot of commands/CmdLets but as a developer I’m always interested in how I might write my own. Whilst it’s likely that combining existing commands might produce the results you’re after, if it doesn’t we can resort to writing our own command using C#.

Getting Started

  • Create a new Class Library project
  • Go to the project properties and target the version of .NET supported by your installed version of Powershell (to find this out simply type $PSVersionTable into Powershell and check the CLRVersion)
  • Add a reference to System.Management.Automation to locate this browse to C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0
  • The namespace we need to add is System.Management.Automation

Hello World CmdLet

Now we’ve got everything set-up we need to make our CmdLet do something. Here’s the source for a good old HelloWorld Cmdlet

[Cmdlet(VerbsCommon.Get, "HelloWorld")]
public class GetHelloWorld : Cmdlet
{
   protected override void ProcessRecord()
   {
      WriteObject("Hello World");
   }
}

The CmdLetAttribute takes a string for the verb, in this case I’m reusing the VerbsCommon.Get string. The next requirements is the noun, the name of the Cmdlet. So in this case the two go together to give us the Cmdlet Get-HelloWorld.

We derive our class from Cmdlet as we’re not dependent upon the Powershell runtime, if we were we’d derive from the PSCmdlet.

Importing and using the new CmdLet

Once we’ve built our CmdLet and assuming it’s been built with the same version of .NET as supported by the installed Powershell, we can import the “module” into Powershell using

Import-Module c:\Dev\MyCmdLets.dll

Obviously replacing the path and DLL with the location and DLL you’re installing

Once imported we can simply run

Get-HelloWorld

Autocomplete also works if you type Get-He then press tab and you’ll find Get-HelloWorld presented.

If you need to rebuild your Cmdlet you’ll need to close the Powershell instance to remove the instance from it, I tried Remove-Module MyCmdLets but this only removes its availability to Powershell, i.e. you can no longer run it, but I guess, like in C# applications, once the module is in the AppDomain you cannot fully unload it.

Parameters

Let’s add a parameter to the Cmdlet.

[Cmdlet(VerbsCommon.Get, "HelloWorld")]
public class GetHelloWorld : Cmdlet
{
   [Parameter(Mandatory = true)]
   public string Name { get; set; }

   protected override void ProcessRecord()
   {
      WriteObject("Hello World " + Name);
   }
}

So now, we’ve added a mandatory parameter Name. When we run the Get-HelloWorld Cmdlet we can now supply the name, thus

Get-HelloWorld -Name Scooby

Returning objects

So far we’ve returned a string, but what about if we want to return and object or better still multiple objects, like Get-Process might.

[Cmdlet(VerbsCommon.Get, "HelloWorld")]
public class GetHelloWorld : Cmdlet
{
   protected override void ProcessRecord()
   {
      WriteObject(new HelloObject { Name = "Scooby", Description = "Dog"} );
      WriteObject(new HelloObject { Name = "Shaggy", Description = "Man" });
      WriteObject(new HelloObject { Name = "Daphne", Description = "Woman" });
   }
}

public class HelloObject
{
   public string Name { get; set; }
   public string Description { get; set; }
}

Now running this from Powershell will list two columns, Name and Description and three rows with the name and description as per our objects.

Better still we can now write commands such as

Get-HelloWorld | where {$_.Description -eq "Dog"}

References

Cmdlet Methods