{"id":3678,"date":"2016-03-10T20:40:01","date_gmt":"2016-03-10T20:40:01","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=3678"},"modified":"2016-03-10T20:40:01","modified_gmt":"2016-03-10T20:40:01","slug":"creating-a-c-cmdlet","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/creating-a-c-cmdlet\/","title":{"rendered":"Creating a C# CmdLet"},"content":{"rendered":"<p>So Powershell comes with a lot of commands\/CmdLets but as a developer I&#8217;m always interested in how I might write  my own. Whilst it&#8217;s likely that combining existing commands might produce the results you&#8217;re after, if it doesn&#8217;t we can resort to writing our own command using C#.<\/p>\n<p><string>Getting Started<\/strong><\/p>\n<ul>\n<li>Create a new Class Library project<\/li>\n<li>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)<\/li>\n<li>Add a reference to System.Management.Automation to locate this browse to C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\WindowsPowerShell\\3.0<\/li>\n<li>The namespace we need to add is System.Management.Automation<\/li>\n<\/ul>\n<p><strong>Hello World CmdLet<\/strong><\/p>\n<p>Now we&#8217;ve got everything set-up we need to make our CmdLet do something. Here&#8217;s the source for a good old HelloWorld Cmdlet<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;Cmdlet(VerbsCommon.Get, &quot;HelloWorld&quot;)]\r\npublic class GetHelloWorld : Cmdlet\r\n{\r\n   protected override void ProcessRecord()\r\n   {\r\n      WriteObject(&quot;Hello World&quot;);\r\n   }\r\n}\r\n<\/pre>\n<p>The CmdLetAttribute takes a string for the verb, in this case I&#8217;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.<\/p>\n<p>We derive our class from <em>Cmdlet<\/em> as we&#8217;re not dependent upon the Powershell runtime, if we were we&#8217;d derive from the <em>PSCmdlet<\/em>.<\/p>\n<p><strong>Importing and using the new CmdLet<\/strong><\/p>\n<p>Once we&#8217;ve built our CmdLet and assuming it&#8217;s been built with the same version of .NET as supported by the installed Powershell, we can import the &#8220;module&#8221; into Powershell using<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nImport-Module c:\\Dev\\MyCmdLets.dll\r\n<\/pre>\n<p><em>Obviously replacing the path and DLL with the location and DLL you&#8217;re installing<\/em><\/p>\n<p>Once imported we can simply run<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nGet-HelloWorld\r\n<\/pre>\n<p>Autocomplete also works if you type <em>Get-He<\/em> then press tab and you&#8217;ll find Get-HelloWorld presented.<\/p>\n<p>If you need to rebuild your Cmdlet you&#8217;ll need to close the Powershell instance to remove the instance from it, I tried <em>Remove-Module MyCmdLets<\/em> 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.<\/p>\n<p><strong>Parameters<\/strong><\/p>\n<p>Let&#8217;s add a parameter to the Cmdlet. <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;Cmdlet(VerbsCommon.Get, &quot;HelloWorld&quot;)]\r\npublic class GetHelloWorld : Cmdlet\r\n{\r\n   &#x5B;Parameter(Mandatory = true)]\r\n   public string Name { get; set; }\r\n\r\n   protected override void ProcessRecord()\r\n   {\r\n      WriteObject(&quot;Hello World &quot; + Name);\r\n   }\r\n}\r\n<\/pre>\n<p>So now, we&#8217;ve added a mandatory parameter <em>Name<\/em>. When we run the Get-HelloWorld Cmdlet we can now supply the name, thus<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nGet-HelloWorld -Name Scooby\r\n<\/pre>\n<p><strong>Returning objects<\/strong><\/p>\n<p>So far we&#8217;ve returned a string, but what about if we want to return and object or better still multiple objects, like Get-Process might.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;Cmdlet(VerbsCommon.Get, &quot;HelloWorld&quot;)]\r\npublic class GetHelloWorld : Cmdlet\r\n{\r\n   protected override void ProcessRecord()\r\n   {\r\n      WriteObject(new HelloObject { Name = &quot;Scooby&quot;, Description = &quot;Dog&quot;} );\r\n      WriteObject(new HelloObject { Name = &quot;Shaggy&quot;, Description = &quot;Man&quot; });\r\n      WriteObject(new HelloObject { Name = &quot;Daphne&quot;, Description = &quot;Woman&quot; });\r\n   }\r\n}\r\n\r\npublic class HelloObject\r\n{\r\n   public string Name { get; set; }\r\n   public string Description { get; set; }\r\n}\r\n<\/pre>\n<p>Now running this from Powershell will list two columns, Name and Description and three rows with the name and description as per our objects.<\/p>\n<p>Better still we can now write commands such as<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nGet-HelloWorld | where {$_.Description -eq &quot;Dog&quot;}\r\n<\/pre>\n<p><strong>References<\/strong><\/p>\n<p><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.management.automation.cmdlet_methods(v=vs.85).aspx\" target=\"_blank\">Cmdlet Methods<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>So Powershell comes with a lot of commands\/CmdLets but as a developer I&#8217;m always interested in how I might write my own. Whilst it&#8217;s likely that combining existing commands might produce the results you&#8217;re after, if it doesn&#8217;t we can resort to writing our own command using C#. Getting Started Create a new Class Library [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[118],"tags":[],"class_list":["post-3678","post","type-post","status-publish","format-standard","hentry","category-powershell"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3678","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=3678"}],"version-history":[{"count":7,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3678\/revisions"}],"predecessor-version":[{"id":3685,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/3678\/revisions\/3685"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=3678"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=3678"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=3678"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}