PowerShell / PowerShell/platyPS

Export-MamlCommandHelp: a module file in the batch aborts the whole export and writes nothing

Open
#862 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
871
Forks
166
Avg merge
21h 17m
Merged PRs (30d)
1

Description

Summary

Passing a module file (the -WithModulePage output) to Import-MarkdownCommandHelp and piping the
result to Export-MamlCommandHelp throws and aborts the entire batch, so no MAML is written at
all — including for the valid command help in the same pipeline.

The failure is silent in the sense that matters: you get a created output directory containing zero
.xml files, and the only signal is a terminating error naming a directory rather than a document.

Steps to reproduce

Microsoft.PowerShell.PlatyPS 1.0.3, PowerShell 7.6.5, Windows.

Import-Module Microsoft.PowerShell.PlatyPS -RequiredVersion 1.0.3

# a one-function module, imported
$mi = Import-Module .\DemoMod\DemoMod.psd1 -Force -PassThru

New-MarkdownCommandHelp -ModuleInfo $mi -OutputFolder .\docs -WithModulePage -Force
# => docs\DemoMod\DemoMod.md, docs\DemoMod\Get-DemoThing.md

Import-MarkdownCommandHelp -Path (Get-ChildItem .\docs\DemoMod -Filter *.md).FullName |
    Export-MamlCommandHelp -OutputFolder .\maml -Force
Actual
imported objects: 2
  Title='DemoMod'        ExternalHelpFile=''
  Title='Get-DemoThing'  ExternalHelpFile='DemoMod-Help.xml'

EXPORT THREW: UnauthorizedAccessException :: Access to the path '...\maml\DemoMod' is denied.
xml files written: 0

Get-DemoThing's help is valid and was lost.

Expected

Either Import-MarkdownCommandHelp rejects a module file the way Update-MarkdownCommandHelp
already does, or Export-MamlCommandHelp skips the record with a non-terminating error and still
writes the command help it can.

Analysis

Two things combine.

Import-MarkdownCommandHelp does no document-type probing. Update-MarkdownCommandHelp does:

var identity = MarkdownProbe.Identify(path);
if (! identity.IsCommandHelp())
{
    WriteError(new ErrorRecord(new ArgumentException($"'{path}' is not a CommandHelp file."), ...));
    continue;
}

ImportMarkdownCommand.cs has no equivalent check and calls
MarkdownConverter.GetCommandHelpFromMarkdownFile(path) directly, so a module file returns a
CommandHelp with ExternalHelpFile set to the empty string rather than null.

That empty string then defeats both null-coalescing fallbacks in the export path:

GroupBy(c => c?.ExternalHelpFile ?? c?.ModuleName)
helpFileName = group.First().ExternalHelpFile ?? $"{moduleName}-Help.xml"

"" is not null, so neither falls through, and Path.Combine(moduleMamlBasePath, "") resolves to
the directory itself. Writing it throws UnauthorizedAccessException. Because OrderBy(g => g.Key)
sorts the empty key first and the exception is unhandled in EndProcessing, the batch stops before
reaching any real document.

Suggested fix

A string.IsNullOrEmpty check in place of the ?? in the export path would turn a total-loss abort
into a single skipped record. Probing document type in Import-MarkdownCommandHelp, matching
Update-MarkdownCommandHelp, would stop it earlier and give a clearer message.

Notes

The documented idiom does filter module files out, and every example I found uses it:

Measure-PlatyPSMarkdown -Path .\WidgetModule\*.md |
    Where-Object Filetype -match 'CommandHelp' |
    Import-MarkdownCommandHelp -Path {$_.FilePath} |
    Export-MamlCommandHelp -OutputFolder .\maml

So this is avoidable, and we do avoid it. It is reported because the failure mode is
disproportionate — a caller who forgets the filter, or who points at a docs tree that happens to
contain a module page, loses the whole export rather than one file, and the error message names a
directory with no indication that a module page was the cause.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproduction using Import-MarkdownCommandHelp and Export-MamlCommandHelp, then inspect ImportMarkdownCommand.cs and the export grouping and output-path logic described in the issue. Compare import behavior with Update-MarkdownCommandHelp and verify the batch containing a module page still writes the valid command help without aborting.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, powershell
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.