Alt3.Docusaurus.Powershell.psm1
#Region 'PREFIX' 0 Set-StrictMode -Version Latest $PSDefaultParameterValues['*:ErrorAction'] = 'Stop' # full stop on first error #EndRegion 'PREFIX' #Region '.\Private\CreateOrCleanFolder.ps1' 0 function CreateOrCleanFolder() { <# .SYNOPSIS Helper function to create a folder OR remove it's contents if it already exists. #> param( [Parameter(Mandatory = $True)][string]$Path ) # create the folder if it does not exist if (-not(Test-Path -Path $Path)) { Write-Verbose "=> creating folder $($Path)" New-Item -Path $Path -ItemType Directory -Force return } # otherwise remove it's contents Write-Verbose "=> cleaning folder $($Path)" Remove-Item -Path (Join-Path -Path $Path -ChildPath *.*) } #EndRegion '.\Private\CreateOrCleanFolder.ps1' 21 #Region '.\Private\GetCustomEditUrl.ps1' 0 function GetCustomEditUrl() { <# .SYNOPSIS Returns the `custom_edit_url` for the given .md file. .DESCRIPTION Generates a URL pointing to the Powershell source file that was used to generate the markdown file. .NOTES - URLs for non-monolithic modules point to a .ps1 file with same name as the markdown file - URLs for monolithic modules will always point to a .psm1 with same name as passed module #> param( [Parameter(Mandatory = $True)][string]$Module, [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile, [Parameter(Mandatory = $False)][string]$EditUrl, [switch]$Monolithic ) # return "false" so Docusaurus will not render the `Edit this page` button if (-not($EditUrl)) { return } # point to the function source file for non-monlithic modules if (-not($Monolithic)) { $command = [System.IO.Path]::GetFileNameWithoutExtension($MarkdownFile) return $EditUrl + '/' + $command + ".ps1" } # point to the module source file for monolithic modules if (Test-Path $Module) { $Module = [System.IO.Path]::GetFileNameWithoutExtension($Module) } return $EditUrl + '/' + $Module + ".psm1" } #EndRegion '.\Private\GetCustomEditUrl.ps1' 38 #Region '.\Private\InitializeTempFolder.ps1' 0 function InitializeTempFolder() { <# .SYNOPSIS Creates the temp folder and the `debug.info` file. .DESCRIPTION The temp folder is where all work is done before the enriched mdx files are copied to the docusaurus sidebar folder. We use this approach to support future debugging as it will be near impossible to reason about bugs without looking at the initial PlatyPS files, knowing which Powershell version was used etc. We might even instruct users to send us the files when reporting issues (which would require re-generating using the `-KeepTempFiles` switch). .NOTES Ideally we would also log used module versions for Alt3, PlatyPS and Pester. #> param( [Parameter(Mandatory = $True)][string]$Path ) Write-Verbose "Initializing temp folder:" CreateOrCleanFolder -Path $Path # prepare the debug info Write-Verbose "=> creating debug file" $debugInfo = [ordered]@{ PSVersionTable = $PSVersionTable } | ConvertTo-Json # create the debug file $debugFile = Join-Path -Path $Path -ChildPath "debug.json" $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($debugFile, $debugInfo, $fileEncoding) } #EndRegion '.\Private\InitializeTempFolder.ps1' 35 #Region '.\Private\NewMarkdownExample.ps1' 0 function NewMarkdownExample() { <# .SYNOPSIS Generates a new markdown example block. #> param( [Parameter(Mandatory = $True)][string]$Header, [Parameter(Mandatory = $True)][string]$Code, [Parameter(Mandatory = $False)][string]$Description = $null ) $example = "$Header`n" $example += '```powershell' + "`n" $example += $Code $example += '```' + "`n" if ([string]::IsNullOrEmpty($Description)) { $example += "`n" } else { $example += "`n$Description`n" } return $example } #EndRegion '.\Private\NewMarkdownExample.ps1' 24 #Region '.\Private\NewSidebarIncludeFile.ps1' 0 function NewSidebarIncludeFile() { <# .SYNOPSIS Generates a `.js` file holding an array with all .mdx 'ids` to be imported in Docusaurus `sidebar.js`. .LINK https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-powershell-1.0/ff730948(v=technet.10) #> param( [Parameter(Mandatory = $True)][string]$OutputFolder, [Parameter(Mandatory = $True)][string]$Sidebar, [Parameter(Mandatory = $True)][Object]$MarkdownFiles ) Write-Verbose "Generating docusaurus.sidebar.js" # generate a list of Powershell commands by stripping .md from the generated PlatyPs files [array]$commands = $MarkdownFiles | Select-Object @{ Name = "PowershellCommand"; Expression={ "'$Sidebar/" + [System.IO.Path]::GetFileNameWithoutExtension($_) + "'" } } | Select-Object -Expand PowershellCommand # generate content using Here-String block $content = @" /** * Import this file in your Docusaurus ``sidebars.js`` file. * * Auto-generated by Alt3.Powershell.Docusaurus. * * Copyright (c) 2019-present, ALT3 B.V. * * Licensed under the MIT license. */ module.exports = [ $($commands -Join ",`n ") ]; "@ # generate file path, convert relative output folder to absolute if needed if (-Not([System.IO.Path]::IsPathRooted($OutputFolder))) { $outputFolder = Join-Path "$(Get-Location)" -ChildPath $OutputFolder } $filePath = Join-Path -Path $outputFolder -ChildPath "docusaurus.sidebar.js" # create the file $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($filePath, $content, $fileEncoding) } #EndRegion '.\Private\NewSidebarIncludeFile.ps1' 47 #Region '.\Private\RemoveFile.ps1' 0 function RemoveFile() { <# .SYNOPSIS Helper function to remove a file if it exists. #> param( [Parameter(Mandatory = $True)][string]$Path ) Write-Verbose "=> removing $Path" if (Test-Path -Path $Path) { Remove-Item -Path $Path -Force } } #EndRegion '.\Private\RemoveFile.ps1' 15 #Region '.\Private\RemoveMarkdownHeaderOne.ps1' 0 function RemoveMarkdownHeaderOne() { <# .SYNOPSIS Removes the H1 element from the markdown content because Docusaurus already generates H1 using the `title` front matter. #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() $regex = '\n#{1}\s.+' $newContent = [regex]::replace($content, $regex, '') # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding) } #EndRegion '.\Private\RemoveMarkdownHeaderOne.ps1' 19 #Region '.\Private\ReplaceMarkdownExamples.ps1' 0 function ReplaceMarkdownExamples() { <# .SYNOPSIS Replace PlatyPS generated code block examples. .DESCRIPTION Replaces custom fenced code blocks and placeholder examples, otherwise uses PlatyPS generated defaults. See link below for a detailed description of the determination process. .LINK https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556 #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile, [switch]$NoPlaceHolderExamples ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() [string]$newExamples = "" # --------------------------------------------------------------------- # extract all EXAMPLE nodes # https://regex101.com/r/y4UxP8/2 # --------------------------------------------------------------------- $regexExtractExamples = [regex]::new('### (EXAMPLE|Example) [0-9][\s\S]*?(?=\n.*?#|$)') $examples = $regexExtractExamples.Matches($content) if ($examples.Count -eq 0) { Write-Warning "Unable to find any EXAMPLE nodes. Please check your Get-Help definitions before filing an issue!" } # process each EXAMPLE node $examples | ForEach-Object { $example = $_ # --------------------------------------------------------------------- # do not modify if it's a PlatyPS placeholder example # https://regex101.com/r/WOQL0l/4 # --------------------------------------------------------------------- $regexPlatyPlaceholderExample = [regex]::new('{{ Add example code here }}') if ($example -match $regexPlatyPlaceholderExample) { if ($NoPlaceHolderExamples) { Write-Verbose "=> Example 1: PlatyPS Placeholder (dropping)" return } Write-Verbose "=> Example 1: PlatyPS Placeholder (keeping)" $newExamples += "$example`n" return } # --------------------------------------------------------------------- # Powershell 6: re-construct Code Fenced example # - https://regex101.com/r/lHdZHM/6 => without a description # - https://regex101.com/r/CGjQco/3 => with a description # --------------------------------------------------------------------- $regexPowershell6TripleCodeFence = [regex]::new('(### EXAMPLE ([0-9|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?)\\`\\`\\`(\n\n|\n)([\s\S]*|\n)') if ($example -match $regexPowershell6TripleCodeFence) { $header = $matches[1] $code = $matches[5] $description = $matches[7] Write-Verbose "=> $($header): Triple Code Fence (Powershell 6 and lower)" $newExample = NewMarkdownExample -Header $header -Code $code -Description $description $newExamples += $newExample return } # --------------------------------------------------------------------- # Powershell 7: re-construct PlatyPS Paired Code Fences example # - https://regex101.com/r/FRA139/1 => without a description # - https://regex101.com/r/YIIwUs/5 => with a description # --------------------------------------------------------------------- $regexPowershell7PairedCodeFences = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?)```\n```(\n\n|\n)([\s\S]*|\n)') if ($example -match $regexPowershell7PairedCodeFences) { $header = $matches[1] $code = $matches[5] $description = $matches[7] Write-Verbose "=> $($header): Paired Code Fences (Powershell 7)" $newExample = NewMarkdownExample -Header $header -Code $code -Description $description $newExamples += $newExample return } # --------------------------------------------------------------------- # Powershell 7: re-construct non-adjacent Code Fenced example # - https://regex101.com/r/kLr98l/3 => without a description # - https://regex101.com/r/eJH4cQ/6 => with a complex description # --------------------------------------------------------------------- $regexPowershell7NonAdjacentCodeBlock = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?)\\`\\`\\`(\n\n([\s\S]*)|\n)') if ($example -match $regexPowershell7NonAdjacentCodeBlock) { $header = $matches[1] $code = $matches[5] -replace ('```' + "`n"), '' $description = $matches[7] Write-Verbose "=> $($header): Non-Adjacent Code Block (Powershell 7)" $newExample = NewMarkdownExample -Header $header -Code $code -Description $description $newExamples += $newExample return } # --------------------------------------------------------------------- # no matches so we simply use the unaltered PlatyPS generated example # - https://regex101.com/r/rllmTj/1 => without a decription # - https://regex101.com/r/kTH75U/1 => with a description # --------------------------------------------------------------------- $regexPlatyPsDefaults = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n```\n([\s\S]*)```\n([\s\S]*)') if ($example -match $regexPlatyPsDefaults) { $header = $matches[1] $code = $matches[5] -replace ('```' + "`n"), '' $description = $matches[7] Write-Verbose "=> $($header): PlatyPS Default (all Powershell versions)" $newExamples += "$example`n" return } # we should never reach this point Write-Warning "Unsupported code block detected, please file an issue containing the error message below at https://github.com/alt3/Docusaurus.Powershell/issues" Write-Warning $example } # replace EXAMPLES section in content with updated examples # https://regex101.com/r/8OEW0w/1/ $regex = '## EXAMPLES\n[\s\S]+## PARAMETERS' $replacement = "## EXAMPLES`n`n$($newExamples)## PARAMETERS" $content = [regex]::replace($content, $regex, $replacement) # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) } #EndRegion '.\Private\ReplaceMarkdownExamples.ps1' 143 #Region '.\Private\SetMarkdownCodeBlockMoniker.ps1' 0 function SetMarkdownCodeBlockMoniker() { <# .SYNOPSIS Add `powershell` moniker to generated code blocks for correct syntax highlighting. .NOTES 1. unfortunately we need to do this because PlatyPS does not add the language (design choice) 2. @todo change regex so it will match on \n as well (now only works on CRLF files) #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() # this regex replaces all opening code fences without a language moniker with "```powershell" # https://regex101.com/r/AYzALd/1 $regex = '(```)\n((?:(?!```)[\s\S])+)(```)\n' $content = [regex]::replace($content, $regex, '```powershell' + "`n" + '$2```' + "`n") # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) } #EndRegion '.\Private\SetMarkdownCodeBlockMoniker.ps1' 25 #Region '.\Private\SetMarkdownFrontMatter.ps1' 0 function SetMarkdownFrontMatter() { <# .SYNOPSIS Replaces PlatyPS generated front matter with Docusaurus compatible front matter. .LINK https://www.apharmony.com/software-sagacity/2014/08/multi-line-regular-expression-replace-in-powershell/ #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile, [Parameter(Mandatory = $False)][string]$CustomEditUrl, [Parameter(Mandatory = $False)][string]$MetaDescription, [Parameter(Mandatory = $False)][array]$MetaKeywords, [switch]$HideTitle, [switch]$HideTableOfContents ) $powershellCommandName = [System.IO.Path]::GetFileNameWithoutExtension($markdownFile.Name) # prepare front matter $newFrontMatter = [System.Collections.ArrayList]::new() $newFrontMatter.Add("---") | Out-Null $newFrontMatter.Add("id: $($powershellCommandName)") | Out-Null $newFrontMatter.Add("title: $($powershellCommandName)") | Out-Null if ($MetaDescription) { $description = [regex]::replace($MetaDescription, '%1', $powershellCommandName) $newFrontMatter.Add("description: $($description)") | Out-Null } if ($MetaKeywords) { $newFrontMatter.Add("keywords:") | Out-Null $MetaKeywords | ForEach-Object { $newFrontMatter.Add(" - $($_)") | Out-Null } } $newFrontMatter.Add("hide_title: $(if ($HideTitle) {"true"} else {"false"})") | Out-Null $newFrontMatter.Add("hide_table_of_contents: $(if ($HideTableOfContents) {"true"} else {"false"})") | Out-Null if ($EditUrl) { $newFrontMatter.Add("custom_edit_url: $($EditUrl)") | Out-Null } $newFrontMatter.Add("---") | Out-Null # replace front matter $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() $regex = "(?sm)^(---)(.+)^(---).$\n" $newContent = $content -replace $regex, ($newFrontMatter | Out-String) # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding) } #EndRegion '.\Private\SetMarkdownFrontMatter.ps1' 56 #Region '.\Private\SetMarkdownLineEndings.ps1' 0 function SetMarkdownLineEndings() { <# .SYNOPSIS Replaces all CRLF line endings with LF so we can consitently use/expect `n when regexing etc. #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() $content = $content -replace "`r`n", "`n" # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) } #EndRegion '.\Private\SetMarkdownLineEndings.ps1' 17 #Region '.\Private\UpdateMarkdownBackticks.ps1' 0 function UpdateMarkdownBackticks() { <# .SYNOPSIS Replaces platyPS-produced "escaped backticks" with normal backticks so markdown gets rendered as expected. #> param( [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() $regex = '\\`' $newContent = [regex]::replace($content, $regex, '`') # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding) } #EndRegion '.\Private\UpdateMarkdownBackticks.ps1' 19 #Region '.\Public\New-DocusaurusHelp.ps1' 0 function New-DocusaurusHelp() { <# .SYNOPSIS Generates Get-Help documentation in Docusaurus compatible `.mdx` format. .DESCRIPTION The `New-DocusaurusHelp` cmdlet generates Get-Help documentation in Docusaurus compatible format by creating an `.mdx` file for each command exported by the module, enriched with command-specific front matter variables. Also creates a `sidebar.js` file for simplified integration into the Docusaurus sidebar menu. .OUTPUTS System.Object .EXAMPLE New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell This example uses default settings to generate a Get-Help page for each command exported by the Alt3.Docusaurus.Powershell module. .EXAMPLE ``` $parameters = @{ Module = "Alt3.Docusaurus.Powershell" DocsFolder = "D:\my-project\docs" Sidebar = "commands" Exclude = @( "Get-SomeCommand" ) MetaDescription = 'Help page for the Powershell command "%1"' MetaKeywords = @( "Powershell" "Documentation" ) } New-DocusaurusHelp @parameters ``` This example uses splatting to override default settings. See the list of Parameters below for all available overrides. .PARAMETER Module Specifies the module this cmdlet will generate Docusaurus documentation for. You may specify a module name, a `.psd1` file or a `.psm1` file. .PARAMETER DocsFolder Specifies the absolute or relative **path** to the Docusaurus `docs` folder. Optional, defaults to `docusaurus/docs`, case sensitive. .PARAMETER Sidebar Specifies the **name** of the docs subfolder in which the `.mdx` files will be created. Optional, defaults to `commands`, case sensitive. .PARAMETER Exclude Optional array with command names to exclude. .PARAMETER MetaDescription Optional string that will be inserted into Docusaurus front matter to be used as html meta tag 'description'. If placeholder `%1` is detected in the string, it will be replaced by the command name. .PARAMETER MetaKeywords Optional array of keywords inserted into Docusaurus front matter to be used as html meta tag `keywords`. .PARAMETER EditUrl Specifies the URL prefixed to all Docusaurus `custom_edit_url` front matter variables. Optional, defaults to `null`. .PARAMETER HideTitle Sets the Docusaurus front matter variable `hide_title`. Optional, defaults to `false`. .PARAMETER HideTableOfContents Sets the Docusaurus front matter variable `hide_table_of_contents`. Optional, defaults to `false`. .PARAMETER NoPlaceholderExamples By default, Docusaurus will generate a placeholder example if your Get-Help definition does not contain any `EXAMPLE` nodes. You can use this switch to disable that behavior which will result in an empty `EXAMPLES` section. .PARAMETER Monolithic Use this optional parameter if the Powershell module source is monolithic. Will point all `custom_edit_url` front matter variables to the `.psm1` file. .NOTES Please note that Docusaurus v2 is an early and alpha version, just like this module. .LINK https://v2.docusaurus.io/ .LINK https://github.com/PowerShell/platyPS #> [cmdletbinding()] param( [Parameter(Mandatory = $True)][string]$Module, [Parameter(Mandatory = $False)][string]$DocsFolder = "docusaurus/docs", [Parameter(Mandatory = $False)][string]$Sidebar = "commands", [Parameter(Mandatory = $False)][array]$Exclude = @(), [Parameter(Mandatory = $False)][string]$EditUrl, [Parameter(Mandatory = $False)][string]$MetaDescription, [Parameter(Mandatory = $False)][array]$MetaKeywords = @(), [switch]$HideTitle, [switch]$HideTableOfContents, [switch]$NoPlaceHolderExamples, [switch]$Monolithic ) # make sure the passed module is valid if (Test-Path($Module)) { Import-Module $Module -Force -Global $Module = [System.IO.Path]::GetFileNameWithoutExtension($Module) } if (-Not(Get-Module -Name $Module)) { $Module = $Module throw "New-DocusaurusHelp: Specified module '$Module' is not loaded" } $moduleName = [io.path]::GetFileName($module) # markdown for the module will be copied into the sidebar subfolder Write-Verbose "Initializing sidebar folder:" $sidebarFolder = Join-Path -Path $DocsFolder -ChildPath $Sidebar CreateOrCleanFolder -Path $sidebarFolder # create tempfolder used for generating the PlatyPS files and creating the mdx files $tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "Alt3.Docusaurus.Powershell" | Join-Path -ChildPath $moduleName InitializeTempFolder -Path $tempFolder # generate PlatyPs markdown files Write-Verbose "Generating PlatyPS files." New-MarkdownHelp -Module $Module -OutputFolder $tempFolder -Force | Out-Null # remove excluded files Write-Verbose "Removing excluded files:" $Exclude | ForEach-Object { RemoveFile -Path (Join-Path -Path $tempFolder -ChildPath "$($_).md") } # rename PlatyPS files and create an `.mdx` copy we will transform Write-Verbose "Cloning PlatyPS files." Get-ChildItem -Path $tempFolder -Filter *.md | ForEach-Object { $platyPsFile = $_.FullName -replace '.md', '.PlatyPS.md' $mdxFile = $_.FullName -replace '.md', '.mdx' Move-Item -Path $_.FullName -Destination $platyPsFile Copy-Item -Path $platyPsFile -Destination $mdxFile } # update all remaining mdx files to make them Docusaurus compatible Write-Verbose "Updating mdx files." $mdxFiles = Get-ChildItem -Path $tempFolder -Filter *.mdx ForEach ($mdxFile in $mdxFiles) { Write-Verbose "Processing $($mdxFile.Name):" SetMarkdownLineEndings -MarkdownFile $mdxFile $customEditUrl = GetCustomEditUrl -Module $Module -MarkdownFile $mdxFile -EditUrl $EditUrl -Monolithic:$Monolithic $frontMatterArgs = @{ MarkdownFile = $mdxFile MetaDescription = $metaDescription CustomEditUrl = $customEditUrl MetaKeywords = $metaKeywords HideTitle = $HideTitle HideTableOfContents = $HideTableOfContents } SetMarkdownFrontMatter @frontmatterArgs RemoveMarkdownHeaderOne -MarkdownFile $mdxFile ReplaceMarkdownExamples -MarkdownFile $mdxFile -NoPlaceholderExamples:$NoPlaceholderExamples SetMarkdownCodeBlockMoniker -MarkdownFile $mdxFile UpdateMarkdownBackticks -MarkdownFile $mdxFile } # copy updated mdx files to the target folder Write-Verbose "Copying mdx files to sidebar folder." Get-ChildItem -Path $tempFolder -Filter *.mdx | ForEach-Object { # $mdxFile = $_.FullName -replace '.md', '.mdx' Copy-Item -Path $_.FullName -Destination (Join-Path -Path $sidebarFolder -ChildPath ($_.Name)) } # generate the `.js` file used for the docusaurus sidebar NewSidebarIncludeFile -MarkdownFiles $mdxFiles -OutputFolder $sidebarFolder -Sidebar $Sidebar # zip temp files in case we need them Compress-Archive -Path (Join-Path -Path $tempFolder -ChildPath *.*) -DestinationPath (Join-Path $tempFolder -ChildPath "$moduleName.zip") # output Get-ChildItem so end-user can post-process generated files as they see fit Get-ChildItem -Path $sidebarFolder } #EndRegion '.\Public\New-DocusaurusHelp.ps1' 204 |