{"id":31,"date":"2007-01-01T02:00:00","date_gmt":"2007-01-01T10:00:00","guid":{"rendered":"http:\/\/testblog.sapien.com\/index.php\/2007\/01\/01\/make-a-cmdlet-part-3-the-code\/"},"modified":"2007-01-01T02:00:00","modified_gmt":"2007-01-01T10:00:00","slug":"make-a-cmdlet-part-3-the-code","status":"publish","type":"post","link":"https:\/\/dev.sapien.com\/blog\/2007\/01\/01\/make-a-cmdlet-part-3-the-code\/","title":{"rendered":"Make-A-Cmdlet: Part 3, The Code"},"content":{"rendered":"<p><P>Okay, without further ado, here&#8217;s the next evolution of my code. I want to point out that I&#8217;m blogging as I&#8217;m going &#8211; if you follow along with this step and things don&#8217;t work&#8230; well, maybe they didn&#8217;t work for me, either. Learning process! Stay tuned, if that&#8217;s the case :), and we&#8217;ll explore my mistakes together.<\/P><P>And, by the way &#8211; if you&#8217;re doing this in Visual Basic Express, remember to add a reference (using the Tools menu) to the System.Management and System.Management.Automation DLLs. That way Express knows to actually load those DLLs. Stick with me, now&#8230;<\/P><P>I&#8217;m going to put comments in-line to explain what&#8217;s going on. First, I have two lines of code that import the necessary .NET namespaces for what I want to do.<\/P><PRE>Imports System.Management.Automation<BR>Imports System.Management<\/PRE><P>Next up is my cmdlet declaration. Notice that I&#8217;ve changed my mind on the cmdlet name, making it Ping-Computer&#8230; I felt obliged to stick with the official naming. &#8220;Where-Object,&#8221; a built-in cmdlet, is actually a special kind of exception to the naming scheme, and I didn&#8217;t want to base my name on an exception. Notice that the cmdlet name is defined in two parts: Verb and Noun. I had missed this last time, and made my cmdlet name something like Where-WhereObjectCmd or something bizarre. Anyway &#8211; figured it out, now. For the verb, I&#8217;m using the built-in VerbsDiagnostic.Ping enumeration. The name of my class &#8211; PingComputerCmd &#8211; is abritrary; nobody will see it but me.<\/P><PRE>&lt;Cmdlet(VerbsDiagnostic.Ping, &#8220;Computer&#8221;, SupportsShouldProcess:=True)&gt; _<BR>Public Class PingComputerCmd<BR>Inherits Cmdlet<\/PRE><P>Now I need to define a variable which will hold my input &#8211; I&#8217;ve blogged this bit before, although I&#8217;ve standardized the property name to Name rather than Address; the PowerShell SDK recommends using Name whenever it&#8217;s appropriate. My _Name variable is for use within the cmdlet itself, and it&#8217;s defined as a String array.<\/P><PRE>Private _Name As String()<\/PRE><P>Now I&#8217;m defining the Name parameter, which is public &#8211; meaning users of the cmdlet will see it. Notice that this parameter is in position zero, meaning you don&#8217;t have to specify a parameter name at all. Also, it&#8217;ll accept input from the pipeline just as easily.<\/P><PRE>&lt;Parameter(Position:=0, Mandatory:=False, ValueFromPipeline:=True)&gt; _<BR>Public Property Name() As String()<BR> Get<BR>  Return _Name<BR> End Get<\/PRE><PRE> Set(ByVal value As String())<BR>  _Name = value<BR> End Set<BR>End Property<\/PRE><P>Now I need to override one of the built-in cmdlet methods, ProcessRecord. The default implementation for this method doesn&#8217;t do anything, so I need to insert the code that makes my cmdlet do whatever it&#8217;s supposed to do. <\/P><PRE>Protected Overrides Sub ProcessRecord()<BR> Dim ThisName As String<BR> For Each ThisName In _Name<BR>  WriteDebug(&#8220;Attempting to ping &#8221; &amp; ThisName)<\/PRE><PRE>  Dim Query As SelectQuery<BR>  Query = New SelectQuery(&#8220;SELECT StatusCode FROM Win32_PingStatus WHERE Address = &#8216;&#8221; &amp; ThisName &amp; &#8220;&#8216;&#8221;)<\/PRE><PRE>  Dim Searcher As ManagementObjectSearcher<BR>  Searcher = New ManagementObjectSearcher(Query)<\/PRE><PRE>  Dim result As ManagementObject<BR>  For Each result In Searcher.Get<BR>   If result.GetPropertyValue(&#8220;StatusCode&#8221;) Then<BR>    WriteDebug(&#8220;Successful ping of &#8221; &amp; ThisName)<BR>    WriteObject(ThisName)<BR>   Else<BR>    WriteDebug(&#8220;Could not ping &#8221; &amp; ThisName)<BR>   End If<BR>  Next<BR> Next<BR>End Sub<\/PRE><P>All I&#8217;m doing is using WMI to ping the specified computer name. Remember that _Name can be an array, so I&#8217;m using a For Each loop to go through each element in the array. Also notice my use of WriteDebug() and WriteOutput(). These are two built-in functions, meaning I don&#8217;t have to define them. WriteOutput() writes an object to the pipeline &#8211; here, I&#8217;m writing the name of the computer if I could ping it. WriteDebug() writes text to PowerShell&#8217;s debug stream. And that&#8217;s it &#8211; the last line of code finishes the class.<\/P><PRE>End Class<\/PRE><P>But we&#8217;re not quite done. In Visual Studio, it&#8217;s time to hit the Build button to make a DLL. Then, I want to execute the InstallUtil utility, which is located in the .NET Framework&#8217;s folder (usually C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727). This utility will &#8220;register&#8221; my snap-in so that PowerShell can see it. Remember from the previous post in this series that my Visual Studio project is not just a cmdlet &#8211; I started from a template that also included the snap-in &#8220;package&#8221; code.<\/P><P>So, I run:<\/P><PRE>installutil &#8220;c:\\projects\\primaltoys.dll&#8221;<\/PRE><P>And then, in PowerShell, I check to make sure PowerShell can see the registration:<\/P><PRE>get-pssnapin -registered<\/PRE><P>Yup, it&#8217;s there! Now I can add it to the shell:<\/P><PRE>add-pssnapin primaltoys<\/PRE><P><A href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/ms714644.aspx\">http:\/\/msdn2.microsoft.com\/en-us\/library\/ms714644.aspx<\/A>&nbsp;has more details on this process, including how to &#8220;export&#8221; the shell into a shortcut so you can always start up with your custom snap-ins loaded.<\/P><P>So it&#8217;s time to try it out:<\/P><PRE>ping-computer localhost<\/PRE><P>What happens? Did it work for you? Yes? No? Well&#8230; stay tuned until next week, and you&#8217;ll see MY results.<\/P><P>Technorati Tags:<BR><A href=\"http:\/\/technorati.com\/tags\/cmdlets\" rel=tag>Cmdlets<\/A><BR><A href=\"http:\/\/technorati.com\/tags\/powershell+development\" rel=tag>PowerShell Development<\/A><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p><P>Okay, without further ado, here&#8217;s the next evolution of my code. I want to point out that I&#8217;m blogging as I&#8217;m going &#8211; if you follow along with this step and things don&#8217;t work&#8230; well, maybe they didn&#8217;t work for me, either. Learning process! Stay tuned, if that&#8217;s the case :), and we&#8217;ll explore my mistakes together.<\/P><P>I&#8217;m going to &#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[2,25],"tags":[],"class_list":["post-31","post","type-post","status-publish","format-standard","hentry","category-general","category-windows-powershell"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":0,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"wp:attachment":[{"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.sapien.com\/blog\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}