Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

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.

Assessment

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

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.

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.

Dominant language
C#
Stars
870
Forks
166
PR merge metrics
No merged PRs in 30d

Getting set up

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.

More from PowerShell/platyPS

All issues in PowerShell/platyPS

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.