{"id":2115,"date":"2015-11-17T00:00:00","date_gmt":"2015-11-17T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/documenting-your-powershell-binary-cmdlets\/"},"modified":"2021-05-03T14:02:03","modified_gmt":"2021-05-03T14:02:03","slug":"documenting-your-powershell-binary-cmdlets","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/documenting-your-powershell-binary-cmdlets\/","title":{"rendered":"Documenting Your PowerShell Binary Cmdlets"},"content":{"rendered":"<div id=\"pretty\">\n<ul class=\"series-articles\">\n<li>Part 1: <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/how-to-document-your-powershell-library\/\">How to Document your PowerShell Library<\/a><\/li>\n<li>Part 2: <a href=\"https:\/\/www.simple-talk.com\/dotnet\/development\/using-c-to-create-powershell-cmdlets-the-basics\/\">Using C# to Create PowerShell Cmdlets: The Basics<\/a><\/li>\n<li class=\"series-articles--active\">Part 3: Documenting Your PowerShell Binary Cmdlets<\/li>\n<li>Part 4: <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/unified-approach-to-generating-documentation-for-powershell-cmdlets\/\">Unified Approach to Generating Documentation for PowerShell Cmdlets<\/a><\/li>\n<\/ul>\n<h2>Contents:<\/h2>\n<ul>\n<li><a href=\"#first\">Documentation: A Snapshot<\/a><\/li>\n<li><a href=\"#second\">Getting Documentation out of your Cmdlets<\/a><\/li>\n<li><a href=\"#third\">Components of Cmdlet Help<\/a>\n<ul>\n<li><a href=\"#fourth\">Name<\/a><\/li>\n<li><a href=\"#fifth\">Synopsis<\/a><\/li>\n<li><a href=\"#sixth\">Syntax<\/a><\/li>\n<li><a href=\"#seventh\">Description<\/a><\/li>\n<li><a href=\"#eighth\">Parameters<\/a><\/li>\n<li><a href=\"#ninth\">Inputs<\/a><\/li>\n<li><a href=\"#tenth\">Outputs<\/a><\/li>\n<li><a href=\"#eleventh\">Notes<\/a><\/li>\n<li><a href=\"#twelveth\">Examples<\/a><\/li>\n<li><a href=\"#thirteenth\">Related Links<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#fourteenth\">Parameters<\/a>\n<ul>\n<li><a href=\"#fifteenth\">Parameter Description<\/a><\/li>\n<li><a href=\"#sixteenth\">Parameter Enumerated Types<\/a><\/li>\n<li><a href=\"#seventeenth\">Parameter Alias<\/a><\/li>\n<li><a href=\"#eighteenth\">Parameter Default Values<\/a><\/li>\n<li><a href=\"#nineteenth\">Input Parameters<\/a><\/li>\n<li><a href=\"#twentieth\">Output Parameters<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#twentyfirst\">Summary<\/a><\/li>\n<\/ul>\n<p class=\"start\">You have developed a whiz-bang library of C#-based  binary PowerShell cmdlets for your team\/&#194;&#173;department\/&#194;&#173;company (or perhaps the whole PowerShell-loving community) to use. And being a PowerShell power user, you know that all good cmdlets <i>must<\/i> have documentation. After all, you do not want to suffer the ire of your colleagues when they invoke <span class=\"Inlinecode\"><code> Get-Help<\/code><\/span> on <span class=\"Inlinecode\"><code>  Get-YourGreatCmdlet<\/code><\/span> and they discover that there&#8217;s almost nothing there beyond a skeleton!<\/p>\n<p>PowerShell script modules (i.e. those written in PowerShell itself), provide a range of opportunities for documentation from within embedded structured comments. However, help documentation for <i>binary<\/i> PowerShell modules written in C# is so much worse than for <i>script<\/i> modules. Although basic information is possible, as you&#8217;ll see shortly, it falls a long way short of best-practice for a script module. All you get is what PowerShell can derive from your DLL, which is essentially (a) the syntax of your cmdlet and (b) a few standard properties of each parameter. But just as vital are the parts you do <i>not<\/i> get, the prose that you write to explain your cmdlet and explain your parameters.  <\/p>\n<p>To provide anything extra, you need to provide a documentation file written in an XML dialect called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Microsoft_Assistance_Markup_Language\"> Microsoft Assistance Markup Language<\/a> (MAML) that sits next to your DLL. From that, PowerShell will automatically generate standard-style help text when you invoke <span class=\"Inlinecode\"><code> Get-Help<\/code><\/span>. The biggest catch is creating that MAML file! It is not easy-<a href=\"http:\/\/blogs.msdn.com\/b\/powershell\/archive\/2006\/09\/14\/draft-creating-cmdlet-help.aspx\">here<\/a> is a sample. Not too long after PowerShell was introduced, along came the <a href=\"https:\/\/cmdlethelpeditor.codeplex.com\/\">CmdletHelpEditor<\/a> to help you do just that. However, unlike conventional C# where you embed doc-comments in your code-and can keep them properly up-to-date as the code evolves-this utility lets you build documentation components into a MAML file-<i>completely  separate from your code base<\/i>. CmdletHelpEditor was supported up through 2011, and was then supplanted by <a href=\"https:\/\/pscmdlethelpeditor.codeplex.com\/\">PowerShell Cmdlet Help Editor<\/a>. (Those name choices certainly made it easy to confuse the two!) But this newer utility suffered from the same major impediments: completely separate from the code, and not all that easy to use.<\/p>\n<p>Then things got interesting. In 2014, Redgate Software-well-known for their database tools-was developing some PowerShell cmdlets of their own. Chris Lambrou was participating in that effort and, realizing there was no easy Sandcastle equivalent for PowerShell, spearheaded the effort to create one-and make it available to everyone as open source. This new utility, <a href=\"https:\/\/github.com\/red-gate\/XmlDoc2CmdletDoc\"> XmlDoc2CmdletDoc<\/a>, generates the requisite MAML file for you <i>using essentially standard C# doc-comments  embedded directly in your code<\/i>, <i>just  like documenting any other C# library<\/i>. Now you can document PowerShell simply and easily, and keep it synchronized with the code.<\/p>\n<p> The rest of this article gives you practical tips and guidelines on how to do just that.<\/p>\n<h2 id=\"first\">Documentation: A Snapshot<\/h2>\n<p>To show you where we are headed, the images here give you a good overview. Presented first is generating documentation from traditional C# classes. Using documentation comments embedded in the code, Sandcastle and <a href=\"https:\/\/github.com\/EWSoftware\/SHFB\">Sandcastle Help File Builder<\/a> made it very straightforward to generate the documentation. (You can see a live example documenting my open source C# library <a href=\"http:\/\/cleancode.sourceforge.net\/api\/csharp\/\">here<\/a>.)<\/p>\n<p> <img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2311-img8.jpg\" alt=\"2311-img8.jpg\" \/><\/p>\n<p> A few years back I wrote an article explaining how best to document your C# libraries (<a href=\"https:\/\/www.simple-talk.com\/dotnet\/.net-tools\/taming-sandcastle-a-.net-programmers-guide-to-documenting-your-code\/\">Taming  Sandcastle: A .NET Programmer&#8217;s Guide to Documenting Your Code<\/a>). That task was made much easier because (a) .NET directly supports-and provides Intellisense-for documentation-comments, (b) Microsoft provided a great foundation for generating the documentation from the doc-comments in the form of Sandcastle, and (c) last but not least, Eric Woodruff provided Sandcastle Help File Builder, which made using Sandcastle easy. <\/p>\n<p>Similarly, for <i> scripted<\/i> PowerShell cmdlets (i.e. those written in PowerShell itself), you could embed documentation comments in the code and here you do not even need to invoke a documentation generator. PowerShell does it automatically and on-the-fly when you invoke <span class=\"Inlinecode\"> <code>Get-Help<\/code><\/span>. (You can also see a live example of this documenting my open source PowerShell library <a href=\"http:\/\/cleancode.sourceforge.net\/api\/powershell\/\">here<\/a>.)<\/p>\n<p> <img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2311-img9.jpg\" alt=\"2311-img9.jpg\" \/><\/p>\n<p>Now you have the analogous treatment for <i>compiled<\/i> PowerShell cmdlets (i.e. those written in C#). Using documentation comments embedded in the code, XmlDoc2CmdletDoc makes it very straightforward to generate the documentation. (The live example for this requires you to build the sample project, then run XmlDoc2CmdletDoc, and use <span class=\"Inlinecode\"> Get-Help<\/span> on the <span class=\"Inlinecode\"> Get-Gizmo<\/span> cmdlet.)<\/p>\n<p> <img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2311-imgA.jpg\" alt=\"2311-imgA.jpg\" \/><\/p>\n<p>Let&#8217;s explore just how to do the documentation for the compiled PowerShell cmdlets.<\/p>\n<h2 id=\"second\">Getting Documentation out of your Cmdlets<\/h2>\n<p>You start, of course, with a Visual Studio project containing your cmdlets. This should be a project of type <b>Class Library<\/b>. Within your project in Visual Studio, you need to enable XML documentation creation (Go to &#8216;<i>Project  Properties<\/i>&#8216; &gt;&gt; &#8216;<i>build pane&#8217;<\/i> &gt;&gt; &#8216;<i>Output&#8217;<\/i>  and check the <code>XML documentation file<\/code> option) then compile your project. You will now find a corresponding XML file adjacent to your project DLL in your output directory. For example, attached to this article is a sample <code> CmdletSamplesProject <\/code>solution that generates <code>CmdletSamples.dll<\/code> and, with the above setting, <code>CmdletSamples.XML<\/code>. Note that this XML file is an intermediate file; it is <i>not<\/i> the requisite MAML file that PowerShell needs in order to generate documentation.<\/p>\n<p> Here&#8217;s the code for our initial cmdlet, <span class=\"Inlinecode\"> <code>  Get-Gizmo<\/code><\/span>, that you will find in the sample project. To be a cmdlet you have to both derive from <span class=\"Inlinecode\"> <code> Cmdlet<\/code><\/span> and decorate the class with the <span class=\"Inlinecode\"> <b> <code>Cmdlet<\/code><\/b><\/span> attribute, as you will see below. To give your cmdlet parameters, you need to create each as a public property and decorate each with the <span class=\"Inlinecode\"><code>  Parameter<\/code><\/span> attribute. Here you will see two: <span class=\"Inlinecode\"><b> <code>Flavor<\/code><\/b><\/span>, which is an auto-generated property, and <span class=\"Inlinecode\"><code> Quantity<\/code><\/span>, which has a backing field. The <span class=\"Inlinecode\"> <b> <code>ProcessRecord<\/code><\/b><\/span> method is where the actual work of your cmdlet gets done, but that is not germane to creating the documentation.<\/p>\n<pre class=\"lang:c# theme:vs2012\">       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"synopsis\"&gt;This is the cmdlet synopsis.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;This is part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Also part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n       {\r\n              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(Position = 0,\r\n                     Mandatory = true,\r\n                     ValueFromPipeline=true,\r\n                     HelpMessage = \"Enter the flavor name, e.g. Marshmallow\")]\r\n              [Alias(\"Aroma\",\"JeNeSaisQuoi\")]\r\n              public FlavorTypes Flavor { get; set; }\r\n \r\n              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The quantity of the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter()]\r\n              public int Quantity {\r\n                     get { return _quantity; }\r\n                     set { _quantity = value; }\r\n              }\r\n              private int _quantity = 42;\r\n \r\n \r\n              protected override void ProcessRecord()\r\n              {\r\n                     base.ProcessRecord();\r\n              }\r\n       }\r\n \r\n       public enum FlavorTypes\r\n       {\r\n              Chocolate,\r\n              Vanilla,\r\n              Marshmallow\r\n       }\r\n<\/pre>\n<p>That cmdlet is compiled into the <b>CmdletSamples.dll<\/b>. In a PowerShell window import the DLL as a module. You can then use <span class=\"Inlinecode\"> <b> <code>Get-Command<\/code><\/b><\/span> to list its cmdlets. (Note that the red text is what you type.)<\/p>\n<pre class=\"lang:c# theme:vs2012\"> PS&gt; Import-Module .\\CmdletSamples\\bin\\Debug\\CmdletSamples.dll\r\n \r\nPS&gt; Get-Command -Module CmdletSamples\r\nCommandType     Name                                               ModuleName\r\n-----------     ----                                               ----------\r\nCmdlet          Get-Gizmo                                          CmdletSamples\r\n<\/pre>\n<p>Before doing <i>any<\/i> documentation generation, let&#8217;s execute <span class=\"Inlinecode\"> <code> Get-Help<\/code><\/span> and review the output. As shown below, it is quite basic; but only because it has little to go on. It knows the syntax of the cmdlet and the properties of its parameters from processing the DLL. Also, because of the <span class=\"Inlinecode\"> <code> HelpMessage<\/code> <\/span>attribute on the <span class=\"Inlinecode\"> <code>Flavor<\/code><\/span> parameter, it can present a brief description of that parameter.<\/p>\n<pre class=\"lang:c# theme:vs2012\"> PS&gt; Get-Help Get-Gizmo -full\r\nNAME\r\n    Get-Gizmo\r\n \r\nSYNTAX\r\n    Get-Gizmo [-Flavor] &lt;FlavorTypes&gt; {Chocolate | Vanilla | Marshmallow} [-Quantity &lt;int&gt;]  [&lt;CommonParameters&gt;]\r\n \r\n \r\nPARAMETERS\r\n    -Flavor &lt;FlavorTypes&gt;\r\n        Enter the flavor name, e.g. Marshmallow\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Accept pipeline input?       true (ByValue)\r\n        Parameter set name           (All)\r\n        Aliases                      Aroma, JeNeSaisQuoi\r\n        Dynamic?                     false\r\n \r\n    -Quantity &lt;int&gt;\r\n \r\n        Required?                    false\r\n        Position?                    Named\r\n        Accept pipeline input?       false\r\n        Parameter set name           (All)\r\n        Aliases                      None\r\n        Dynamic?                     false\r\n \r\n    &lt;CommonParameters&gt;\r\n        This cmdlet supports the common parameters: Verbose, Debug,\r\n        ErrorAction, ErrorVariable, WarningAction, WarningVariable,\r\n        OutBuffer and OutVariable. For more information, see\r\n        about_CommonParameters (http:\/\/go.microsoft.com\/fwlink\/?LinkID=113216).\r\n \r\n \r\nINPUTS\r\n    System.String\r\n \r\n \r\nOUTPUTS\r\n    System.Object\r\n \r\nALIASES\r\n    None\r\n<\/pre>\n<p>Next let&#8217;s apply the documentation generator:<\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt; C:\\lib\\XmlDoc2CmdletDoc.exe .\\CmdletSamples\\bin\\Debug\\CmdletSamples.dll\r\n<\/pre>\n<p>In your output directory, besides the DLL and the XML files, you will now also find a <code> CmdletSample.dll-Help.xml<\/code> file that contains the help text in MAML format, which PowerShell can directly consume. So now look at the help we get from the cmdlet-you will need to re-import the module with the <span class=\"Inlinecode\"> -Force<\/span> parameter, though!<\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt; Import-Module .\\CmdletSamples\\bin\\Debug\\CmdletSamples.dll -force\r\n \r\nPS&gt; Get-Help Get-Gizmo -full\r\n \r\nNAME\r\n    Get-Gizmo\r\n \r\nSYNOPSIS\r\n    This is the cmdlet synopsis.\r\n \r\nSYNTAX\r\n    Get-Gizmo [-Flavor] &lt;FlavorTypes&gt; {Chocolate | Vanilla | Marshmallow} [-Quantity &lt;int&gt;] [&lt;CommonParameters&gt;]\r\n \r\n \r\nDESCRIPTION\r\n    This is part of the longer cmdlet description.\r\n \r\n    Also part of the longer cmdlet description.\r\n \r\n \r\nPARAMETERS\r\n    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  false\r\n \r\n    -Aroma &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        This is an alias of the Flavor parameter.\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  false\r\n \r\n    -JeNeSaisQuoi &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        This is an alias of the Flavor parameter.\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  false\r\n \r\n    -Quantity &lt;int&gt;\r\n        The quantity of the gizmo.\r\n \r\n        Required?                    false\r\n        Position?                    named\r\n        Default value                42\r\n        Accept pipeline input?       false\r\n        Accept wildcard characters?  false\r\n \r\n    &lt;CommonParameters&gt;\r\n        This cmdlet supports the common parameters: Verbose, Debug,\r\n        ErrorAction, ErrorVariable, WarningAction, WarningVariable,\r\n        OutBuffer and OutVariable. For more information, see\r\n        about_CommonParameters (http:\/\/go.microsoft.com\/fwlink\/?LinkID=113216).\r\n \r\nINPUTS\r\n    CmdletSamples.FlavorTypes\r\n \r\n        The flavor for the gizmo.\r\n \r\nOUTPUTS\r\n \r\n \r\nRELATED LINKS\r\n \r\n<\/pre>\n<p>Compare this help text with the previous version without documentation generation, and you will see all the additional sections that now show up in the help. <\/p>\n<p>(Note: Curiously there is one thing you lose, too:  with no help file for the module, parameters document three properties-Parameter set name, Aliases, and Dynamic-that are absent when you add the help file! But those same three properties are also absent from standard\/built-in cmdlets, so <code> XmlDoc2CmdletDoc<\/code> is just mirroring what the .NET framework did.)<\/p>\n<h2 id=\"third\">Components of Cmdlet Help<\/h2>\n<p>Without further ado, here is a brief description of each of the sections of the help output for a PowerShell cmdlet.<\/p>\n<h3 id=\"fourth\">Name<\/h3>\n<div class=\"indent\">\n<p>The name of the cmdlet; think of this as the title of the help page.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p><i>Noun<\/i>&#8211;<i>Verb<\/i>, where <i>Noun<\/i> and <i>Verb<\/i> are the arguments to the <span class=\"Inlinecode\"> Cmdlet<\/span> attribute attached to the cmdlet, highlighted here: <\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:1\">       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n<\/pre>\n<\/div>\n<h3 id=\"fifth\">Synopsis<\/h3>\n<div class=\"indent\">\n<p>A brief summary of the cmdlet, typically just a single sentence.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>The <span class=\"Inlinecode\"> synopsis<\/span> paragraph in the summary attached to the cmdlet. <\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:2\">       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"synopsis\"&gt;This is the cmdlet synopsis.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;This is part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Also part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n<\/pre>\n<\/div>\n<h3 id=\"sixth\">Syntax<\/h3>\n<div class=\"indent\">\n<p>This auto-generated section lays out all the possible parameters and parameter combinations that are valid for the cmdlet, using a common variant of the well-known <a href=\"https:\/\/en.wikipedia.org\/wiki\/Backus-Naur_Form\">Backus-Naur Form<\/a> notation.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>Derived from the parameters of your cmdlet.<\/p>\n<\/p><\/div>\n<h3 id=\"seventh\">Description<\/h3>\n<div class=\"indent\">\n<p>This is where you explain-in as much detail as appropriate-what your cmdlet does, how to use it, what to watch out for, and things to keep in mind when using it. In other words, <i>everything<\/i> your user needs to know to use your cmdlet effectively, <i>except<\/i> for the details you add to specific parameters and to specific examples.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>The <span class=\"Inlinecode\"> description<\/span> paragraphs in the summary attached to the cmdlet. <\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:3,4\">       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"synopsis\"&gt;This is the cmdlet synopsis.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;This is part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Also part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n<\/pre>\n<\/p><\/div>\n<h3 id=\"eighth\">Parameters<\/h3>\n<div class=\"indent\">\n<p>This section enumerates each of your parameters, documenting values for common properties (whether the parameter is required, what its default value is, etc.) and providing a description of each parameter, supplementing your cmdlet&#8217;s description.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>The <span class=\"Inlinecode\"> description<\/span> paragraphs in the summary attached to a parameter, along with its <code>Parameter<\/code> and <code> Alias<\/code> attributes. <\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:2,4,5,6,8,9\">              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(Position = 0,\r\n                     Mandatory = true,\r\n                     ValueFromPipeline=true,\r\n                     HelpMessage = \"Enter the flavor name, e.g. Marshmallow\")]\r\n              [Alias(\"Aroma\",\"JeNeSaisQuoi\")]\r\n              public FlavorTypes Flavor { get; set; }\r\n        <\/pre>\n<\/p><\/div>\n<h3 id=\"ninth\">Inputs<\/h3>\n<div class=\"indent\">\n<p>This auto-generated section enumerates each type of object that may be piped to your cmdlet.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>The <span class=\"Inlinecode\"> description<\/span> paragraph and parameter type for each parameter decorated with the <span class=\"Inlinecode\"> <strong>ValueFromPipeline<\/strong><\/span> or<strong> <\/strong> <span class=\"Inlinecode\">  <strong>ValueFromPipelineByPropertyName<\/strong><\/span> argument in its <span class=\"Inlinecode\"> Parameter<\/span> attribute.<\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:2,6,9\">              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(Position = 0,\r\n                     Mandatory = true,\r\n                     ValueFromPipeline=true,\r\n                     HelpMessage = \"Enter the flavor name, e.g. Marshmallow\")]\r\n              [Alias(\"Aroma\",\"JeNeSaisQuoi\")]\r\n              public FlavorTypes Flavor { get; set; }\r\n                <\/pre>\n<\/div>\n<h3 id=\"tenth\">Outputs<\/h3>\n<div class=\"indent\">\n<p>This auto-generated section enumerates each type of object that your cmdlet may return.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>The argument to the <span class=\"Inlinecode\">  OutputType<\/span> attribute(s) attached to the cmdlet and the <code>description<\/code> paragraph of the referenced type.<\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:2\">       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n<\/pre>\n<\/p><\/div>\n<h3 id=\"eleventh\">Notes<\/h3>\n<div class=\"indent\">\n<p>Here you provide any ancillary information that may be relevant, just not worth cluttering up the main description with. Think of this as akin to footnotes.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>A list of type <span class=\"Inlinecode\"> <b> <code>alertSet<\/code><\/b><\/span> in the doc-comments attached to the cmdlet. Each <span class=\"Inlinecode\"><code> &lt;item&gt;<\/code><\/span> constitutes one note. Within each <span class=\"Inlinecode\"> <b> <code>&lt;item&gt;<\/code><\/b><\/span>, the <span class=\"Inlinecode\"> <code> &lt;term&gt;<\/code><\/span> is the title and the <code>&lt;description&gt;<\/code> is the content of the note. The <code>&lt;description&gt;<\/code> may be text only or it may contain one or more <span class=\"Inlinecode\"> <code> &lt;para&gt;<\/code><\/span> elements.<\/p>\n<p> <code>Example:<\/code><\/p>\n<pre class=\"lang:c# theme:vs2012\">    \/\/\/ &lt;list type=\"alertSet\"&gt;\r\n    \/\/\/   &lt;item&gt;\r\n    \/\/\/     &lt;term&gt;First Note&lt;\/term&gt;\r\n    \/\/\/     &lt;description&gt;\r\n    \/\/\/     This is the description for the first note.\r\n    \/\/\/     &lt;\/description&gt;\r\n    \/\/\/   &lt;\/item&gt;\r\n    \/\/\/   &lt;item&gt;\r\n    \/\/\/     &lt;term&gt;Second Note&lt;\/term&gt;\r\n    \/\/\/     &lt;description&gt;\r\n    \/\/\/       &lt;para&gt;This is part of the description for the second note.&lt;\/para&gt;\r\n    \/\/\/       &lt;para&gt;This is also part of the description for the second note.&lt;\/para&gt;\r\n    \/\/\/     &lt;\/description&gt;\r\n    \/\/\/   &lt;\/item&gt;\r\n    \/\/\/ &lt;\/list&gt;\r\n        <\/pre>\n<p> <code>Known Issues<\/code>:<\/p>\n<p>PowerShell does not layout multiple notes very well. To simulate multiple notes, it is better to use a single note (<span class=\"Inlinecode\"><code>&lt;item&gt;<\/code><\/span><code> <\/code>element) with multiple paragraphs (<span class=\"Inlinecode\"><code>&lt;para&gt;<\/code><\/span><code> <\/code>elements) and with no title (<span class=\"Inlinecode\"><code>&lt;term&gt;<\/code><\/span><code> <\/code>element). (See source issue on GitHub: <a href=\"https:\/\/github.com\/red-gate\/XmlDoc2CmdletDoc\/issues\/9\">Multiple notes  do not render as expected<\/a>)<\/p>\n<\/p><\/div>\n<h3 id=\"twelveth\">Examples<\/h3>\n<div class=\"indent\">\n<p>An important section but often given short shrift, this is where you show the world how to really use your cmdlet. You should include exactly what needs to be typed, describe what happens with the particular set of parameters you are using, and even show some sample output, when appropriate.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>One or more <span class=\"Inlinecode\"> <b> <code>&lt;example&gt;<\/code><\/b><\/span> elements in the doc-comments attached to the cmdlet. Each example may contains one or more paragraphs (<span class=\"Inlinecode\"><code>&lt;para&gt;<\/code><\/span><code> <\/code>elements preceding <span class=\"Inlinecode\"> <code> &lt;code&gt;<\/code><\/span>) as introductory text, then the example invocation (<span class=\"Inlinecode\"><code>&lt;code&gt;<\/code><\/span> element), and one or more remarks (<span class=\"Inlinecode\"><code>&lt;para&gt;<\/code><\/span><code> <\/code>elements following <span class=\"Inlinecode\"> <code> &lt;code&gt;<\/code><\/span>).<\/p>\n<p> <b>Example:<\/b><\/p>\n<pre class=\"lang:c# theme:vs2012\">    \/\/\/ &lt;example&gt;\r\n    \/\/\/   &lt;para&gt;This is part of the first example's introduction.&lt;\/para&gt;\r\n    \/\/\/   &lt;para&gt;This is also part of the first example's introduction.&lt;\/para&gt;\r\n    \/\/\/   &lt;code&gt;New-Thingy | Write-Host&lt;\/code&gt;\r\n    \/\/\/   &lt;para&gt;This is part of the first example's remarks.&lt;\/para&gt;\r\n    \/\/\/   &lt;para&gt;This is also part of the first example's remarks.&lt;\/para&gt;\r\n    \/\/\/ &lt;\/example&gt;\r\n                <\/pre>\n<p> <code>Known Issues<\/code>:<\/p>\n<p>In principle, you can include introductory text as shown in the example; but in practice PowerShell does not render it particularly well. And in fact, when Chris investigated this reported issue, he noted that there were virtually no standard .NET cmdlets that even tried to include introductory paragraphs. It is better to describe your example in remarks <i>following<\/i> the <span class=\"Inlinecode\"> &lt;code&gt;<\/span> element. (See source issue on GitHub: <a href=\"https:\/\/github.com\/red-gate\/XmlDoc2CmdletDoc\/issues\/1\">No newline after  an example&#8217;s introduction<\/a>)<\/p>\n<\/p><\/div>\n<h3 id=\"thirteenth\">Related Links<\/h3>\n<div class=\"indent\">\n<p>A list of related topics, typically other cmdlet names (e.g. <code>Get-ChildItem<\/code>, <b>New-Alias<\/b>, etc.), other PowerShell help topic names (e.g. <code>about_Providers<\/code>), or ordinary URLs pointing to web pages.<\/p>\n<p> <code>Source:<\/code><\/p>\n<p>Paragraphs of type <span class=\"Inlinecode\"> <code> link<\/code><\/span>, which may optionally include a <span class=\"Inlinecode\"><code> uri<\/code><\/span> attribute for web pages. Convention is <i>not<\/i> to include a <span class=\"Inlinecode\"><code> uri<\/code><\/span> for standard PowerShell help topics, since those would be immediately accessible with another invocation of <span class=\"Inlinecode\"> <code> Get-Help<\/code><\/span>.<\/p>\n<p> <b>Example:<\/b><\/p>\n<pre class=\"lang:c# theme:vs2012 mark:6,7\">       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"synopsis\"&gt;This is the cmdlet synopsis.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;This is part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Also part of the longer cmdlet description.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       \/\/\/ &lt;para type=\"link\" uri=\"http:\/\/tempuri.org\"&gt;My Web Page&lt;\/para&gt;\r\n       \/\/\/ &lt;para type=\"link\"&gt;about_Gizmos&lt;\/para&gt;\r\n       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n \r\n<\/pre>\n<p> <code>Known Issues<\/code>:<\/p>\n<p>If you include a URI in your link, PowerShell renders it by simply juxtaposing it next to the text, so the output would appear as:<\/p>\n<pre>My Web Page http:\/\/tempuri.org<\/pre>\n<p>Call me particular, but that is not user-friendly! I urge you to include some textual demarcation in your <span class=\"Inlinecode\"> uri<\/span> attribute. I recommend using the standard <a href=\"http:\/\/daringfireball.net\/projects\/markdown\/syntax\">markdown<\/a> format for <a href=\"http:\/\/daringfireball.net\/projects\/markdown\/syntax#link\">hyperlinks<\/a>:<\/p>\n<pre class=\"lang:c# theme:vs2012\">       \/\/\/ &lt;para type=\"link\" uri=\"(http:\/\/tempuri.org)\"&gt;[My Web Page]&lt;\/para&gt;<\/pre>\n<p>The link will then be rendered by <span class=\"Inlinecode\"> <code> Get-Help<\/code><\/span> like this (and could potentially be made into a live link should you pass the help text through a post-processor that understands markdown):<\/p>\n<pre> [My Web Page](http:\/\/tempuri.org)<\/pre>\n<p>Of course, this could easily be compensated for by XmlDoc2CmdletDoc so perhaps by the time you read this it may already be fixed-see issue #10: <a href=\"https:\/\/github.com\/red-gate\/XmlDoc2CmdletDoc\/issues\/10\">Render related  web links to be more user friendly<\/a>.<\/p>\n<h1 id=\"fourteenth\">Parameters<\/h1>\n<p>So far, you learned the fundamentals of documenting your PowerShell binary cmdlets written in C#. I&#8217;ve explained the basics of what was needed: adding a <span class=\"Inlinecode\"> <b> <code>synopsis<\/code><\/b><\/span> paragraph and <span class=\"Inlinecode\"> <code> description<\/code><\/span> paragraphs to each cmdlet class, and also adding <span class=\"Inlinecode\"> <b> <code>description<\/code><\/b><\/span> paragraphs to each parameter. I then described all the moving pieces needed to be able to thoroughly document your custom set of PowerShell cmdlets. <\/p>\n<p>This section provides a further bit of sanding and polishing, if you will, to really make your documentation shine! Specifically you will learn the particulars about documenting the parameters of your cmdlets.<\/p>\n<h2 id=\"fifteenth\">Parameter Description<\/h2>\n<p>The <i>parameter  description<\/i> is text of arbitrary length describing a given parameter.  Consider the <span class=\"Inlinecode\"> <code> Flavor<\/code><\/span><b> <\/b>parameter, repeated here:<\/p>\n<pre class=\"lang:c# theme:vs2012\">              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(Position = 0,\r\n                     Mandatory = true,\r\n                     ValueFromPipeline=true,\r\n                     HelpMessage = \"Enter the flavor name, e.g. Marshmallow\")]\r\n              [Alias(\"Aroma\",\"JeNeSaisQuoi\")]\r\n              public FlavorTypes Flavor { get; set; }\r\n<\/pre>\n<p>With <i>no<\/i> help file (i.e. without using <code>XmlDoc2CmdletDoc<\/code>), this description stems from the <span class=\"Inlinecode\"> HelpMessage<\/span> property:<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Flavor &lt;FlavorTypes&gt;\r\n        Enter the flavor name, e.g. Marshmallow\r\n<\/pre>\n<p>However, <i>with<\/i> a help file present, the description instead comes from the <span class=\"Inlinecode\"><code> description<\/code><\/span> paragraph within the <span class=\"Inlinecode\"> <b> <code>&lt;summary&gt;<\/code><\/b><\/span> element immediately preceding the parameter. Since the goal here is to generate just such a help file, you should utilize this <span class=\"Inlinecode\"><code>  &lt;summary&gt;<\/code><\/span> element for your description.<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n<\/pre>\n<p>The <span class=\"Inlinecode\"> <b> <code>HelpMessage<\/code><\/b><\/span> property is still useful, though. When a parameter is required but <i>not<\/i> supplied on the command-line, PowerShell prompts you to enter its value. If you are not sure what it expects for the value, you can ask for more information at that prompt. That&#8217;s where the <span class=\"Inlinecode\"> <b> <code>HelpMessage<\/code><\/b><\/span> appears: <\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt; Get-Gizmo\r\n \r\ncmdlet Get-Gizmo at command pipeline position 1\r\nSupply values for the following parameters:\r\n(Type !? for Help.)\r\nFlavor: !?\r\nEnter the flavor name, e.g. Marshmallow\r\nFlavor:\r\n<\/pre>\n<h2 id=\"sixteenth\">Parameter Enumerated Types<\/h2>\n<p>When my colleagues and I at NextIT were working to rapidly integrate <code>XmlDoc2CmdletDoc<\/code> into our build process, I noticed that we had to manually document the possible values for an <code>enum<\/code>. And, if you look at standard .NET cmdlets that is how they do it as well-this is clearly manually written documentation:<\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt;  Get-Help Add-Computer -Param Options\r\n-Options &lt;JoinOptions&gt;\r\n    Sets advanced options for the Add-Computer join operation. Enter one or more values\r\n    in a comma-separated string.\r\n \r\n    Valid values are:\r\n \r\n    -- AccountCreate: Creates a domain account. The Add-Computer cmdlet automatically\r\n    creates a domain account when it adds a computer to a domain. This option is\r\n    included for completeness.\r\n \r\n    -- Win9XUpgrade: Indicates that the join operation is part of a Windows operating\r\n    system upgrade.\r\n \r\n    -- UnsecuredJoin: Performs an unsecured join. To request an unsecured join, use the\r\n    Unsecure parameter or this option.\r\n<\/pre>\n<p>I thought we could do better, and so I tweaked <code>XmlDoc2CmdletDoc<\/code> to auto-document the enumerated values. Thus, with just this code:<\/p>\n<pre class=\"lang:c# theme:vs2012\">              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(Position = 0, Mandatory = true, ...)]\r\n              public FlavorTypes Flavor { get; set; }\r\n<\/pre>\n<p>You would get this output &#8211; notice the <b>Possible values<\/b> line automatically inserted:<\/p>\n<pre class=\"lang:c# theme:vs2012\">PARAMETERS\r\n    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  False\r\n \r\n<\/pre>\n<p>(Of course, if you need or want to explain those <code>enum<\/code> values, you will still need manually written comments, but in many cases the auto-generated text would be sufficient.)<\/p>\n<p>But there&#8217;s more. Notice at the very beginning-before using <code>XmlDoc2CmdletDoc<\/code>-the <code>Syntax<\/code> section listed the possible <code>enum<\/code> values right there:<\/p>\n<pre class=\"lang:c# theme:vs2012\">SYNTAX\r\n    Get-Gizmo [-Flavor] &lt;FlavorTypes&gt; {Chocolate | Vanilla | Marshmallow} [-Quantity &lt;int&gt;]  [&lt;CommonParameters&gt;]\r\n        <\/pre>\n<p>But standard .NET cmdlets do <i>not<\/i> do this!<\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt;  Get-Help Add-Computer\r\nSYNTAX\r\n    Add-Computer [-DomainName] &lt;String&gt; [-ComputerName &lt;String[]&gt;] [-Force\r\n    [&lt;SwitchParameter&gt;]] [-LocalCredential &lt;PSCredential&gt;] [-NewName &lt;String&gt;]\r\n    [-Options &lt;JoinOptions&gt;] [-OUPath &lt;String&gt;] . . .\r\n        <\/pre>\n<p>And that&#8217;s also the way that <b>XmlDoc2CmdletDoc<\/b> worked when I found it. But I really liked the idea of listing the <code>enum<\/code> values in the <code>Syntax<\/code> section so I updated the code to do that. (Thus you will find support for both forms of auto-documenting enums merged into the latest version of <code> XmlDoc2CmdletDoc<\/code>!)<\/p>\n<h2 id=\"seventeenth\">Parameter Alias<\/h2>\n<p>PowerShell lets you define one or more <i>aliases<\/i> both to cmdlets and to parameters of a cmdlet.  The <span class=\"Inlinecode\"><code> Flavor<\/code><\/span> parameter, for example, defines two aliases. With the following code you could invoke <span class=\"Inlinecode\"><code> Get-Gizmo -Flavor<\/code><\/span> or <span class=\"Inlinecode\"><code>  Get-Gizmo -Aroma<\/code><\/span> or <span class=\"Inlinecode\"> <b> <code>Get-Gizmo -JeNeSaisQuoi<\/code><\/b><\/span>.<\/p>\n<pre class=\"lang:c# theme:vs2012\">              [Alias(\"Aroma\",\"JeNeSaisQuoi\")]\r\n              public FlavorTypes Flavor { get; set; }\r\n        <\/pre>\n<p>Standard PowerShell documentation does little to document those aliases automatically. It is up to the developer who is  writing the documentation comments to mention the alias as was done, for example, with the <span class=\"Inlinecode\"> <code> File<\/code><\/span><b> <\/b>parameter for <span class=\"Inlinecode\"> <b> <code>Get-ChildItem<\/code><\/b><\/span> and its alias <span class=\"Inlinecode\"> <code> af<\/code><\/span><b>:<\/b><\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt; Get-Help Get-ChildItem -Param file\r\n \r\n-File [&lt;SwitchParameter&gt;]\r\n    Gets files.\r\n \r\n    To get only files, use the File parameter and omit the Directory parameter. To\r\n    exclude files, use the Directory parameter and omit the File parameter, or use the\r\n    Attributes parameter.\r\n \r\n    To get files, use the File parameter, its \"af\" alias, or the File value of the\r\n    Attributes parameter.\r\n<\/pre>\n<p>What if you knew the alias, <span class=\"Inlinecode\"> <code> -af<\/code><\/span>, but did not know the actual parameter name, and wanted to get help? If you try <span class=\"Inlinecode\"> <code> Get-Help Get-ChildItem -Param af<\/code><\/span>, PowerShell will simply report that it does not know of any such parameter. Fear not! <code>XmlDoc2CmdletDoc<\/code> makes this more convenient for you and your users. It essentially promotes each alias to be a first-class parameter with respect to the generated help. Excerpting the help shown earlier, you will see that both the <span class=\"Inlinecode\"> <code> Flavor<\/code><\/span> parameter and its aliases are documented identically (with the one exception that each alias explicitly identifies itself as an alias).<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  false\r\n \r\n    -Aroma &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        This is an alias of the Flavor parameter.\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  false\r\n \r\n    -JeNeSaisQuoi &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        This is an alias of the Flavor parameter.\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  False\r\n<\/pre>\n<p>You automatically get a second benefit as well. You can now ask for help on a parameter using either the actual parameter name <i>or any of its aliases<\/i>; each of these commands will yield the same help text!<\/p>\n<pre class=\"lang:c# theme:vs2012\">PS&gt; Get-Help Get-Gizmo -Param Flavor\r\nPS&gt; Get-Help Get-Gizmo -Param Aroma\r\nPS&gt; Get-Help Get-Gizmo -Param JeNeSaisQuoi\r\n<\/pre>\n<h2 id=\"eighteenth\">Parameter Default Values<\/h2>\n<p>Often you want to define a <i>default value<\/i> for a given parameter. When writing a <i>scripted<\/i> cmdlet (i.e. a cmdlet written in PowerShell rather than C#), this is straightforward to do: just supply a default value in the function signature:<\/p>\n<pre class=\"lang:c# theme:vs2012\">              function Get-Value($count = 42) {\r\n                     Write-Output $count\r\n              } \r\n        <\/pre>\n<p>When writing regular C# methods, you could provide default values in a similar fashion, but <i>not so<\/i> when writing a <i>compiled<\/i> cmdlet (i.e. a cmdlet written in C#). Here, you typically create a class deriving from <span class=\"Inlinecode\"><code> Cmdlet<\/code><\/span> (or <span class=\"Inlinecode\"><code>  PSCmdlet<\/code><\/span>) wherein each parameter is defined as a property, and the main processing of the cmdlet is done in the overridden <span class=\"Inlinecode\"> ProcessRecord<\/span> method (and its ilk). So the task, then, is how to provide a default value to a property in a way that the documentation generator will recognize it. It turns out to be actually quite straightforward once you know how: simply provide a backing field for a property that is initialized at compile time. You can see this done for the <span class=\"Inlinecode\"> <code>  Quantity<\/code><\/span> property in our cmdlet sample; here is the relevant portion of code:<\/p>\n<pre class=\"lang:c# theme:vs2012\">              public int Quantity {\r\n                     get { return _quantity; }\r\n                     set { _quantity = value; }\r\n              }\r\n              private int _quantity = 42;\r\n<\/pre>\n<p>The default value manifests in the documentation thus:<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Quantity &lt;int&gt;\r\n        The quantity of the gizmo.\r\n \r\n        Required?                    false\r\n        Position?                    named\r\n        Default value                42\r\n        Accept pipeline input?       false\r\n        Accept wildcard characters?  False\r\n<\/pre>\n<p>But the story does not end there!  Consider the <span class=\"Inlinecode\"> Flavor<\/span> parameter again-it lacks a backing field&#8230;<\/p>\n<pre class=\"lang:c# theme:vs2012\">              public FlavorTypes Flavor { get; set; }\r\n<\/pre>\n<p>&#8230; and yet the documentation yields a default value:<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n \r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n        Required?                    true\r\n        Position?                    0\r\n        Default value                Chocolate\r\n        Accept pipeline input?       true (ByValue)\r\n        Accept wildcard characters?  False\r\n<\/pre>\n<p>And if you add these other parameters, all <i>without<\/i> backing fields&#8230;<\/p>\n<pre class=\"lang:c# theme:vs2012\">              [Parameter()]\r\n              public int SomeInteger { get; set; }\r\n \r\n              [Parameter()]\r\n              public SwitchParameter SomeSwitch { get; set; }\r\n \r\n              [Parameter()]\r\n              public string SomeString { get; set; }\r\n \r\n              [Parameter()]\r\n              public DateTime SomeDateTime { get; set; }\r\n \r\n              [Parameter(ValueFromPipelineByPropertyName = true)]\r\n              public Container MyContainer { get; set; }\r\n        <\/pre>\n<p>&#8230;here&#8217;s what the documentation yields (I&#8217;ve filtered the output to just show the defaults for each):<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -SomeInteger &lt;int&gt;\r\n        Default value                0\r\n \r\n    -SomeSwitch &lt;SwitchParameter&gt;\r\n        Default value                False\r\n \r\n    -SomeString &lt;string&gt;\r\n        Default value\r\n \r\n    -SomeDateTime &lt;DateTime&gt;\r\n        Default value                1\/1\/0001 12:00:00 AM\r\n \r\n    -MyContainer &lt;Container&gt;\r\n        Default value\r\n<\/pre>\n<p>As you may have surmised, if you do <i>not<\/i> use a backing field to explicitly provide a default value then the compiler default is used: zero for an integer, false for a <span class=\"Inlinecode\"><code> Boolean<\/code><\/span>, empty string for a <code>string<\/code>, zero for a <span class=\"Inlinecode\"><code>  DateTime<\/code><\/span>, and so forth. So why did the <span class=\"Inlinecode\"><b> <code>Flavor<\/code><\/b><\/span> parameter (of type <span class=\"Inlinecode\">  FlavorTypes<\/span>) show a default of <span class=\"Inlinecode\"> <code>  Chocolate<\/code><\/span>? Hearken back to the enumerated <span class=\"Inlinecode\"><b> <code>FlavorType<\/code><\/b><\/span> definition:<\/p>\n<pre class=\"lang:c# theme:vs2012\">       public enum FlavorTypes\r\n       {\r\n              Chocolate,\r\n              Vanilla,\r\n              Marshmallow\r\n       }\r\n        <\/pre>\n<p>As it turns out, enumerated types map to the set of integers beginning with 0. Thus <span class=\"Inlinecode\"> <b> <code>Chocolate<\/code><\/b><\/span> is really equivalent to 0, but since it is an enumerated type, the documentation nicely displays its enumerated label. To expose this mechanism, force the <i> FlavorTypes<\/i> to start with something <i> other than<\/i> 0, e.g.<\/p>\n<pre class=\"lang:c# theme:vs2012\">       public enum FlavorTypes\r\n       {\r\n              Chocolate = 5,\r\n              Vanilla,\r\n              Marshmallow\r\n       }\r\n<\/pre>\n<p>Then the default in the documentation would show an actual 0, because there is now <i>no<\/i> label in the enumerated type that corresponds to 0.<\/p>\n<pre class=\"lang:c# theme:vs2012\">    -Flavor &lt;FlavorTypes&gt;\r\n        Default value                0\r\n        <\/pre>\n<p>Final note: you cannot really know <i>from the documentation<\/i> what the default value is when it is blank: in the case of the string parameter above it is an empty string, but for the <span class=\"Inlinecode\"><code> Container<\/code><\/span><code> <\/code>parameter above it is null!<\/p>\n<h2 id=\"nineteenth\">Input Parameters<\/h2>\n<p>You are likely to be familiar with  piping objects from one cmdlet to another. When you write your own cmdlets, you can make specific parameters receive pipeline input using either the <span class=\"Inlinecode\"> <b> <code>ValueFromPipeline<\/code><\/b><\/span><code> <\/code>property (which accepts a value of the same type expected by the parameter), or the<code> <\/code><span class=\"Inlinecode\"> <code>  ValueFromPipelineByPropertyName<\/code><\/span><code> <\/code>property (which accepts a value from a property of the input object of the same name as the parameter). Here are the salient portions of the sample cmdlet showing these in use on several parameters. Note that some have documentation comments and some do not. Some of those doc-comments are of type <span class=\"Inlinecode\"><b> <code>description<\/code><\/b><\/span>, and some of type <span class=\"Inlinecode\"> <code> inputType<\/code><\/span>. Some of the parameters are built-in .NET objects but some are custom objects. I&#8217;ve also included the custom <span class=\"Inlinecode\"><code>  Container<\/code><\/span> class definition for discussion as well.<\/p>\n<pre class=\"lang:c# theme:vs2012\">       public class GetGizmoCmdlet : Cmdlet\r\n       {\r\n              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;The flavor for the gizmo.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(ValueFromPipeline=true]\r\n              public FlavorTypes Flavor { get; set; }\r\n \r\n              [Parameter(ValueFromPipelineByPropertyName = true)]\r\n              public SwitchParameter SomeSwitch { get; set; }\r\n \r\n              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"inputType\"&gt;Input description for parameter.&lt;\/para&gt;\r\n              \/\/\/ &lt;para type=\"description\"&gt;Main description for parameter.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(ValueFromPipelineByPropertyName = true)]\r\n              public string SomeString { get; set; }\r\n \r\n              \/\/\/ &lt;summary&gt;\r\n              \/\/\/ &lt;para type=\"inputType\"&gt;Description for input only.&lt;\/para&gt;\r\n              \/\/\/ &lt;\/summary&gt;\r\n              [Parameter(ValueFromPipelineByPropertyName = true)]\r\n              public DateTime SomeDateTime { get; set; }\r\n \r\n              [Parameter(ValueFromPipelineByPropertyName = true)]\r\n              public Container MyContainer { get; set; }\r\n       }\r\n \r\n       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Container object.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       public class Container\r\n       {\r\n       }\r\n<\/pre>\n<p>Of course, all parameters, pipeline-able or not, are listed in the <code>Parameters<\/code> section of the documentation. But those that may receive input from the pipeline are also listed separately in the <code>Inputs<\/code> section. Here is what <code>XmlDoc2CmdletDoc<\/code> produces for those two sections, again compressed to show just the relevant portions.<\/p>\n<pre class=\"lang:c# theme:vs2012\">PARAMETERS\r\n \r\n    -Flavor &lt;FlavorTypes&gt;\r\n        The flavor for the gizmo.\r\n        Possible values: Chocolate, Vanilla, Marshmallow\r\n \r\n    -SomeSwitch &lt;SwitchParameter&gt;\r\n \r\n    -SomeString &lt;string&gt;\r\n        Main description for parameter.\r\n \r\n    -SomeDateTime &lt;DateTime&gt;\r\n \r\n    -MyContainer &lt;Container&gt;\r\n \r\nINPUTS\r\n \r\n    CmdletSamples.FlavorTypes\r\n        The flavor for the gizmo.\r\n \r\n    System.Management.Automation.SwitchParameter\r\n \r\n \r\n    System.String\r\n        Input description for parameter.\r\n \r\n    System.DateTime\r\n        Description for input only.\r\n \r\n    CmdletSamples.Container\r\n        Container object.\r\n        <\/pre>\n<p>Each of these five parameters is a different case. Study the code, comparing to the output, and you will discern the following:<\/p>\n<ul>\n<li>If a parameter is decorated with a <span class=\"Inlinecode\"><code> description<\/code><\/span> paragraph, that text appears in the <code> Parameters<\/code> section. [<span class=\"Inlinecode\"><code>Flavor<\/code><\/span>, <span class=\"Inlinecode\"><code>  SomeString<\/code><\/span>]<\/li>\n<li>If a parameter lacks a <span class=\"Inlinecode\"> <code> description<\/code><\/span><b> <\/b>paragraph, that parameter has no descriptive text in the <code>Parameters<\/code> section. [<span class=\"Inlinecode\"><code>SomeSwitch<\/code><\/span>, <span class=\"Inlinecode\"><code>  SomeDateTime<\/code><\/span>, <span class=\"Inlinecode\"> <code>  MyContainer<\/code><\/span>]<\/li>\n<li>If a parameter is decorated with an <span class=\"Inlinecode\"><code> inputType<\/code><\/span> paragraph, that text appears in the <code> Inputs<\/code> section. [<span class=\"Inlinecode\"><code>SomeString<\/code><\/span>, <span class=\"Inlinecode\"><code>  SomeDateTime<\/code><\/span>]<\/li>\n<li>If a parameter lacks an <span class=\"Inlinecode\"> <code> inputType<\/code><\/span> paragraph but has a <span class=\"Inlinecode\"><code> description<\/code><\/span><code> <\/code>paragraph, that text appears in the <code> Inputs<\/code> section. [<span class=\"Inlinecode\"><code>Flavor<\/code><\/span>]<\/li>\n<li>If a parameter lacks both an<b> <\/b><span class=\"Inlinecode\"><code>  inputType<\/code><\/span> and a <span class=\"Inlinecode\"> <code>description<\/code><\/span> paragraph, then the <span class=\"Inlinecode\"><code> description<\/code><\/span> paragraph of the parameter&#8217;s type appears in the <b>Inputs<\/b> section. [<span class=\"Inlinecode\"><b><code>MyContainer<\/code><\/b><\/span>]<\/li>\n<li>If a parameter lacks both an <span class=\"Inlinecode\"><code> inputType<\/code><\/span> and a <span class=\"Inlinecode\"> <code>description<\/code><\/span> paragraph, and the parameter&#8217;s type lacks a<code> <\/code> <span class=\"Inlinecode\"><code> description<\/code><\/span> paragraph (either because it is a .NET type or a custom type lacking a <span class=\"Inlinecode\"><code> description<\/code><\/span> paragraph), then that parameter has no descriptive text in the <code>Inputs<\/code> section. [<span class=\"Inlinecode\"><code>SomeSwitch<\/code><\/span>]<\/li>\n<\/ul>\n<h2 id=\"twentieth\">Output Parameters<\/h2>\n<p>Just as the <code>Inputs<\/code> section documents those parameters that may be <i>received<\/i> via the pipeline, the <code>Outputs<\/code> section documents those parameters that may be <i>transmitted<\/i> on to the next cmdlet in the pipeline. Unique to outputs, though, the crucial point to know is that the compiler does <i>not<\/i> validate what you specify as being the actual return type! That is, the compiler validates that the argument to the<code> <\/code><span class=\"Inlinecode\"><code> OutputType<\/code><\/span> attribute is a valid, known type. But it does <i>not<\/i> validate that your cmdlet is, in fact, returning objects of that type; and, if you think about it, that makes sense because a cmdlet does not have a method signature specifying its inputs and outputs. The inputs are simply the public properties, and the outputs are whatever objects are returned from the<b> <\/b><span class=\"Inlinecode\"><code>  base.WriteObject()<\/code><\/span><code> <\/code> call in your cmdlet (deriving from either <span class=\"Inlinecode\"> <code> Cmdlet<\/code><\/span> or <span class=\"Inlinecode\"><code>  PSCmdlet<\/code><\/span>). And you are even at liberty to return objects of different types in successive calls to <span class=\"Inlinecode\"> <code>  WriteObject<\/code><\/span>. <span class=\"Inlinecode\"> <code>  Get-ChildItem<\/code><\/span>, for example returns <span class=\"Inlinecode\"> <code>  FileInfo<\/code><\/span> objects and <span class=\"Inlinecode\"> <code>  DirectoryInfo<\/code><\/span> objects in a single invocation. You will see this reflected in the <code>Outputs<\/code> section of <span class=\"Inlinecode\"><code> Get-Help<\/code><\/span>: <\/p>\n<pre class=\"lang:c# theme:vs2012\">OUTPUTS\r\n    System.IO.DirectoryInfo, System.IO.FileInfo, System.String\r\n<\/pre>\n<p>Thus, take care that your <span class=\"Inlinecode\"> <code> OutputType<\/code><\/span> values are accurate as you maintain your code over time, and remember that <span class=\"Inlinecode\"> <code> OutputType<\/code><\/span> exists solely for the benefit of editors (for Intellisense) and documentation generators.<\/p>\n<p>As far as documentation usage, decorate the cmdlet class with the<code> <\/code><span class=\"Inlinecode\"> <code> OutputType<\/code><\/span> attribute, as you saw in the previous article:<\/p>\n<pre class=\"lang:c# theme:vs2012\">       [Cmdlet(VerbsCommon.Get, \"Gizmo\")]\r\n       [OutputType(typeof(Gizmo))]\r\n       public class GetGizmoCmdlet : Cmdlet\r\n<\/pre>\n<p>But another important point here is that<b> XmlDoc2CmdletDoc<\/b> can give you enhanced output (compared to standard .NET cmdlets) if you attach doc-comments <i>to your return type<\/i>&#8211;<span class=\"Inlinecode\"><b><code>Gizmo<\/code><\/b><\/span> in the example above:<\/p>\n<pre class=\"lang:c# theme:vs2012\">       \/\/\/ &lt;summary&gt;\r\n       \/\/\/ &lt;para type=\"description\"&gt;Description of the Gizmo class.&lt;\/para&gt;\r\n       \/\/\/ &lt;\/summary&gt;\r\n       public class Gizmo { . . . }\r\n<\/pre>\n<p>Your generated <code> Outputs<\/code> section will then list the return type you specified with<b> <\/b><span class=\"Inlinecode\"><code>  OutputType<\/code><\/span> along with the description taken from that type itself:<\/p>\n<pre class=\"lang:c# theme:vs2012\">OUTPUTS\r\n    CmdletSamples.Gizmo\r\n \r\n        Description of the Gizmo class.\r\n<\/pre>\n<p>That works well for your custom types. However, if your return type is a standard .NET class-which would <i>not<\/i> have the appropriate description paragraphs-then the help text will have only the type name with no description.<\/p>\n<h2 id=\"twentyfirst\">Summary<\/h2>\n<p>With the advent of <code> XmlDoc2CmdletDoc<\/code>, what used to be an arduous, tedious, and error-prone task of assembling documentation for PowerShell cmdlets has become much easier. <code>XmlDoc2CmdletDoc<\/code> brings the experience of documenting cmdlets much closer to that of both (a) documenting any other C# API,  and (b) documenting scripted cmdlets (i.e. those written in PowerShell itself). In both of these cases you put the documentation comments right alongside the code, greatly reducing the maintenance hassle.<\/p>\n<p>Furthermore, <code> XmlDoc2CmdletDoc<\/code> provides several enhancements to standard PowerShell documentation:<\/p>\n<ul>\n<li>Each custom type in the <b>Outputs<\/b> section includes a description.<\/li>\n<li>The <code>Syntax<\/code> section includes possible values for enumerated types*.<\/li>\n<li>The <code>Parameter<\/code> section includes possible values for enumerated types*.<\/li>\n<li>Aliases are documented automatically in the <code>Parameters<\/code> section*.<\/li>\n<li>Aliases are treated as first-class parameters so you can ask for help on an alias*.<\/li>\n<li>You can optionally use a different description for a parameter in the <code>Inputs<\/code> section as you have for the <code>Parameter<\/code> section.<\/li>\n<li>Web links are automatically rendered in markdown format, for possible post-processing to live links. (This enhancement is pending, as noted earlier.)<\/li>\n<li>You can require documentation of all elements by running with the -strict flag in your build process, then abort your build if the error code is non-zero.<\/li>\n<\/ul>\n<p> * The starred items are tweaks to the code base that I introduced as my colleagues and I were giving <b>XmlDoc2CmdletDoc<\/b> a good workout.<\/p>\n<p>This article provides all the details you need to effectively use <code>XmlDoc2CmdletDoc<\/code>. So what are you waiting for? Help your users help themselves by giving them thorough and complete documentation!<\/p>\n<div class=\"note\">\n<p><strong>Update &#8211; April 2016<\/strong><br \/>\n                <br \/>Since this article, I&#8217;ve created a wallchart putting both XmlDoc2Cmdlet and DocTreeGenerator in context, showing you how to do a complete documentation solution for your PowerShell work in both C# and PowerShell. <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/unified-approach-to-generating-documentation-for-powershell-cmdlets\/\">Click here for more details<\/a>.<br \/>\n                <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/unified-approach-to-generating-documentation-for-powershell-cmdlets\/\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2407-1-5728ddc3-433a-4b82-a6dc-84f5f450b519.png\" alt=\"2407-1-5728ddc3-433a-4b82-a6dc-84f5f450b\" \/><\/a>\n            <\/p>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Whereas it is easy to provide inline documentation for a normal scripted<br \/>\nPowerShell cmdlet or function so as&nbsp; to provide comprehensive help at the command-line or IDE, the same isn&#8217;t true of binary cmdlets written in C#. At last, there is an open-source utility to assist with this that is being actively<br \/>\nmaintained and updated. At last, binary cmdlets need no longer be the poor cousins of scripted cmdlets in their documentation&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4178,4371,4635,6011,4179,4306],"coauthors":[6802],"class_list":["post-2115","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-bi","tag-c","tag-powershell","tag-software-tools","tag-source-control","tag-ssis"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=2115"}],"version-history":[{"count":13,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2115\/revisions"}],"predecessor-version":[{"id":90789,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/2115\/revisions\/90789"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=2115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=2115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=2115"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=2115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}