Coder Social home page Coder Social logo

xmldoc2cmdletdoc's Introduction

XmlDoc2CmdletDoc

It's easy to write good help documentation for PowerShell script modules (those written in the PowerShell script language). You just write specially formatted comments alongside the source code for your cmdlets, and the PowerShell host automatically uses those comments to provide good inline help for your cmdlets' users. XmlDoc2CmdletDoc brings this same functionality to PowerShell binary modules (those written in C# or VB.NET). You no longer need to use CmdletHelpEditor or PowerShell Cmdlet Help Editor to manually edit a separate help file. Instead, this tool will automatically generate your PowerShell module's help file from XML Doc comments in your source code.

For more details, Michael Sorens has written a comprehensive guide to documenting your PowerShell binary cmdlets using XmlDoc2CmdletDoc.

To create a .dll-Help.xml file for your binary PowerShell module:

  1. Ensure that your project is configured to generate an XML Documentation file alongside its output assembly.
  2. Install the XmlDoc2CmdletDoc NuGet package into your project.

Optionally, you can enable strict mode to cause a build error if any of your cmdlets are missing required documentation elements. To do so, add the following property to an appropriate PropertyGroup element in your project file:

<XmlDoc2CmdletDocStrict>true</XmlDoc2CmdletDocStrict>

Examples

Here are some examples of how to document your cmdlets:

Cmdlet synopsis and description

The cmdlet's synopsis and description are defined using <para> elements in the cmdlet class's XML doc comment. Tag the <para> elements with a type="synopsis" or type="description" attribute, showing whether <para> is part of the synopsis or description.

You can use multiple <para> elements for both the synopsis and the description, but a cmdlet synopsis is usually just one sentence.

/// <summary>
/// <para type="synopsis">This is the cmdlet synopsis.</para>
/// <para type="description">This is part of the longer cmdlet description.</para>
/// <para type="description">This is also part of the longer cmdlet description.</para>
/// </summary>
[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    ...
}

For guidance on writing the cmdlet synopsis, see http://msdn.microsoft.com/en-us/library/bb525429.aspx. For guidance on writing the cmdlet description, see http://msdn.microsoft.com/en-us/library/bb736332.aspx.

Parameter description

The description for a cmdlet parameter is defined using <para> elements in the XML doc comment for the parameter's field or property. Tag the <para> elements with a type="description" attribute.

[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    /// <summary>
    /// <para type="description">This is part of the parameter description.</para>
    /// <para type="description">This is also part of the parameter description.</para>
    /// </summary>
    [Parameter]
    public string MyParameter {get; set;}
    
    ...
}

For guidance on writing the parameter description, see http://msdn.microsoft.com/en-us/library/bb736339.aspx.

Type description

You can document a parameter's input type or a cmdlet's output type, using <para> elements in the type's XML doc comment. As before, tag the <para> elements with a type="description" attribute.

You can only document types defined in the PowerShell module like this.

[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    [Parameter]
    public MyType MyParameter {get; set;}
    
    ...
}

/// <summary>
/// <para type="description">This is part of the type description.</para>
/// <para type="description">This is also part of the type description.</para>
/// </summary>
public class MyType
{
    ...
}

Notes

You can add notes to a cmdlet's help section using a <list> element with a type="alertSet" attribute. Each <item> sub-element corresponds to a single note.

Inside each <item> element, specify the note's title with the <term> sub-element, and the note's body text with the <description> sub-element. The <description> element can directly contain the note's body text, or you can split the note's body text into multiple paragraphs, using <para> elements.

/// <list type="alertSet">
///   <item>
///     <term>First note title</term>
///     <description>
///     This is the entire body text for the first note.
///     </description>
///   </item>
///   <item>
///     <term>Second note title</term>
///     <description>
///       <para>The first paragraph of the body text for the second note.</para>
///       <para>The second paragraph of the body text for the second note.</para>
///     </description>
///   </item>
/// </list>
[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    ...
}

For guidance on writing cmdlet notes, see http://msdn.microsoft.com/en-us/library/bb736330.aspx.

Examples

Cmdlet examples are defined using <example> elements in the XML doc comment for the cmdlet class.

The example's code body is taken from the <code> element. Any <para> elements before the <code> element become the example's introduction. Any <para> elements after the <code> element become the example's remarks. The introduction and remarks are both optional.

To add multiple cmdlet examples, use multiple <example> elements.

/// <example>
///   <para>This is part of the example's introduction.</para>
///   <para>This is also part of the example's introduction.</para>
///   <code>Test-MyExample | Wrte-Host</code>
///   <para>This is part of the example's remarks.</para>
///   <para>This is also part of the example's remarks.</para>
/// </example>
[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    ...
}

For guidance on writing cmdlet examples, see http://msdn.microsoft.com/en-us/library/bb736335.aspx.

Related links

Related links are defined using <para> elements in the XML doc comment for the cmdlet class. Tag the relevant <para> elements with a type="link" attribute. The link text for each navigation link is taken from the body of the <para> element. If you want to include a uri, specify a uri attribute in the <para> element.

/// <summary>
///   <para type="link">This is the text of the first link.</para>
///   <para type="link">This is the text of the second link.</para>
///   <para type="link" uri="https://github.com/red-gate/XmlDoc2CmdletDoc/">The XmlDoc2CmdletDoc website.</para>
/// </summary>
[Cmdlet("Test", "MyExample")]
public class TestMyExampleCommand : Cmdlet
{
    ...
}

For guidance on writing related links, see http://msdn.microsoft.com/en-us/library/bb736334.aspx.

Developer notes

XmlDoc2CmdletDoc has a handful of NuGet package dependencies that aren't yet available from the official public NuGet repository. Instead, they are included in a local file-based package source in the LocalNuGetPackageSource folder.

  1. RedGate.ThirdParty.JoltCore - A fork of the Jolt.NET productivity libraries, with some modifications. The source is publicly available under the same BSD licence as the original library.

  2. RedGate.Build - A PowerShell module that contains cmdlets used by this project's build scripts. The source is publicly available under version 2.0 of the Apache license.

XmlDoc2CmdletDoc itself is available under the 3-clause BSD license.

Building XmlDoc2CmdletDoc

Prerequisites:

  • Microsoft Visual Studio 2015 or Microsoft Build Tools 2015
  • PowerShell 4.0 or later.

To build XmlDoc2CmdletDoc, simply invoke .\build.ps1 from a PowerShell prompt. This will generate a NuGet package in the dist folder. If you'd like direct access to the XmlDoc2CmdletDoc.exe, it can be found in XmlDoc2CmdletDoc\bin\Debug or XmlDoc2CmdletDoc\bin\Release, depending on the configuration you build.

Contributors

xmldoc2cmdletdoc's People

Contributors

chrislambrou avatar lordmilko avatar mark-raymond avatar msorens avatar rymir75 avatar vonogre avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xmldoc2cmdletdoc's Issues

Provide more console details on how to correct 'System.NullReferenceException: Object reference not set to an instance of an object.'

While debugging 'System.NullReferenceException: Object reference not set to an instance of an object.' at XmlDoc2CmdletDoc.Core.Domain.Command.<>c.<get_OutputTypes> I eventually found the culprit to be the OutputType attribute on my cmdlet [OutputType(nameof(SomeObject))].

Removing it resolved it for now. It would be nice to know on which cmdlet, property or attribute it fails to easily correct the situation. At least the above will give guidance to others.

Example Section not Rendering in Terminal

I am trying to use this nuget in a project but for some reason only the example section of the help message does not appear in the terminal. My project uses version 0.3.0 of XmlDoc2CmdletDoc, by the way. I think this might actually be a bug with this library. Seeing that there have not been any updates as of recently, I am not sure if this project is still in maintenance mode but I figured it might be worth mentioning this issue.

/// <summary>
///    <para type="description"> lorem ipsum </para>
/// </summary>
/// <example>
///     <para> more text </para>
///     <code> Write-Host "Hello, World!" </code>
/// </example>
[Cmdlet(VerbsCommon.Write, "Hello")]
public class WriteHello : PSCmdlet { ... }

BadImageFormatException on x64 compiled cmdlet library

BadImageFormatException occurs if you want to create help documentation for x64 compiled cmdlet-libraries.

I found the reason in the XmlDoc2CmdletDoc.exe project properties: the project is configured for Any CPU but the checkbox "Prefer 32-bit" is checked. So the method LoadAssembly() in the Engine class will always raise an exception on loading a x64-compiled library.

2017-02-01 07_27_48-xmldoc2cmdletdoc - microsoft visual studio

Exception 'Could not load file or assembly...' when trying to load dll reference.

This was via command line because the .targets file command got a different error.

When I pass my dll into the exe I get the following exception:
AssemblyPath: C:\repos\WK.Devops.Scripts\PSModules\WkLocalTools\WkLocalTools\bin\x64\Debug\WkLocalTools.dll, OutputHelpFilePath: C:\repos\WK.Devops.Scripts\PSModules
\WkLocalTools\WkLocalTools\bin\x64\Debug\WkLocalTools.dll-Help.xml, TreatWarningsAsErrors False
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.Assembly.GetTypes()
at XmlDoc2CmdletDoc.Core.Engine.GetCommands(Assembly assembly)
at XmlDoc2CmdletDoc.Core.Engine.GenerateHelp(Options options)
Loader exception: System.IO.FileLoadException: Could not load file or assembly 'WK.OCP.Tax.DCS.Shared, Version=1.5.2.39, Culture=neutral, PublicKeyToken=f70b15a39674
a997' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
File name: 'WK.OCP.Tax.DCS.Shared, Version=1.5.2.39, Culture=neutral, PublicKeyToken=f70b15a39674a997' ---> System.IO.FileLoadException: Could not load file or assem
bly 'file:///C:\repos\WK.Devops.Scripts\PSModules\WkLocalTools\WkLocalTools\bin\x64\Debug\WK.OCP.Tax.DCS.Shared.dll' or one of its dependencies. Operation is not sup
ported. (Exception from HRESULT: 0x80131515)
File name: 'file:///C:\repos\WK.Devops.Scripts\PSModules\WkLocalTools\WkLocalTools\bin\x64\Debug\WK.OCP.Tax.DCS.Shared.dll' ---> System.NotSupportedException: An att
empt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This relea
se of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable th
e loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stack
Mark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& st
ackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boole
an forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at XmlDoc2CmdletDoc.Core.Engine.<>c__DisplayClass7_0.b__0(Object sender, ResolveEventArgs args)
at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)

GenerateHelp completed with exit code 'UnhandledException'

Allow for blocks in <Example> or <Description> tags to not always include a blank line

There is no way to add newline characters to examples or description tags. It would be helpful to be able to add newline characters to allow for generation of tables of possible output or example output. The only way to do this is to include a tag for each line, but this adds a blank line in between each line, causing readability to suffer.

I would like the PowerShell help file to include a table of possible output of a cmdlet. Something like:
image

This is the desired output formatting.

The associated MAML would be:
maml:paraPointID Timestamp Value
1 "1-Apr-2015 11:00:00" 100
2 "2-Apr-2015 12:00:00" 100
3 "3-Apr-2015 13:00:00" 100</maml:para>

However, this cannot be done with xmldoc2cmdletdoc, as it will generate:
maml:paraPointID Timestamp Value</maml:para>
maml:para1 "1-Apr-2015 11:00:00" 100</maml:para>
maml:para2 "2-Apr-2015 12:00:00" 100</maml:para>
maml:para3 "3-Apr-2015 13:00:00" 100</maml:para>

This causes the output to have unnecessary blank lines in between each line. Unfortunately I don't have a screenshot of the exact output for the case above, but it looks similar to:
image

I imagine quite a few other users would benefit from being able to properly format example output or tables within examples or parameter descriptions.

Let me know if I can provide any additional information

Removing online section or support

Hi,
Is it possible to remove the support for -online option and from the Remarks section ? Currently, we are not providing support for online help, however still we are able to see the online support in the Remark section and also with -option in Get-Help.
It would very helpful if you could guide me a way through which i can remove the online section from generated help?

Type description is not pulled in for OutputType target if type is in a separate DLL

One specifies the output type of a cmdlet by decorating the cmdlet class with the OutputType attribute, having a single argument that is the type that the cmdlet returns. If that type is in the same project (DLL) then the Outputs section of the help content will report it.

Example: Given this source...

/// <summary>
/// <para type="description">Container for xyz.</para>
/// </summary>
public class MyData {... }

/// <summary>
/// <para type="description">Container for xyz.</para>
/// </summary>
[OutputType(typeof(MyData))]
public class Get-Foo: Cmdlet {... }

If MyData is in the same DLL as Get-Foo, then you get this help content:

OUTPUTS
MyData
    Container for xyz.

But if MyData is in a separate DLL, the description paragraph does not render.

A way to manually define a parameter?

Is there a way to manually define a parameter? I've got a dynamic parameter in my cmdlet that as far as the help is concerned doesn't exist. Is there a way to create the help for it using this tool? I'd just edit the help file manually after its built, but if there's a way I can get away with automating it to some degree that would be better.

Force new line within paragraph?

I can't seem to get a newline within a paragraph. Multiple lines in a paragraph:

<para type="description">line 1
line 2
line 3
</para>

Are converted to a single-line <maml:para> element.

If I edit the generated .xml file and add line breaks, the help is rendered as expected.

Thank you,
Marko

Provide more console details on how to correct 'System.ArgumentException: Property Get method was not found.'

While debugging 'System.ArgumentException: Property Get method was not found.' at XmlDoc2CmdletDoc.Core.Domain.Parameter.get_DefaultValue() I eventually found it means you are messing a get'er on a Property like
public SomeObject SomeObject
{
set { _id = value.SomeRef; }
}

It would be nice to know on which cmdlet, property or attribute it fails to easily correct the situation. At least the above will give guidance to others.

Integration with Visual Studio projects

Rather than being deployed as a tool, and requiring users to update their build process to invoke the tool, it would be better to simply install XmlDoc2CmdletDoc into a project, and have it automatically plumbed in.

Currently we have the following snippet in one of our projects, and we have to manually update it every time we upgrade XmlDoc2CmdletDoc. A simple NuGet package update should be all that's required.

<Target Name="AfterBuild">
  <Exec Command="$(SolutionDir)packages\XmlDoc2CmdletDoc.0.1.0.9\tools\XmlDoc2CmdletDoc.exe -strict $(TargetPath)" />
</Target>

Any documentation on how to actually install and invoke it?

I've read the linked articles for how to document my binary module, but the article stops at explaining how to actually use XmlDoc2CmdletDoc. There's a flowchart but that doesn't explain how to install it (including the dependencies) or invoke it. Unless I'm missing something.

Parameterless Cmdlets generated with empty <command:syntax/> node

If a parameterless cmdlet is implemented, when the MAML is generated for the help file, this is the entirety of the syntax node:

<command:syntax/>

Instead, I'd expect something more akin to this, so that the syntax is actually displayed when get-help is invoked:

<command:syntax>
      <!-- Parameter set: __AllParameterSets -->
      <command:syntaxItem>
        <maml:name>Get-ParameterlessCmdletResult</maml:name>
      </command:syntaxItem>
</command:syntax>

String default values generate an array of characters instead of the string value

Currently a property that has a default value of "All Computers" generates:

<dev:defaultValue>A, l, l,  , C, o, m, p, u, t, e, r, s</dev:defaultValue>

If you change line #278 in CommentReaderExtensions.cs from:

if (defaultValue is IEnumerable enumerable)

to

if (defaultValue is IEnumerable enumerable && !(defaultValue is string))

then it it will generate:

<dev:defaultValue>All Computers</dev:defaultValue>

Improve error detection and reporting

There have been a couple of issues, specifically #21 and #23, that could have been avoided if XmlDoc2CmdletDoc was more paranoid about detecting problems and had a mechanism for reporting errors to the console. I'm going to close those issues and replace them with this once.

RuntimeDefinedParameterDictionary Dynamic Parameters Support

In #26 basic support for providing information on dynamic parameters was implemented. In the issue, @ChrisLambrou presented that IDynamicParameters.GetDynamicParameters could return anything (technically true), however according to the PowerShell source code, only two types of objects are actually supported

  • A RuntimeDefinedParameterDictionary containing a set of RuntimeDefinedParameter objects contain all the information would typically expect to find on an attribute (a name, type and a set of ParameterAttribute attributes)
  • An object whose members are decorated with ParameterAttribute attributes, allowing the dynamic parameters to be identified via reflection

The fix in the previous issue appeared to implement support for the latter case utilizing the reflection dynamic parameter technique. I would present however that the most common type of dynamic parameter scenario is the RuntimeDefinedParameterDictionary technique.

By default, Get-Help will list all of your dynamic parameters in each parameter set if your cmdlet does not contain any help file information associated with it. As a result, XmlDoc2CmdletDoc not supporting this technique causes Get-Help to show less than it would without an XmlDoc2CmdletDoc help file in this scenario.

While obviously XmlDoc2CmdletDoc wouldn't be able to provide any specific documentation about each parameter, I would like to propose these parameters at least be listed as existing on the cmdlet as well as listing which parameter set each belongs to

Fails to document PowerShell 6 (PowerShell Core) binary modules

I am developing a powershell library using PowerShell core (via the PowerShellStandard.Library nuget package currently at https://powershell.myget.org/F/powershell-core). The library targets .NET standard 2.0, which will be typical for PowerShell modules going forward as it allows your module to run on PowerShell 3+ as well as PowerShell core cross-platform.

Anyway, xmldoc2cmdletdoc fails with the following trace:
Loader exception: System.IO.FileNotFoundException: Could not load file or assembly '<project path>\bin\Debug\netstandard2.0\netstandard.dll' or one of its dependencies. The system cannot find the file specified.

This is on Windows 10 1703. I actually think the issue might be solved by .NET 4.7.1 as its supposed to resolve some binding issues with netstandard libraries. I'll update this case later today or tomorrow as Windows 10 1709 (including .NET 4.7.1) comes out today.

If its fixed, it might just be a good idea to note the dependency on .NET 4.7.1 since this will be a common scenario once PowerShell 6.0 is released.

Parameters of Array Type Report 'No XML doc comment found'

I have found what appears to be a bug, wherein XmlDoc2CmdletDoc will report "No XML doc comment found" for a parameter when the parameter's type is an array.

The following program generates the error

/// <summary>
/// <para type="description">Something!</para> 
/// </summary>
public class Random
{
}

[Cmdlet(VerbsCommon.Get, "Fail")]
public class Class1 : PSCmdlet
{
    /// <summary>
    /// <para type="description">Hello?</para> 
    /// </summary>
    [Parameter]
    public Random[] Param { get; set; }
}

I have found the issue appears to be caused by the Redgate Jolt library, specifically method AppendXDCFullTypeNameTo in Convert.cs on line 401.

private static StringBuilder AppendXDCFullTypeNameTo(StringBuilder builder, Type type)
{
    if (type.IsGenericType) { type = type.GetGenericTypeDefinition(); }
    return AppendNormalizedXDCTypeNameTo(builder, type);
}

I believe this method should be modified to also check whether or not the type is an array, as follows

private static StringBuilder AppendXDCFullTypeNameTo(StringBuilder builder, Type type)
{
    if (type.IsGenericType)
    {
        type = type.GetGenericTypeDefinition();
    }
    else if (type.IsArray)
    {
        type = type.GetElementType();
    }
    return AppendNormalizedXDCTypeNameTo(builder, type);
}

A potential complexity with this however is that I can see on line 533 of Convert.cs there is a method ReduceToElementType which also appears to be capable of determining the underlying type of an array, however this method does not appear to be invoked by the method chain XmlDoc2CmdletDoc uses.

For reference, the following call stack shows the path to AppendXDCFullTypeNameTo when we need to parse an array.

Jolt.dll!Jolt.Convert.AppendXDCFullTypeNameTo(System.Text.StringBuilder builder, System.Type type) Line 409
Jolt.dll!Jolt.Convert.ToXmlDocCommentMember(System.Type type) Line 62
Jolt.dll!Jolt.XmlDocCommentReader.GetComments(System.Type type) Line 214
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Comments.JoltCommentReader.GetComments(System.Type type) Line 26
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Comments.LoggingCommentReader.GetComments(System.Type type) Line 31
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Comments.RewritingCommentReader.GetComments(System.Type type) Line 28
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Comments.CachingCommentReader.GetComments(System.Type type) Line 31
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Extensions.CommentReaderExtensions.GetTypeDescriptionElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, System.Type type, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 338
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateTypeElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, System.Type type, bool includeMamlDescription, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 560
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateParameterElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, XmlDoc2CmdletDoc.Core.Domain.Parameter parameter, string parameterSetName, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 387
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateSyntaxItemElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, XmlDoc2CmdletDoc.Core.Domain.Command command, string parameterSetName, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 332
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateSyntaxElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, XmlDoc2CmdletDoc.Core.Domain.Command command, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 310
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateCommandElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, XmlDoc2CmdletDoc.Core.Domain.Command command, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 249
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateHelpItemsElement(XmlDoc2CmdletDoc.Core.Comments.ICommentReader commentReader, System.Collections.Generic.IEnumerable<XmlDoc2CmdletDoc.Core.Domain.Command> commands, XmlDoc2CmdletDoc.Core.ReportWarning reportWarning) Line 235
XmlDoc2CmdletDoc.Core.dll!XmlDoc2CmdletDoc.Core.Engine.GenerateHelp(XmlDoc2CmdletDoc.Core.Options options) Line 57
XmlDoc2CmdletDoc.exe!XmlDoc2CmdletDoc.Program.Main(string[] args) Line 31

While this appears to be an issue with the Jolt module used by XmlDoc2CmdletDoc, as Redgate's repo for it does not have an issues page, I am not familiar with what Jolt is typically used for, and @ChrisLambrou appears to be a major contributor to both projects, I am opening an issue here.

Arrays of builtin types do not generate this warning, however this is because XmlDoc2CmdletDoc filters out errors for types outside of the assembly being processed.

Any assistance on this matter would be greatly appreciated.

Regards,
lordmilko

documentation build fails with odd error

IF You add a blank HelpMessage on a cmdlet parameter code generation will fail trying to look for the System.Management.Automation.resources.dll file.

This is admittedly a very minor deal...

Specifically this code:

    [Parameter(Mandatory = true, ParameterSetName = "id", HelpMessage = "")]
    public int Id { get; set; }

Fails with the attached exception.
exception.txt

No newline after an example's introduction

heya,
lovely work you have done!
but after an example's introduction a newline is missing (so the introduction-text and the code are in one line)
thx and keep up the good work
Michi

Any way to disable the Xml generation?

When I add the NuGet package a targets file is added to the project calling the commandline tool.
Is there any way to skip this step on certain conditions?
Basically enabling a build like this:
msbuild MyCmdletProject.csproj /p:XmlDoc2CmdletDocSkip=true

We use NCrunch for our tests, which works fine, but lets XmlDoc2CmdletDoc fail and in the end there is no reason to create the documentation for that case at all.

Render related web links to be more user friendly

I have yet to find any related links in standard .NET cmdlets that are not links to other PowerShell topics, but at least XmlDoc2CmdletDoc provides support for standard web links as well. The issue, though, is just the output rendering. Say you have two links, one a web link and one a plain link:

/// <para type="link" uri="http://tempuri.org">My Web Page</para>
/// <para type="link">about_Gizmos</para>

They will render as:

My Web Page http://tempuri.org
about_Gizmos

The web link is technically correct but hard to visually discern the parts. It would be easier on the user--as well as allow for easier post-processing should the occasion arise--if the output was in standard markdown format, clearly delineating what is attached to the link:

[My Web Page](http://tempuri.org)
about_Gizmos

My recommendation then is: if the link is recognized as a weblink in GetCommandRelatedLinksElement() then output it in markdown format as shown; otherwise output it "as is".

Inherited Parameter attributes should not be used

If you have a hierarchy of inheriting classes with virtual and overridden properties, only the ones applied to the overridden property must be taken into account, including none if the overridden property has no such attributes. This is the way PowerShell itself does it. From the PowerShell source CompiledCommandParameter.cs:

// We do not want to get the inherited custom attributes, only the attributes exposed
// directly on the member
var memberAttributes = member.GetCustomAttributes(false);

In our setup we encountered three problems with this:

  1. Parameters which are in AllParameterSets in the base class but only in specific ones in the derived class, are documented as if they are everywhere, while they are not in PowerShell.
  2. Parameters which are mandatory in the base class and not mandatory in the derived class are documented as if they are mandatory, while they are not in PowerShell.
  3. Parameters which are hidden in the derived class by overriding the property without an attribute, are documented as if they exist, while they are not in PowerShell.

The fix could be as simple as adding 'false' into the calls to GetCustomAttributes, similarly to how PowerShell does it internally. For the Mandatory issue, it may also be necessary to change this code to allow for specific parameter sets to override the value from AllParameterSets:

public bool IsRequired(string parameterSetName)
{
    return GetAttributes(parameterSetName).Any(attr => attr.Mandatory);
}

Thank you for looking into this. Please let me know whether you agree with this analysis and proposed implementation.

Comments for array parameters fail

The GetComments functions check type - but if you have an array it does not extract the comment from the element. A simple IsArray check could fix this. I have modified the code locally for my cmdlet and if it is robust enough I will create PR.

Dynamic parameters support

Description topics for dynamic parameters are not generated.
I added code inserting parameters from nested classes of the cmdlet if it implements IDynamicParameters interface. In my situation it's enough to generate a correct help file.
You can use it or make additional dynamic parameters metadata to support cmdlets implementing dynamic parameters.
`

    public IEnumerable<Parameter> Parameters
    {
        get
        {
            IEnumerable<Parameter> members = CmdletType.GetMembers(BindingFlags.Instance | BindingFlags.Public)
                .Where(member => member.GetCustomAttributes<ParameterAttribute>().Any())
                .Select(member => new Parameter(CmdletType, member));

            if (typeof(IDynamicParameters).IsAssignableFrom(CmdletType) == true)
            {
                foreach (Type t in CmdletType.GetNestedTypes())
                {
                    IEnumerable<Parameter> tmp = t.GetMembers(BindingFlags.Instance | BindingFlags.Public)
                        .Where(member => member.GetCustomAttributes<ParameterAttribute>().Any())
                        .Select(member => new Parameter(t, member));

                    if ((tmp != null) && (tmp.Count() > 0))
                    {
                        members = members.Concat(tmp);
                    }
                }
            }

            return members;
        }
    }

`

Problem using the NuGet package in .NET Core 3.1 project

I am trying to use this NuGet package in a .NET Core 3.1 project.

When I build I get an error in the build output of VS telling something about missing rights, which is completly wrong.
When I try to run the shown command I get a more reasonable long error message, basically telling me that the commandline tool cannot find the assembly System.Runtime in version 4.2.2.0.

Does anyone know a workaround for this?

Multiple notes do not render as expected

Using this MAML from one of the acceptance tests...

<maml:alertSet xmlns:maml=""http://schemas.microsoft.com/maml/2004/10"">
  <maml:title>First Note</maml:title>
  <maml:alert>
    <maml:para>This is the description for the first note.</maml:para>
  </maml:alert>
  <maml:title>Second Note</maml:title>
  <maml:alert>
    <maml:para>This is part of the description for the second note.</maml:para>
    <maml:para>This is also part of the description for the second note.</maml:para>
  </maml:alert>
</maml:alertSet>";

... it is rendered in the output of Get-Help as this:

NOTES
    {First Note, Second Note}
        This is the description for the first note.
        This is part of the description for the second note.

        This is also part of the description for the second note.

Is that just how Get-Help does it or is there any way to tweak XmlDoc2CmdletDoc to get something closer to what it should be? Perhaps something like this...

NOTES
    {First Note}
        This is the description for the first note.

    {Second Note}
        This is part of the description for the second note.

        This is also part of the description for the second note.

Add support for documenting PowerShell cmdlet providers.

Modules that use this tool currently have no way of adding help for a provider. This could be done by either adding support directly, or by adding the ability to append to a hand written file that already contains the provider help.

Explicitly indicate "None" if no items for Inputs or Outputs sections

If the Inputs or Outputs section of the help content has no entries, I think it would be much cleaner to add a dummy node in the MAML so that it outputs, e.g. "-None-" or "None". While helpful to both sections, the situation is particularly egregious if the Outputs section is empty (because .NET does not put a header on the Examples section-aarrgh!), currently:

INPUTS
    Data.VersionInfo

OUTPUTS

  ----------  EXAMPLE 1  ----------

So we could at least make it read a bit better:

INPUTS
    Data.VersionInfo

OUTPUTS
    -None-

  ----------  EXAMPLE 1  ----------

Enum Array Parameters Do Not List Possible Values

Potentially somewhat related to #33 , I've observed that when you have a parameter that takes an array of enums, the help text does not list all the possible values that are valid for the enum. I can see this text is generated by XmlDoc2CmdletDoc (and not dynamically determined by PowerShell) as the possible values for a parameter taking an array of enum are included in the resulting dll-Help.xml file

The following is generated for a parameter taking a single enum:

<command:parameter required="false" globbing="false" pipelineInput="false" position="named">
  <maml:name>Since</maml:name>
  <maml:description>
    <maml:para>Possible values: Today, Yesterday, LastWeek, LastMonth, LastSixMonths, LastYear, AllTime</maml:para>
  </maml:description>
  <command:parameterValue required="true">RecordAge</command:parameterValue>
  <dev:type>
    <maml:name>PrtgAPI.RecordAge</maml:name>
    <maml:uri />
  </dev:type>
  <command:parameterValueGroup>
    <command:parameterValue required="false" variableLength="false">Today</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">Yesterday</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">LastWeek</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">LastMonth</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">LastSixMonths</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">LastYear</command:parameterValue>
    <command:parameterValue required="false" variableLength="false">AllTime</command:parameterValue>
  </command:parameterValueGroup>
</command:parameter>

And the following the output for an enum array

<command:parameter required="false" globbing="false" pipelineInput="true (ByValue)" position="named">
  <maml:name>Status</maml:name>
  <maml:description>
    <maml:para>Only retrieve objects that match a specific status.</maml:para>
  </maml:description>
  <command:parameterValue required="true">LogStatus[]</command:parameterValue>
  <dev:type>
    <maml:name>PrtgAPI.LogStatus[]</maml:name>
    <maml:uri />
  </dev:type>
</command:parameter>

In the array scenario the XmlDoc para description is used for the <maml:para>, whereas in the single value scenario the possible values are listed. I'm not sure whether or not this behavior is intentional, however from a usability perspective this prevents users from seeing the valid values that can be used with a parameter.

Adding a new line in Summary is ignored

Hello,

i adding some examples in my c# class summary like this example:

/// <summary>
/// <example>
/// <para type="description">any descrition:</para>
/// <code>Get-Some -ExampleParam "Example" </code>
/// </example>
///</summary>

the output show this:

---------- EXAMPLE 1 -------------
any descrition:Get-Some -ExampleParam "Example"

but i want the output show like this:

---------- EXAMPLE 1 -------------
any descrition:
Get-Some -ExampleParam "Example"

maybe it's my fault, but how to do this? i tryed to add (and many other):
/// <code type="description">Get-Some -ExampleParam "Example" </code>
/// <para type="description"></para>
/// <br />

same result :-(

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.