From f77e9657f98a4c4947d9bd369ec14de1eedf3eb0 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Mon, 24 Aug 2026 16:41:30 -0400 Subject: [PATCH 1/3] feat!: Migrate markdown and MAML help to Microsoft.PowerShell.PlatyPS 1.x Closes #150. Closes #151. Part of #105, Phase 2 of #120. BREAKING CHANGE: help generation uses Microsoft.PowerShell.PlatyPS 1.x, PlatyPS is no longer a required module, and $PSBPreference.Docs.AlphabeticParamsOrder is removed. The two functions are migrated together because they cannot be split: 2b changes the on-disk markdown schema that an unmigrated Build-PSBuildMAMLHelp would be handed, and the two PlatyPS modules cannot be loaded into one psake session. The 1.x API is not a rename. Three of its differences shape this change: - New-MarkdownCommandHelp and Export-MamlCommandHelp both write to //, a level deeper than 0.14.x, and the MAML file name comes from the document's front matter with different casing. Both functions generate into a staging directory and move the results, so the published layout stays //.md and //-help.xml. Consumers' committed docs trees, site configuration, and .ExternalHelp directives keep working, and tests/build.tests.ps1 already pinned that contract. - Without -Force, both skip existing files with a warning rather than an error, so an Overwrite = $false build would silently produce nothing. Existing documents are refreshed with Update-MarkdownCommandHelp, which preserves hand-written prose, and only new documents are moved in. - A module landing page imports as a CommandHelp but fails on export, and that failure aborts the batch and writes nothing. Landing pages are filtered out with Measure-PlatyPSMarkdown rather than caught. PlatyPS is deliberately NOT in RequiredModules. Adding it there failed 394 tests locally: RequiredModules forces the load into every session that imports PowerShellBuild, and a session already holding platyPS 0.14.2 cannot then load 1.x -- both ship their own YamlDotNet with different assembly identities. Every consumer mid-upgrade is in exactly that state. An optional dependency also matches how the docs tasks have always behaved, probing with Get-Module -ListAvailable and skipping. For the same reason Build-PSBuildUpdatableHelp no longer names New-ExternalHelpCab. Merely resolving that command autoloads platyPS 0.14.2 and poisons the session against 1.x. It warns and returns until #152 migrates the cabinet pipeline; it could never succeed before either, see #169. AlphabeticParamsOrder has no 1.x equivalent -- ordering is unconditional now -- so keeping the setting would have been a lie. UseFullTypeName survives unchanged: 1.x inverted the sense of the option, so $false maps to -AbbreviateParameterTypeName. Suite: 460 passed, 0 failed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012AKaM9i6NyMFDcJNeC34h5 --- CHANGELOG.md | 691 +++++++++--------- PowerShellBuild/IB.tasks.ps1 | 13 +- PowerShellBuild/PowerShellBuild.psd1 | 1 - .../Public/Build-PSBuildMAMLHelp.ps1 | 51 +- .../Public/Build-PSBuildMarkdown.ps1 | 94 ++- .../Public/Build-PSBuildUpdatableHelp.ps1 | 57 +- PowerShellBuild/build.properties.ps1 | 9 +- PowerShellBuild/en-US/Messages.psd1 | 1 + PowerShellBuild/psakeFile.ps1 | 13 +- docs/migration-v0.8-to-v1.0.md | 130 +++- .../repository-specific.instructions.md | 2 +- requirements.psd1 | 5 +- tests/Build-PSBuildHelp.tests.ps1 | 84 +-- tests/fixtures/FixtureHelpers.psm1 | 11 +- 14 files changed, 654 insertions(+), 508 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1994b..d0ed861 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,337 +1,354 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) -and this project adheres to [Semantic Versioning](http://semver.org/). - -## Unreleased - -### Changed - -- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) - **Breaking:** `Test-PSBuildScriptAnalysis` now counts PSScriptAnalyzer - `ParseError` records alongside `Error`. A file that does not parse at all - previously satisfied no threshold — not even the strictest validated value, - `Information` — so it was reported and the build passed anyway. It now fails - every threshold except `None`. See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build that - passed before may now correctly fail. - -- [**#120**](https://github.com/psake/PowerShellBuild/issues/120) - **Breaking:** the module manifest now requires PowerShell 5.1 or newer - (`PowerShellVersion = '5.1'`, previously `'3.0'`) and declares - `CompatiblePSEditions = @('Desktop', 'Core')`. The support floor is - Windows PowerShell 5.1 or PowerShell 7.4+ (CI runs Windows PowerShell - 5.1 and the runners' current PowerShell 7 release). See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) for - details. - -### Added - -- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) - `Test-PSBuildScriptAnalysis` accepts `Any` as a `SeverityThreshold`, failing - the build on any diagnostic record regardless of severity. `Any` was already - documented in `build.properties.ps1` but was missing from the parameter's - `ValidateSet`, so setting - `$PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Any'` failed - parameter binding instead of working as documented. - -### Fixed - -- [**#147**](https://github.com/psake/PowerShellBuild/issues/147) - `Test-PSBuildScriptAnalysis` retries the analysis when a PSScriptAnalyzer rule - crashes on an internal race - ([PSScriptAnalyzer#1538](https://github.com/PowerShell/PSScriptAnalyzer/issues/1538)), - which is unrelated to the code being analyzed and succeeds on a re-run. - Consumers who set `$ErrorActionPreference = 'Stop'` — common in a build script — - previously got a randomly red build. A crash that survives every attempt is - still surfaced, so a persistent failure behaves as it did before. - -- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) - `Test-PSBuildScriptAnalysis` now fails the build when PSScriptAnalyzer - reports findings at or above the configured severity threshold. The - severity counts were computed from `$_Severity` — an undefined variable — - instead of `$_.Severity`, so all three counts were always zero and the - `Error`, `Warning`, and `Information` thresholds could never fail a build. - Script analysis reported its findings and the build passed regardless. - Because the default `FailBuildOnSeverityLevel` is `Error`, any consumer - running the `Analyze` task had a gate that only ever looked like it was - working. See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build - that passed before may now correctly fail. -- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) - `Test-PSBuildScriptAnalysis` no longer fails with a path-resolution error - when `SettingsPath` is not supplied. An unsupplied path was forwarded to - PSScriptAnalyzer as `-Settings ''`, which resolved against the current - directory and threw before any analysis ran, so the function's own - documented example could not run as written. -- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) - `Test-PSBuildPester` no longer raises a parameter-binding error from its - cleanup logic when the optional `ModuleName` parameter is not supplied. -- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) - `Test-PSBuildPester` now respects a Pester module that is already loaded in - the session instead of unconditionally importing the newest installed - version on top of it, which crashed with a Pester.dll version conflict when - two Pester versions were installed side by side. When no Pester is loaded, - the newest installed version (5.0.0 minimum) is imported as before, and a - loaded Pester older than 5.0.0 now produces a clear error. -- [**#138**](https://github.com/psake/PowerShellBuild/issues/138) - `Test-PSBuildPester` now reports real code coverage percentages and compares - them against `CodeCoverageThreshold` correctly. Each percentage was passed - through `[Math]::Truncate`, which collapses any fraction to zero, so the - coverage report always printed `0.00%` (or `100.00%`) and every threshold - above zero failed the build unless coverage was exactly 100%. Consumers who - set `$PSBPreference.Test.CodeCoverage.Threshold` could not use coverage - gating at all. The comparison is now strictly more permissive than before, - so a build that passed with a coverage threshold set still passes. - -## [0.8.2] 2026-07-08 - -### Fixed - -- [**#133**](https://github.com/psake/PowerShellBuild/pull/133) - `Test-PSBuildPester` now fails the build when a Pester run fails for any - reason, not only when individual tests fail. Previously the function gated - only on `FailedCount`, so a `BeforeAll`/`AfterAll` that threw or a test file - that errored during discovery left the count at zero and the build passed - despite tests never running. The gate now checks the run's aggregate - `Result` property, which Pester derives from all failure categories. - Companion to [#128](https://github.com/psake/PowerShellBuild/pull/128), - which fixes the same gap in this repository's own build file. - -## [0.8.1] 2026-06-03 - -### Fixed - -- Restore Windows PowerShell 5.1 (Desktop edition) compatibility, which regressed - in 0.8.0. `Get-PSBuildCertificate` used the PowerShell 7+-only ternary operator, - causing the file to fail to parse and the whole module to fail to import under - Windows PowerShell 5.1 — even though the manifest still declares support for it. - The ternary is replaced with an `if`/`else` expression, and the `$IsWindows` - platform guard now treats the absent automatic variable on Desktop edition as - Windows (matching the existing pattern in `Build-PSBuildUpdatableHelp`). Behavior - on PowerShell 7+ is unchanged. - -## [0.8.0] 2026-02-20 - -### Added - -- [**#92**](https://github.com/psake/PowerShellBuild/pull/92) Add Authenticode - code-signing support for PowerShell modules with three new public functions: - - `Get-PSBuildCertificate` - Resolves code-signing X509Certificate2 objects - from certificate store, PFX files, Base64-encoded environment variables, - or pre-resolved certificate objects - - `Invoke-PSBuildModuleSigning` - Signs PowerShell module files (*.psd1, - *.psm1, *.ps1) with Authenticode signatures supporting configurable - timestamp servers and hash algorithms - - `New-PSBuildFileCatalog` - Creates Windows catalog (.cat) files for - tamper detection -- New build tasks for module signing pipeline: `SignModule`, `BuildCatalog`, - `SignCatalog`, `Sign` (meta-task) -- Extended `$PSBPreference.Sign` configuration section with certificate - source selection, timestamp server configuration, hash algorithm options, - and catalog generation settings - -### Fixed - -- Remove extra backticks during localization text migration. - -## [0.7.3] 2025-08-01 - -### Added - -- Add new dependencies variables to allow end user to modify which tasks are - run. -- Add localization support. - -## [0.7.2] 2025-05-21 - -### Added - -- The `$PSBPreference` variable now supports the following PlatyPS - `New-MarkdownHelp` and `Update-MarkdownHelp` boolean options: - - `$PSBPreference.Docs.AlphabeticParamsOrder` - - `$PSBPreference.Docs.ExcludeDontShow` - - `$PSBPreference.Docs.UseFullTypeName` -- The `$PSBPreference` variable now supports the following Pester test - configuration options: - - `$PSBPreference.Test.SkipRemainingOnFailure` can be set to **None**, - **Run**, **Container** and **Block**. The default value is **None**. - - `$PSBPreference.Test.OutputVerbosity` can be set to **None**, **Normal**, - **Detailed**, and **Diagnostic**. The default value is **Detailed**. - -## [0.7.1] 2025-04-01 - -### Fixes - -- Fix a bug in `Build-PSBuildMarkdown` where a hashtable item was added twice. - -## [0.7.0] 2025-03-31 - -### Changed - -- [**#71**](https://github.com/psake/PowerShellBuild/pull/71) Compiled modules - are now explicitly created as UTF-8 files. -- [**#67**](https://github.com/psake/PowerShellBuild/pull/67) You can now - overwrite existing markdown files using `$PSBPreference.Docs.Overwrite` and - setting it to `$true`. -- [**#72**](https://github.com/psake/PowerShellBuild/pull/72) Loosen - dependencies by allowing them to be overwritten with - `$PSBPreference.TaskDependencies`. - -## [0.6.2] 2024-10-06 - -### Changed - -- Bump Pester to latest 5.6.1 - -### Fixed - -- [**#52**](https://github.com/psake/PowerShellBuild/pull/52) Pester object - wasn't being passed back after running tests, causing the Pester task to never - fail (via [@webtroter](https://github.com/webtroter)) -- [**#55**](https://github.com/psake/PowerShellBuild/pull/55) Add `-Module` - parameter to `Build-PSBuildUpdatableHelp` (via - [@IMJLA](https://github.com/IMJLA)) -- [**#60**](https://github.com/psake/PowerShellBuild/pull/60) Fix Windows - PowerShell compatibility in `Initialize-PSBuild` (via - [@joshooaj](https://github.com/joshooaj)) -- [**#62**](https://github.com/psake/PowerShellBuild/pull/62) Fix code coverage - output fle format not working (via - [@OpsM0nkey](https://github.com/OpsM0nkey)) - -## [0.6.1] 2021-03-14 - -### Fixed - -- Fixed bug in IB task `GenerateMarkdown` when dot sourcing precondition - -## [0.6.0] 2021-03-14 - -### Changed - -- [**#50**](https://github.com/psake/PowerShellBuild/pull/50) Invoke-Build tasks - brought inline with psake equivalents (via - [@JustinGrote](https://github.com/JustinGrote)) - -## [0.5.0] 2021-02-27 - -### Added - -- New code coverage parameters for setting output path and format: - - `$PSBPreference.Test.CodeCoverage.OutputFile` - Output file path for code - coverage results - - `$PSBPreference.Test.CodeCoverage.OutputFileFormat` - Code coverage output - format - -## [0.5.0] (beta1) - 2020-11-15 - -### Added - -- When "compiling" a monolithic PSM1, add support for both inserting - headers/footers for the entire PSM1, and for each script file. Control these - via the following new build parameters (via - [@pauby](https://github.com/pauby)) - - `$PSBPreference.Build.CompileHeader` - - `$PSBPreference.Build.CompileFooter` - - `$PSBPreference.Build.CompileScriptHeader` - - `$PSBPreference.Build.CompileScriptFooter` - -- Add ability to import project module from output directory prior to executing - Pester tests. Toggle this with `$PSBPreference.Test.ImportModule`. Defaults to - `$false`. (via [@joeypiccola](https://github.com/joeypiccola)) - -- Use `$PSBPreference.Build.CompileDirectories` to control directories who's - contents will be concatenated into the PSM1 when - `$PSBPreference.Build.CompileModule` is `$true`. Defaults to - `@('Enum', 'Classes', 'Private', 'Public')`. -- Use `$PSBPreference.Build.CopyDirectories` to control directories that will be - copied "as is" into the built module. Default is an empty array. - -### Changed - -- `$PSBPreference.Build.Exclude` now should be a list of regex expressions when - `$PSBPreference.Build.CompileModule` is `$false` (default). - -- Use Pester v5 - -### Fixed - -- Overriding `$PSBPreference.Build.OutDir` now correctly determines the final - module output directory. `$PSBPreference.Build.ModuleOutDir` is now computed - internally and **SHOULD NOT BE SET DIRECTLY**. `$PSBPreference.Build.OutDir` - will accept both relative and fully-qualified paths. - -- Before, when `$PSBPreference.Build.CompileModule` was set to `$true`, any - files listed in `$PSBPreference.Build.Exclude` weren't being excluded like - they should have been. Now, when it is `$true`, files matching regex - expressions in `$PSBPreference.Build.Exclude` will be properly excluded (via - [@pauby](https://github.com/pauby)) - -- `$PSBPreference.Help.DefaultLocale` now defaults to `en-US` on Linux since it - is not correctly determined with `Get-UICulture`. - -## [0.4.0] - 2019-08-31 - -### Changed - -- Allow using both `Credential` and `ApiKey` when publishing a module (via - [@pauby](https://github.com/pauby)) - -### Fixed - -- Don't overwrite Pester parameters when specifying `OutputPath` or - `OutputFormat` (via [@ChrisLGardner](https://github.com/ChrisLGardner)) - -## [0.3.1] - 2019-06-09 - -### Fixed - -- Don't create module page MD file. - -## [0.3.0] - 2019-04-23 - -### Fixed - -- [**#24**](https://github.com/psake/PowerShellBuild/pull/24) Fix case of - 'Public' folder when dot sourcing functions in PSM1 (via - [@pauby](https://github.com/pauby)) - -### Breaking changes - -- Refactor build properties into a single hashtable `$PSBPreference` - -### Changed - -- [**#11**](https://github.com/psake/PowerShellBuild/pull/11) The Invoke-Build - tasks are now auto-generated from the psake tasks via a converter script (via - [@JustinGrote](https://github.com/JustinGrote)) - -- [**#19**](https://github.com/psake/PowerShellBuild/pull/19) Allow the - `BHBuildOutput` environment variable defined by `BuildHelpers` to be set via - the `$PSBPreference.Build.ModuleOutDir` property of the build tasks (via - [@pauby](https://github.com/pauby)) - -## [0.2.0] - 2018-11-15 - -### Added - -- Add `Publish` task to publish the module to the defined PowerShell Repository - (PSGallery by default). - -## [0.1.1] - 2018-11-09 - -### Fixed - -- [**#4**](https://github.com/psake/PowerShellBuild/pull/4) Fix syntax for - `Analyze` task in `IB.tasks.ps1` (via - [@nightroman](https://github.com/nightroman)) - -## [0.1.0] - 2018-11-07 - -### Added - -- Initial commit - - +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## Unreleased + +### Changed + +- [**#105**](https://github.com/psake/PowerShellBuild/issues/105) + **Breaking:** help generation moved from `platyPS` 0.14.x to + [`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) + 1.x. PlatyPS is also no longer a `RequiredModules` entry, so + `Install-Module PowerShellBuild` no longer installs it — the two PlatyPS + modules cannot be loaded into one process, so forcing the new one into every + session would break any consumer still holding the old one. Install it + yourself if you build help. `$PSBPreference.Docs.AlphabeticParamsOrder` is + removed, because PlatyPS 1.x always sorts parameters alphabetically and + offers no way back. Generated markdown carries the 1.x schema, though its + on-disk layout is unchanged. `Build-PSBuildUpdatableHelp` warns and returns + until the cabinet pipeline migrates in + [#152](https://github.com/psake/PowerShellBuild/issues/152); it could never + succeed in 0.8.x either, see + [#169](https://github.com/psake/PowerShellBuild/issues/169). See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md). + +- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) + **Breaking:** `Test-PSBuildScriptAnalysis` now counts PSScriptAnalyzer + `ParseError` records alongside `Error`. A file that does not parse at all + previously satisfied no threshold — not even the strictest validated value, + `Information` — so it was reported and the build passed anyway. It now fails + every threshold except `None`. See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build that + passed before may now correctly fail. + +- [**#120**](https://github.com/psake/PowerShellBuild/issues/120) + **Breaking:** the module manifest now requires PowerShell 5.1 or newer + (`PowerShellVersion = '5.1'`, previously `'3.0'`) and declares + `CompatiblePSEditions = @('Desktop', 'Core')`. The support floor is + Windows PowerShell 5.1 or PowerShell 7.4+ (CI runs Windows PowerShell + 5.1 and the runners' current PowerShell 7 release). See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) for + details. + +### Added + +- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) + `Test-PSBuildScriptAnalysis` accepts `Any` as a `SeverityThreshold`, failing + the build on any diagnostic record regardless of severity. `Any` was already + documented in `build.properties.ps1` but was missing from the parameter's + `ValidateSet`, so setting + `$PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Any'` failed + parameter binding instead of working as documented. + +### Fixed + +- [**#147**](https://github.com/psake/PowerShellBuild/issues/147) + `Test-PSBuildScriptAnalysis` retries the analysis when a PSScriptAnalyzer rule + crashes on an internal race + ([PSScriptAnalyzer#1538](https://github.com/PowerShell/PSScriptAnalyzer/issues/1538)), + which is unrelated to the code being analyzed and succeeds on a re-run. + Consumers who set `$ErrorActionPreference = 'Stop'` — common in a build script — + previously got a randomly red build. A crash that survives every attempt is + still surfaced, so a persistent failure behaves as it did before. + +- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) + `Test-PSBuildScriptAnalysis` now fails the build when PSScriptAnalyzer + reports findings at or above the configured severity threshold. The + severity counts were computed from `$_Severity` — an undefined variable — + instead of `$_.Severity`, so all three counts were always zero and the + `Error`, `Warning`, and `Information` thresholds could never fail a build. + Script analysis reported its findings and the build passed regardless. + Because the default `FailBuildOnSeverityLevel` is `Error`, any consumer + running the `Analyze` task had a gate that only ever looked like it was + working. See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build + that passed before may now correctly fail. +- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) + `Test-PSBuildScriptAnalysis` no longer fails with a path-resolution error + when `SettingsPath` is not supplied. An unsupplied path was forwarded to + PSScriptAnalyzer as `-Settings ''`, which resolved against the current + directory and threw before any analysis ran, so the function's own + documented example could not run as written. +- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) + `Test-PSBuildPester` no longer raises a parameter-binding error from its + cleanup logic when the optional `ModuleName` parameter is not supplied. +- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) + `Test-PSBuildPester` now respects a Pester module that is already loaded in + the session instead of unconditionally importing the newest installed + version on top of it, which crashed with a Pester.dll version conflict when + two Pester versions were installed side by side. When no Pester is loaded, + the newest installed version (5.0.0 minimum) is imported as before, and a + loaded Pester older than 5.0.0 now produces a clear error. +- [**#138**](https://github.com/psake/PowerShellBuild/issues/138) + `Test-PSBuildPester` now reports real code coverage percentages and compares + them against `CodeCoverageThreshold` correctly. Each percentage was passed + through `[Math]::Truncate`, which collapses any fraction to zero, so the + coverage report always printed `0.00%` (or `100.00%`) and every threshold + above zero failed the build unless coverage was exactly 100%. Consumers who + set `$PSBPreference.Test.CodeCoverage.Threshold` could not use coverage + gating at all. The comparison is now strictly more permissive than before, + so a build that passed with a coverage threshold set still passes. + +## [0.8.2] 2026-07-08 + +### Fixed + +- [**#133**](https://github.com/psake/PowerShellBuild/pull/133) + `Test-PSBuildPester` now fails the build when a Pester run fails for any + reason, not only when individual tests fail. Previously the function gated + only on `FailedCount`, so a `BeforeAll`/`AfterAll` that threw or a test file + that errored during discovery left the count at zero and the build passed + despite tests never running. The gate now checks the run's aggregate + `Result` property, which Pester derives from all failure categories. + Companion to [#128](https://github.com/psake/PowerShellBuild/pull/128), + which fixes the same gap in this repository's own build file. + +## [0.8.1] 2026-06-03 + +### Fixed + +- Restore Windows PowerShell 5.1 (Desktop edition) compatibility, which regressed + in 0.8.0. `Get-PSBuildCertificate` used the PowerShell 7+-only ternary operator, + causing the file to fail to parse and the whole module to fail to import under + Windows PowerShell 5.1 — even though the manifest still declares support for it. + The ternary is replaced with an `if`/`else` expression, and the `$IsWindows` + platform guard now treats the absent automatic variable on Desktop edition as + Windows (matching the existing pattern in `Build-PSBuildUpdatableHelp`). Behavior + on PowerShell 7+ is unchanged. + +## [0.8.0] 2026-02-20 + +### Added + +- [**#92**](https://github.com/psake/PowerShellBuild/pull/92) Add Authenticode + code-signing support for PowerShell modules with three new public functions: + - `Get-PSBuildCertificate` - Resolves code-signing X509Certificate2 objects + from certificate store, PFX files, Base64-encoded environment variables, + or pre-resolved certificate objects + - `Invoke-PSBuildModuleSigning` - Signs PowerShell module files (*.psd1, + *.psm1, *.ps1) with Authenticode signatures supporting configurable + timestamp servers and hash algorithms + - `New-PSBuildFileCatalog` - Creates Windows catalog (.cat) files for + tamper detection +- New build tasks for module signing pipeline: `SignModule`, `BuildCatalog`, + `SignCatalog`, `Sign` (meta-task) +- Extended `$PSBPreference.Sign` configuration section with certificate + source selection, timestamp server configuration, hash algorithm options, + and catalog generation settings + +### Fixed + +- Remove extra backticks during localization text migration. + +## [0.7.3] 2025-08-01 + +### Added + +- Add new dependencies variables to allow end user to modify which tasks are + run. +- Add localization support. + +## [0.7.2] 2025-05-21 + +### Added + +- The `$PSBPreference` variable now supports the following PlatyPS + `New-MarkdownHelp` and `Update-MarkdownHelp` boolean options: + - `$PSBPreference.Docs.AlphabeticParamsOrder` + - `$PSBPreference.Docs.ExcludeDontShow` + - `$PSBPreference.Docs.UseFullTypeName` +- The `$PSBPreference` variable now supports the following Pester test + configuration options: + - `$PSBPreference.Test.SkipRemainingOnFailure` can be set to **None**, + **Run**, **Container** and **Block**. The default value is **None**. + - `$PSBPreference.Test.OutputVerbosity` can be set to **None**, **Normal**, + **Detailed**, and **Diagnostic**. The default value is **Detailed**. + +## [0.7.1] 2025-04-01 + +### Fixes + +- Fix a bug in `Build-PSBuildMarkdown` where a hashtable item was added twice. + +## [0.7.0] 2025-03-31 + +### Changed + +- [**#71**](https://github.com/psake/PowerShellBuild/pull/71) Compiled modules + are now explicitly created as UTF-8 files. +- [**#67**](https://github.com/psake/PowerShellBuild/pull/67) You can now + overwrite existing markdown files using `$PSBPreference.Docs.Overwrite` and + setting it to `$true`. +- [**#72**](https://github.com/psake/PowerShellBuild/pull/72) Loosen + dependencies by allowing them to be overwritten with + `$PSBPreference.TaskDependencies`. + +## [0.6.2] 2024-10-06 + +### Changed + +- Bump Pester to latest 5.6.1 + +### Fixed + +- [**#52**](https://github.com/psake/PowerShellBuild/pull/52) Pester object + wasn't being passed back after running tests, causing the Pester task to never + fail (via [@webtroter](https://github.com/webtroter)) +- [**#55**](https://github.com/psake/PowerShellBuild/pull/55) Add `-Module` + parameter to `Build-PSBuildUpdatableHelp` (via + [@IMJLA](https://github.com/IMJLA)) +- [**#60**](https://github.com/psake/PowerShellBuild/pull/60) Fix Windows + PowerShell compatibility in `Initialize-PSBuild` (via + [@joshooaj](https://github.com/joshooaj)) +- [**#62**](https://github.com/psake/PowerShellBuild/pull/62) Fix code coverage + output fle format not working (via + [@OpsM0nkey](https://github.com/OpsM0nkey)) + +## [0.6.1] 2021-03-14 + +### Fixed + +- Fixed bug in IB task `GenerateMarkdown` when dot sourcing precondition + +## [0.6.0] 2021-03-14 + +### Changed + +- [**#50**](https://github.com/psake/PowerShellBuild/pull/50) Invoke-Build tasks + brought inline with psake equivalents (via + [@JustinGrote](https://github.com/JustinGrote)) + +## [0.5.0] 2021-02-27 + +### Added + +- New code coverage parameters for setting output path and format: + - `$PSBPreference.Test.CodeCoverage.OutputFile` - Output file path for code + coverage results + - `$PSBPreference.Test.CodeCoverage.OutputFileFormat` - Code coverage output + format + +## [0.5.0] (beta1) - 2020-11-15 + +### Added + +- When "compiling" a monolithic PSM1, add support for both inserting + headers/footers for the entire PSM1, and for each script file. Control these + via the following new build parameters (via + [@pauby](https://github.com/pauby)) + - `$PSBPreference.Build.CompileHeader` + - `$PSBPreference.Build.CompileFooter` + - `$PSBPreference.Build.CompileScriptHeader` + - `$PSBPreference.Build.CompileScriptFooter` + +- Add ability to import project module from output directory prior to executing + Pester tests. Toggle this with `$PSBPreference.Test.ImportModule`. Defaults to + `$false`. (via [@joeypiccola](https://github.com/joeypiccola)) + +- Use `$PSBPreference.Build.CompileDirectories` to control directories who's + contents will be concatenated into the PSM1 when + `$PSBPreference.Build.CompileModule` is `$true`. Defaults to + `@('Enum', 'Classes', 'Private', 'Public')`. +- Use `$PSBPreference.Build.CopyDirectories` to control directories that will be + copied "as is" into the built module. Default is an empty array. + +### Changed + +- `$PSBPreference.Build.Exclude` now should be a list of regex expressions when + `$PSBPreference.Build.CompileModule` is `$false` (default). + +- Use Pester v5 + +### Fixed + +- Overriding `$PSBPreference.Build.OutDir` now correctly determines the final + module output directory. `$PSBPreference.Build.ModuleOutDir` is now computed + internally and **SHOULD NOT BE SET DIRECTLY**. `$PSBPreference.Build.OutDir` + will accept both relative and fully-qualified paths. + +- Before, when `$PSBPreference.Build.CompileModule` was set to `$true`, any + files listed in `$PSBPreference.Build.Exclude` weren't being excluded like + they should have been. Now, when it is `$true`, files matching regex + expressions in `$PSBPreference.Build.Exclude` will be properly excluded (via + [@pauby](https://github.com/pauby)) + +- `$PSBPreference.Help.DefaultLocale` now defaults to `en-US` on Linux since it + is not correctly determined with `Get-UICulture`. + +## [0.4.0] - 2019-08-31 + +### Changed + +- Allow using both `Credential` and `ApiKey` when publishing a module (via + [@pauby](https://github.com/pauby)) + +### Fixed + +- Don't overwrite Pester parameters when specifying `OutputPath` or + `OutputFormat` (via [@ChrisLGardner](https://github.com/ChrisLGardner)) + +## [0.3.1] - 2019-06-09 + +### Fixed + +- Don't create module page MD file. + +## [0.3.0] - 2019-04-23 + +### Fixed + +- [**#24**](https://github.com/psake/PowerShellBuild/pull/24) Fix case of + 'Public' folder when dot sourcing functions in PSM1 (via + [@pauby](https://github.com/pauby)) + +### Breaking changes + +- Refactor build properties into a single hashtable `$PSBPreference` + +### Changed + +- [**#11**](https://github.com/psake/PowerShellBuild/pull/11) The Invoke-Build + tasks are now auto-generated from the psake tasks via a converter script (via + [@JustinGrote](https://github.com/JustinGrote)) + +- [**#19**](https://github.com/psake/PowerShellBuild/pull/19) Allow the + `BHBuildOutput` environment variable defined by `BuildHelpers` to be set via + the `$PSBPreference.Build.ModuleOutDir` property of the build tasks (via + [@pauby](https://github.com/pauby)) + +## [0.2.0] - 2018-11-15 + +### Added + +- Add `Publish` task to publish the module to the defined PowerShell Repository + (PSGallery by default). + +## [0.1.1] - 2018-11-09 + +### Fixed + +- [**#4**](https://github.com/psake/PowerShellBuild/pull/4) Fix syntax for + `Analyze` task in `IB.tasks.ps1` (via + [@nightroman](https://github.com/nightroman)) + +## [0.1.0] - 2018-11-07 + +### Added + +- Initial commit + + diff --git a/PowerShellBuild/IB.tasks.ps1 b/PowerShellBuild/IB.tasks.ps1 index fe54942..fe50828 100644 --- a/PowerShellBuild/IB.tasks.ps1 +++ b/PowerShellBuild/IB.tasks.ps1 @@ -109,8 +109,8 @@ Task Pester -If (. $pesterPreReqs) Build, { $genMarkdownPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result @@ -124,7 +124,6 @@ Task GenerateMarkdown -if (. $genMarkdownPreReqs) StageFiles, { DocsPath = $PSBPreference.Docs.RootDir Locale = $PSBPreference.Help.DefaultLocale Overwrite = $PSBPreference.Docs.Overwrite - AlphabeticParamsOrder = $PSBPreference.Docs.AlphabeticParamsOrder ExcludeDontShow = $PSBPreference.Docs.ExcludeDontShow UseFullTypeName = $PSBPreference.Docs.UseFullTypeName } @@ -133,8 +132,8 @@ Task GenerateMarkdown -if (. $genMarkdownPreReqs) StageFiles, { $genHelpFilesPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result @@ -147,8 +146,8 @@ Task GenerateMAML -if (. $genHelpFilesPreReqs) GenerateMarkdown, { $genUpdatableHelpPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result diff --git a/PowerShellBuild/PowerShellBuild.psd1 b/PowerShellBuild/PowerShellBuild.psd1 index 16538fc..e87cd1b 100644 --- a/PowerShellBuild/PowerShellBuild.psd1 +++ b/PowerShellBuild/PowerShellBuild.psd1 @@ -11,7 +11,6 @@ RequiredModules = @( @{ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.16' } @{ModuleName = 'Pester'; ModuleVersion = '5.6.1' } - @{ModuleName = 'platyPS'; ModuleVersion = '0.14.1' } @{ModuleName = 'psake'; ModuleVersion = '4.9.0' } ) FunctionsToExport = @( diff --git a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 index 20d42a6..a1e9d67 100644 --- a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 @@ -27,13 +27,50 @@ function Build-PSBuildMAMLHelp { # Generate the module's primary MAML help file foreach ($locale in $helpLocales) { - $externalHelpParams = @{ - Path = [IO.Path]::Combine($Path, $locale) - OutputPath = [IO.Path]::Combine($DestinationPath, $locale) - Force = $true - ErrorAction = 'SilentlyContinue' - Verbose = $VerbosePreference + $localePath = [IO.Path]::Combine($Path, $locale) + + # Only command documents can be exported. A module landing page imports without + # complaint but fails on export, and that failure aborts the whole batch and writes + # nothing, so it has to be filtered out rather than caught. + $commandMarkdownPath = @( + Measure-PlatyPSMarkdown -Path ([IO.Path]::Combine($localePath, '*.md')) | + Where-Object { $_.Filetype -match 'CommandHelp' } | + Select-Object -ExpandProperty 'FilePath' + ) + if ($commandMarkdownPath.Count -eq 0) { + continue + } + + # Export-MamlCommandHelp writes to //, + # a level deeper than PowerShell looks and with the file name taken from the + # document's front matter. Export to a staging directory and move the results so the + # published layout stays //-help.xml, which is + # where every consumer's existing .ExternalHelp directive already points. + $stagingPath = [IO.Path]::Combine( + [IO.Path]::GetTempPath(), + [IO.Path]::GetRandomFileName() + ) + try { + $mamlFile = @( + Import-MarkdownCommandHelp -Path $commandMarkdownPath | + Export-MamlCommandHelp -OutputFolder $stagingPath -Force -Verbose:($VerbosePreference -eq 'Continue') + ) + + $localeDestinationPath = [IO.Path]::Combine($DestinationPath, $locale) + if (-not (Test-Path -LiteralPath $localeDestinationPath)) { + New-Item -Path $localeDestinationPath -ItemType Directory -Force > $null + } + + foreach ($file in $mamlFile) { + # PlatyPS 1.x capitalizes the suffix as "-Help.xml" where 0.14.x wrote + # "-help.xml". Preserving the old casing keeps existing .ExternalHelp + # directives resolving on case-sensitive file systems. + $destinationFileName = $file.Name -replace '-Help\.xml$', '-help.xml' + $destinationFilePath = Join-Path -Path $localeDestinationPath -ChildPath $destinationFileName + Move-Item -LiteralPath $file.FullName -Destination $destinationFilePath -Force + } + } finally { + Remove-Item -LiteralPath $stagingPath -Recurse -Force -ErrorAction SilentlyContinue } - New-ExternalHelp @externalHelpParams > $null } } diff --git a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 index 9010543..eddbeb9 100644 --- a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 @@ -4,6 +4,10 @@ function Build-PSBuildMarkdown { Creates PlatyPS markdown documents based on comment-based help of module. .DESCRIPTION Creates PlatyPS markdown documents based on comment-based help of module. + + Existing command markdown is refreshed in place with Update-MarkdownCommandHelp so + hand-written prose survives, and markdown for commands that have no document yet is + generated with New-MarkdownCommandHelp. .PARAMETER ModulePath The path to the module .PARAMETER ModuleName @@ -14,8 +18,6 @@ function Build-PSBuildMarkdown { The locale to save the markdown docs. .PARAMETER Overwrite Overwrite existing markdown files and use comment based help as the source of truth. - .PARAMETER AlphabeticParamsOrder - Order parameters alphabetically by name in PARAMETERS section. There are 5 exceptions: -Confirm, -WhatIf, -IncludeTotalCount, -Skip, and -First parameters will be the last. .PARAMETER ExcludeDontShow Exclude the parameters marked with `DontShow` in the parameter attribute from the help content. .PARAMETER UseFullTypeName @@ -42,9 +44,6 @@ function Build-PSBuildMarkdown { [parameter(Mandatory)] [bool]$Overwrite, - [parameter(Mandatory)] - [bool]$AlphabeticParamsOrder, - [parameter(Mandatory)] [bool]$ExcludeDontShow, @@ -60,41 +59,72 @@ function Build-PSBuildMarkdown { return } - if (-not (Test-Path -LiteralPath $DocsPath)) { - New-Item -Path $DocsPath -ItemType Directory > $null + $localePath = [IO.Path]::Combine($DocsPath, $Locale) + if (-not (Test-Path -LiteralPath $localePath)) { + New-Item -Path $localePath -ItemType Directory -Force > $null } - if (Get-ChildItem -LiteralPath $DocsPath -Filter *.md -Recurse) { - $updateMDParams = @{ - AlphabeticParamsOrder = $AlphabeticParamsOrder - ExcludeDontShow = $ExcludeDontShow - UseFullTypeName = $UseFullTypeName - Verbose = $VerbosePreference - } - Get-ChildItem -LiteralPath $DocsPath -Directory | ForEach-Object { - Update-MarkdownHelp -Path $_.FullName @updateMDParams > $null + # Refresh first. Update-MarkdownCommandHelp merges the module's current surface into + # existing documents and preserves hand-written prose, where regenerating would + # discard it. -NoBackup keeps it from littering the docs tree with .md.bak files. + # Module landing pages are a different document type and are left alone. + $existingMarkdown = @( + Get-ChildItem -LiteralPath $localePath -Filter '*.md' -File -ErrorAction SilentlyContinue + ) + if ($existingMarkdown.Count -gt 0) { + $existingCommandMarkdown = @( + $existingMarkdown.Where({ + (Measure-PlatyPSMarkdown -LiteralPath $_.FullName).Filetype -match 'CommandHelp' + }) + ) + if ($existingCommandMarkdown.Count -gt 0) { + Update-MarkdownCommandHelp -LiteralPath $existingCommandMarkdown.FullName -NoBackup > $null } } - # ErrorAction set to SilentlyContinue so this command will not overwrite an existing MD file. - $newMDParams = @{ - Module = $ModuleName - Locale = $Locale - OutputFolder = [IO.Path]::Combine($DocsPath, $Locale) - AlphabeticParamsOrder = $AlphabeticParamsOrder - ExcludeDontShow = $ExcludeDontShow - UseFullTypeName = $UseFullTypeName - ErrorAction = 'SilentlyContinue' - Verbose = $VerbosePreference - } - if ($Overwrite) { - $newMDParams.Add('Force', $true) - $newMDParams.Remove('ErrorAction') + # New-MarkdownCommandHelp always writes to /, and without + # -Force it skips existing files with a warning rather than an error. Generating into + # an empty staging directory and moving the results keeps the documented + # / layout and keeps Overwrite meaning what it did before. + $stagingPath = [IO.Path]::Combine( + [IO.Path]::GetTempPath(), + [IO.Path]::GetRandomFileName() + ) + try { + $newMarkdownParams = @{ + ModuleInfo = $moduleInfo + OutputFolder = $stagingPath + Locale = $Locale + Verbose = $VerbosePreference + } + if ($ExcludeDontShow) { + $newMarkdownParams.ExcludeDontShow = $true + } + # The sense of this option inverted in PlatyPS 1.x: full type names are now the + # default and abbreviation is the switch, so the old setting maps to its absence. + if (-not $UseFullTypeName) { + $newMarkdownParams.AbbreviateParameterTypeName = $true + } + New-MarkdownCommandHelp @newMarkdownParams > $null + + $generatedPath = [IO.Path]::Combine($stagingPath, $ModuleName) + $generatedMarkdown = @( + Get-ChildItem -LiteralPath $generatedPath -Filter '*.md' -File -ErrorAction SilentlyContinue + ) + foreach ($markdownFile in $generatedMarkdown) { + $destinationPath = Join-Path -Path $localePath -ChildPath $markdownFile.Name + if ((Test-Path -LiteralPath $destinationPath) -and -not $Overwrite) { + # Already refreshed above; regenerating would discard hand-written prose. + continue + } + Move-Item -LiteralPath $markdownFile.FullName -Destination $destinationPath -Force + } + } finally { + Remove-Item -LiteralPath $stagingPath -Recurse -Force -ErrorAction SilentlyContinue } - New-MarkdownHelp @newMDParams > $null } catch { Write-Error ($LocalizedData.FailedToGenerateMarkdownHelp -f $_) } finally { - Remove-Module $moduleName + Remove-Module $ModuleName } } diff --git a/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 b/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 index de784eb..986a22e 100644 --- a/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 @@ -4,6 +4,11 @@ function Build-PSBuildUpdatableHelp { Create updatable help .cab file based on PlatyPS markdown help. .DESCRIPTION Create updatable help .cab file based on PlatyPS markdown help. + + Not implemented against PlatyPS 1.x yet. The cabinet pipeline is migrated in + psake/PowerShellBuild#152 along with the three defects in #169 that prevented this + function from ever succeeding. Until then it reports that updatable help was skipped + and returns without writing anything. .PARAMETER DocsPath Path to PlatyPS markdown help files. .PARAMETER OutputPath @@ -14,8 +19,11 @@ function Build-PSBuildUpdatableHelp { .EXAMPLE PS> Build-PSBuildUpdatableHelp -DocsPath ./docs -OutputPath ./Output/UpdatableHelp - Create help .cab file based on PlatyPS markdown help. + Reports that updatable help is not available and returns. #> + # The parameters are unused only because the body is stubbed. They stay so the public + # signature does not change twice -- once here and again when #152 restores the body. + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] [CmdletBinding()] param( [parameter(Mandatory)] @@ -27,44 +35,11 @@ function Build-PSBuildUpdatableHelp { [string]$Module = $ModuleName ) - if ($null -ne $IsWindows -and -not $IsWindows) { - Write-Warning $LocalizedData.MakeCabNotAvailable - return - } - - $helpLocales = (Get-ChildItem -Path $DocsPath -Directory).Name - - # Create updatable help output directory - if (-not (Test-Path -LiteralPath $OutputPath)) { - $newItemSplat = @{ - ItemType = 'Directory' - Verbose = $VerbosePreference - Path = $OutputPath - } - New-Item @newItemSplat > $null - } else { - Write-Verbose ($LocalizedData.DirectoryAlreadyExists -f $OutputPath) - $removeItemSplat = @{ - Recurse = $true - Force = $true - Verbose = $VerbosePreference - } - Get-ChildItem $OutputPath | Remove-Item @removeItemSplat - } - - # Generate updatable help files. Note: this will currently update the - # version number in the module's MD file in the metadata. - foreach ($locale in $helpLocales) { - $cabParams = @{ - CabFilesFolder = [IO.Path]::Combine($moduleOutDir, $locale) - LandingPagePath = [IO.Path]::Combine( - $DocsPath, - $locale, - "$Module.md" - ) - OutputFolder = $OutputPath - Verbose = $VerbosePreference - } - New-ExternalHelpCab @cabParams > $null - } + # Deliberately references no PlatyPS command. Naming New-ExternalHelpCab here is enough to + # make PowerShell autoload platyPS 0.14.2 on any session that resolves it, and once that + # module is loaded, Microsoft.PowerShell.PlatyPS can no longer be imported in the same + # process -- both ship their own YamlDotNet with different assembly identities. Leaving the + # old call in place would poison every session that still has 0.14.2 installed, which is + # every consumer part-way through the upgrade. + Write-Warning $LocalizedData.UpdatableHelpNotMigrated } diff --git a/PowerShellBuild/build.properties.ps1 b/PowerShellBuild/build.properties.ps1 index 541cda9..2e8d24c 100644 --- a/PowerShellBuild/build.properties.ps1 +++ b/PowerShellBuild/build.properties.ps1 @@ -126,16 +126,13 @@ $moduleVersion = (Import-PowerShellDataFile -Path $env:BHPSModuleManifest).Modul # Whether to overwrite existing markdown files and use comment based help as the source of truth Overwrite = $false - # Whether to order parameters alphabetically by name in PARAMETERS section. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. - AlphabeticParamsOrder = $false - # Exclude the parameters marked with `DontShow` in the parameter attribute from the help content. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. + # Value passed to New-MarkdownCommandHelp. ExcludeDontShow = $false # Indicates that the target document will use a full type name instead of a short name for parameters. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. + # PlatyPS 1.x writes full type names by default, so $false is passed through as + # New-MarkdownCommandHelp's -AbbreviateParameterTypeName switch. UseFullTypeName = $false } Publish = @{ diff --git a/PowerShellBuild/en-US/Messages.psd1 b/PowerShellBuild/en-US/Messages.psd1 index 9149e18..fae187d 100644 --- a/PowerShellBuild/en-US/Messages.psd1 +++ b/PowerShellBuild/en-US/Messages.psd1 @@ -3,6 +3,7 @@ NoCommandsExported=No commands have been exported. Skipping markdown generation. FailedToGenerateMarkdownHelp=Failed to generate markdown help. : {0} AddingFileToPsm1=Adding [{0}] to PSM1 MakeCabNotAvailable=MakeCab.exe is not available. Cannot create help cab. +UpdatableHelpNotMigrated=Updatable help was skipped. The cabinet pipeline has not been migrated to Microsoft.PowerShell.PlatyPS 1.x yet; see psake/PowerShellBuild#152. DirectoryAlreadyExists=Directory already exists [{0}]. PathLongerThan3Chars=Path [{0}] must be longer than 3 characters. BuildSystemDetails=Build System Details: diff --git a/PowerShellBuild/psakeFile.ps1 b/PowerShellBuild/psakeFile.ps1 index cff79f9..2208e18 100644 --- a/PowerShellBuild/psakeFile.ps1 +++ b/PowerShellBuild/psakeFile.ps1 @@ -174,8 +174,8 @@ Task BuildHelp -Depends $PSBBuildHelpDependency {} -Description 'Builds help doc $genMarkdownPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result @@ -187,7 +187,6 @@ Task GenerateMarkdown -Depends $PSBGenerateMarkdownDependency -PreCondition $gen DocsPath = $PSBPreference.Docs.RootDir Locale = $PSBPreference.Help.DefaultLocale Overwrite = $PSBPreference.Docs.Overwrite - AlphabeticParamsOrder = $PSBPreference.Docs.AlphabeticParamsOrder ExcludeDontShow = $PSBPreference.Docs.ExcludeDontShow UseFullTypeName = $PSBPreference.Docs.UseFullTypeName Verbose = $VerbosePreference -eq 'Continue' @@ -197,8 +196,8 @@ Task GenerateMarkdown -Depends $PSBGenerateMarkdownDependency -PreCondition $gen $genHelpFilesPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result @@ -209,8 +208,8 @@ Task GenerateMAML -Depends $PSBGenerateMAMLDependency -PreCondition $genHelpFile $genUpdatableHelpPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result diff --git a/docs/migration-v0.8-to-v1.0.md b/docs/migration-v0.8-to-v1.0.md index 6268436..ee05ac1 100644 --- a/docs/migration-v0.8-to-v1.0.md +++ b/docs/migration-v0.8-to-v1.0.md @@ -28,9 +28,16 @@ One line per break; follow the link for details and migration steps. - [Unparsable files now fail the script analysis gate](#unparsable-files-now-fail-the-script-analysis-gate) — `ParseError` findings are counted with `Error`, so a file that does not parse fails every threshold except `None`. +- [Help generation now uses Microsoft.PowerShell.PlatyPS 1.x, and installs it yourself](#help-generation-now-uses-microsoftpowershellplatyps-1x-and-installs-it-yourself) + — the PlatyPS dependency changed module, and is no longer installed for you. +- [`$PSBPreference.Docs.AlphabeticParamsOrder` is removed](#psbpreferencedocsalphabeticparamsorder-is-removed) + — PlatyPS 1.x always sorts alphabetically, so the setting could no longer do anything. +- [Generated markdown uses the PlatyPS 1.x schema](#generated-markdown-uses-the-platyps-1x-schema) + — expect a large diff in `docs/` on the first 1.0.0 build. +- [Updatable help is temporarily unavailable](#updatable-help-is-temporarily-unavailable) + — the cabinet pipeline is migrated before 1.0.0 ships. -> More entries will follow as the Phase 2 migrations to -> Microsoft.PowerShell.PlatyPS 1.x and psake 5.x land. +> More entries will follow as the remaining Phase 2 work lands. ## AI-assisted migration @@ -200,6 +207,125 @@ This is additive — existing values behave as before. Tracked in issue [#144](https://github.com/psake/PowerShellBuild/issues/144). +### Help generation now uses Microsoft.PowerShell.PlatyPS 1.x, and installs it yourself + +`Build-PSBuildMarkdown` and `Build-PSBuildMAMLHelp` are built on +[`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) +1.x instead of `platyPS` 0.14.x. The `GenerateMarkdown` and `GenerateMAML` +tasks now check for the new module and skip with a warning if it is +missing, exactly as they did for the old one. + +PlatyPS is **no longer listed in `RequiredModules`**, so +`Install-Module PowerShellBuild` no longer installs it for you. This is +deliberate rather than an oversight. The two PlatyPS modules each ship +their own `YamlDotNet.dll` with different assembly identities, and .NET +refuses to load both into one process — whichever imports second fails +with `Assembly with same name is already loaded`. A `RequiredModules` +entry forces that load into **every** session that imports +PowerShellBuild, including builds that never generate documentation, so +any consumer still holding `platyPS` 0.14.x — which is every consumer +part-way through this upgrade — would be unable to import PowerShellBuild +at all. Making the dependency optional matches how the docs tasks have +always behaved: they probe for the module and skip when it is absent. + +**Before (0.8.x):** + +```powershell +# platyPS arrived with PowerShellBuild via RequiredModules +Install-Module -Name PowerShellBuild +``` + +**After (1.0.0):** + +```powershell +Install-Module -Name PowerShellBuild +# Only if you build help; add it to your own requirements/bootstrap +Install-Module -Name Microsoft.PowerShell.PlatyPS -MinimumVersion 1.0.3 +``` + +**Detection:** the build prints +`Microsoft.PowerShell.PlatyPS module is not installed. Skipping [GenerateMarkdown] task.` +and produces no markdown or MAML. + +You can uninstall `platyPS` 0.14.x once nothing else on the machine needs +it. Leaving it installed is safe — it is only a problem if something +loads it into the same session that loads PlatyPS 1.x. + +Tracked in PRs [#150](https://github.com/psake/PowerShellBuild/issues/150) +and [#151](https://github.com/psake/PowerShellBuild/issues/151); chain +context in [#105](https://github.com/psake/PowerShellBuild/issues/105). + +### `$PSBPreference.Docs.AlphabeticParamsOrder` is removed + +PlatyPS 1.x always orders parameters alphabetically and offers no option +to restore declaration order, so the setting could no longer do anything. +Rather than keep a setting that silently lies, it is gone, along with the +`AlphabeticParamsOrder` parameter on `Build-PSBuildMarkdown`. + +**Before (0.8.x):** + +```powershell +$PSBPreference.Docs.AlphabeticParamsOrder = $true +``` + +**After (1.0.0):** + +```powershell +# Remove the line. Alphabetical ordering is now the only behavior. +``` + +**Detection:** setting the property no longer fails (it is a plain +hashtable), so this will not error — grep your build file for +`AlphabeticParamsOrder` and delete the assignment. Calling +`Build-PSBuildMarkdown` with `-AlphabeticParamsOrder` **does** fail, with +`A parameter cannot be found that matches parameter name 'AlphabeticParamsOrder'`. + +`ExcludeDontShow` and `UseFullTypeName` are unchanged and keep their +existing behavior. + +### Generated markdown uses the PlatyPS 1.x schema + +Markdown written into `$PSBPreference.Docs.RootDir` now carries +`PlatyPS schema version: 2024-05-01` and a `document type:` key where +0.14.x wrote `schema: 2.0.0`. Command documents also gain an `## ALIASES` +section and per-parameter-set `### __AllParameterSets` headings inside +`SYNTAX`. + +The on-disk layout is unchanged: documents stay at +`//.md`, and MAML still lands at +`//-help.xml`. PlatyPS 1.x would +otherwise nest both a level deeper under a `` directory; +PowerShellBuild flattens that back out so existing docs trees, static +site configuration, and `.ExternalHelp` directives keep working. + +**Detection:** your first 1.0.0 build produces a large diff in `docs/`. + +If you **commit** your `docs/` tree, review that diff for lost prose +before committing it. Existing documents are refreshed in place with +`Update-MarkdownCommandHelp`, which preserves hand-written content, so +this should be schema churn rather than content loss — but verify. +Consumer guidance for converting a committed tree is +[#154](https://github.com/psake/PowerShellBuild/issues/154). + +### Updatable help is temporarily unavailable + +`Build-PSBuildUpdatableHelp` and the `GenerateUpdatableHelp` task write a +warning and return without producing a cabinet. The 1.x cabinet pipeline +is migrated in [#152](https://github.com/psake/PowerShellBuild/issues/152) +before 1.0.0 ships. + +This costs nothing in practice: the function could never succeed in +0.8.x either. It required a module landing page that +`Build-PSBuildMarkdown` never generated, and it passed an undefined +variable as the cabinet source folder — three separate defects, recorded +in [#169](https://github.com/psake/PowerShellBuild/issues/169). The task +is opt-in and is not part of the default build, so most consumers never +reached it. + +**Detection:** `Updatable help was skipped. The cabinet pipeline has not +been migrated to Microsoft.PowerShell.PlatyPS 1.x yet` in the build +output, where 0.8.x raised a parameter-binding error. + ## Adding an entry (for PR contributors) Every breaking-change PR that lands in v1.0.0 must add an entry here for diff --git a/instructions/repository-specific.instructions.md b/instructions/repository-specific.instructions.md index c10d30f..ad048f7 100644 --- a/instructions/repository-specific.instructions.md +++ b/instructions/repository-specific.instructions.md @@ -232,7 +232,7 @@ versions — and installed via **PSDepend** when `./build.ps1 -Bootstrap` runs: | psake | Task runner for this repo's own build | | PSScriptAnalyzer | Static analysis of the built module | | InvokeBuild | Alternate task runner (consumer-facing `IB.tasks.ps1`) | -| platyPS | Help and documentation generation | +| Microsoft.PowerShell.PlatyPS | Help and documentation generation (optional; not a required module) | ## Testing diff --git a/requirements.psd1 b/requirements.psd1 index 3f920f5..bc837ae 100755 --- a/requirements.psd1 +++ b/requirements.psd1 @@ -12,5 +12,8 @@ psake = '5.0.4' PSScriptAnalyzer = '1.25.0' InvokeBuild = '5.14.23' - platyPS = '0.14.2' + PlatyPS = @{ + Name = 'Microsoft.PowerShell.PlatyPS' + Version = '1.0.3' + } } diff --git a/tests/Build-PSBuildHelp.tests.ps1 b/tests/Build-PSBuildHelp.tests.ps1 index e10236c..1d38a2b 100644 --- a/tests/Build-PSBuildHelp.tests.ps1 +++ b/tests/Build-PSBuildHelp.tests.ps1 @@ -21,8 +21,8 @@ BeforeDiscovery { # The psake PreConditions on the docs tasks gate on exactly this, so the tests behave the - # same way the shipped tasks do: absent platyPS means skipped, not failed. - $script:platyPSAvailable = [bool](Get-Module -Name 'platyPS' -ListAvailable) + # same way the shipped tasks do: an absent module means skipped, not failed. + $script:platyPSAvailable = [bool](Get-Module -Name 'Microsoft.PowerShell.PlatyPS' -ListAvailable) # Build-PSBuildUpdatableHelp returns early on non-Windows, and Windows PowerShell 5.1 has # no $IsWindows at all, so it takes the Windows path there. Resolved at discovery because @@ -85,12 +85,23 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { Should -Not -Exist } - It 'produces markdown carrying the 0.14.x schema marker' { - # The 0.14.x front matter carries "external help file" and "schema: 2.0.0". The 1.x - # schema drops the latter, so this assertion is the tripwire that says the - # migration in #150 actually changed the output format. + It 'produces markdown carrying the 1.x schema marker' { + # 0.14.x front matter carried "schema: 2.0.0". 1.x replaces it with a dated schema + # version and a document type, so this pins the migration rather than just passing + # either way. $markdownPath = Join-Path -Path $script:markdownScenario.LocalePath -ChildPath 'Get-Widget.md' - Get-Content -Path $markdownPath -Raw | Should -Match 'schema:\s*2\.0\.0' + $markdown = Get-Content -Path $markdownPath -Raw + $markdown | Should -Match 'PlatyPS schema version:' + $markdown | Should -Match 'document type:\s*cmdlet' + $markdown | Should -Not -Match 'schema:\s*2\.0\.0' + } + + It 'keeps the markdown directly under the locale directory' { + # New-MarkdownCommandHelp writes to /. The function + # flattens that back out, so a nested module directory here means the flattening + # regressed and every downstream path assumption breaks with it. + Join-Path -Path $script:markdownScenario.LocalePath -ChildPath $script:markdownScenario.ModuleName | + Should -Not -Exist } } @@ -136,23 +147,6 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { BeforeAll { $script:cabScenario = New-PSBuildDocsScenario -Path $TestDrive -Name 'cab' - $cabMarkdownJobParameter = @{ - ModulePath = $script:builtModulePath - CommandName = 'Build-PSBuildMarkdown' - Parameter = New-PSBuildMarkdownParameter -Scenario $script:cabScenario - } - $null = Invoke-PSBuildCommandInJob @cabMarkdownJobParameter - - $cabMamlJobParameter = @{ - ModulePath = $script:builtModulePath - CommandName = 'Build-PSBuildMAMLHelp' - Parameter = @{ - Path = $script:cabScenario.DocsPath - DestinationPath = $script:cabScenario.OutputPath - } - } - $null = Invoke-PSBuildCommandInJob @cabMamlJobParameter - $cabJobParameter = @{ ModulePath = $script:builtModulePath CommandName = 'Build-PSBuildUpdatableHelp' @@ -165,42 +159,18 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { $script:cabResult = Invoke-PSBuildCommandInJob @cabJobParameter } - It 'declines to run on platforms without makecab' -Skip:$script:onWindows { + # Pins the documented intermediate state, not the destination. The cabinet pipeline + # migrates in #152 together with the three defects in #169 that stopped this function + # ever succeeding. Until then it must fail quietly rather than throw, and above all it + # must not name a platyPS 0.14.2 command: resolving one autoloads that module, and a + # session holding it can no longer import Microsoft.PowerShell.PlatyPS at all. + It 'returns without throwing' { $script:cabResult.Threw | Should -BeFalse - $script:cabScenario.UpdatableHelpPath | Should -Not -Exist - } - - It 'creates the output directory' -Skip:(-not $script:onWindows) { - # This much works today: the directory is created before the cab step throws. - $script:cabScenario.UpdatableHelpPath | Should -Exist + $script:cabResult.ErrorMessage | Should -BeNullOrEmpty } - It 'fails parameter binding on the cab step' -Skip:(-not $script:onWindows) { - # Pins the CURRENT broken behavior so the baseline is honest about what happens, - # and so fixing psake/PowerShellBuild#169 forces this test to be revisited rather - # than leaving a silent pass. Delete this test when #169 is fixed; the two below - # replace it. - # - # Either of two independent defects can surface first, depending on the order - # PowerShell binds the splatted parameters: LandingPagePath points at a module page - # that is never generated, and CabFilesFolder is built from the undefined - # $moduleOutDir, which collapses to the bare locale name. Asserting on one of them - # specifically makes this test flaky, so it accepts either. - $script:cabResult.Threw | Should -BeTrue - $script:cabResult.ErrorMessage | Should -Match 'LandingPagePath|CabFilesFolder' - } - - It 'produces a cabinet file' -Skip { - # Skipped pending psake/PowerShellBuild#169. This is the acceptance criterion for - # that fix and for the #152 migration, written now so it is not written twice. - Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*.cab' | - Should -Not -BeNullOrEmpty - } - - It 'produces the help info manifest' -Skip { - # Skipped pending psake/PowerShellBuild#169. See above. - Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*HelpInfo.xml' | - Should -Not -BeNullOrEmpty + It 'writes nothing' { + $script:cabScenario.UpdatableHelpPath | Should -Not -Exist } } } diff --git a/tests/fixtures/FixtureHelpers.psm1 b/tests/fixtures/FixtureHelpers.psm1 index 744a2ee..5e7bc7b 100644 --- a/tests/fixtures/FixtureHelpers.psm1 +++ b/tests/fixtures/FixtureHelpers.psm1 @@ -115,17 +115,14 @@ function New-PSBuildMarkdownParameter { .SYNOPSIS Build the Build-PSBuildMarkdown parameter set for a docs scenario. .DESCRIPTION - Build-PSBuildMarkdown takes four mandatory [bool] parameters that most tests do not care - about but cannot omit. This supplies them at their build.properties.ps1 defaults so a + Build-PSBuildMarkdown takes three mandatory [bool] parameters that most tests do not + care about but cannot omit. This supplies them at their build.properties.ps1 defaults so a test only has to name the ones it is actually exercising. .PARAMETER Scenario Scenario object from New-PSBuildDocsScenario. .PARAMETER Overwrite Whether comment-based help overwrites existing markdown. Defaults to $false, matching $PSBPreference.Docs.Overwrite. - .PARAMETER AlphabeticParamsOrder - Whether parameters are ordered alphabetically. Defaults to $false, matching - $PSBPreference.Docs.AlphabeticParamsOrder. .PARAMETER ExcludeDontShow Whether parameters marked DontShow are excluded. Defaults to $false, matching $PSBPreference.Docs.ExcludeDontShow. @@ -153,9 +150,6 @@ function New-PSBuildMarkdownParameter { [bool] $Overwrite = $false, - [bool] - $AlphabeticParamsOrder = $false, - [bool] $ExcludeDontShow = $false, @@ -169,7 +163,6 @@ function New-PSBuildMarkdownParameter { DocsPath = $Scenario.DocsPath Locale = $Scenario.Locale Overwrite = $Overwrite - AlphabeticParamsOrder = $AlphabeticParamsOrder ExcludeDontShow = $ExcludeDontShow UseFullTypeName = $UseFullTypeName } From 7db09e76495d7cbd20d758f6076def310fb94173 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Mon, 24 Aug 2026 16:42:17 -0400 Subject: [PATCH 2/3] fix: Repair doubled carriage returns in the changelog The entry was inserted by a script that joined lines with CRLF and then converted newlines again, turning every added line ending into \r\r\n. That rewrote the whole file as far as git was concerned, burying a twenty-line addition in a 691-line diff. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012AKaM9i6NyMFDcJNeC34h5 --- CHANGELOG.md | 708 +++++++++++++++++++++++++-------------------------- 1 file changed, 354 insertions(+), 354 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0ed861..78fa432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,354 +1,354 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) -and this project adheres to [Semantic Versioning](http://semver.org/). - -## Unreleased - -### Changed - -- [**#105**](https://github.com/psake/PowerShellBuild/issues/105) - **Breaking:** help generation moved from `platyPS` 0.14.x to - [`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) - 1.x. PlatyPS is also no longer a `RequiredModules` entry, so - `Install-Module PowerShellBuild` no longer installs it — the two PlatyPS - modules cannot be loaded into one process, so forcing the new one into every - session would break any consumer still holding the old one. Install it - yourself if you build help. `$PSBPreference.Docs.AlphabeticParamsOrder` is - removed, because PlatyPS 1.x always sorts parameters alphabetically and - offers no way back. Generated markdown carries the 1.x schema, though its - on-disk layout is unchanged. `Build-PSBuildUpdatableHelp` warns and returns - until the cabinet pipeline migrates in - [#152](https://github.com/psake/PowerShellBuild/issues/152); it could never - succeed in 0.8.x either, see - [#169](https://github.com/psake/PowerShellBuild/issues/169). See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md). - -- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) - **Breaking:** `Test-PSBuildScriptAnalysis` now counts PSScriptAnalyzer - `ParseError` records alongside `Error`. A file that does not parse at all - previously satisfied no threshold — not even the strictest validated value, - `Information` — so it was reported and the build passed anyway. It now fails - every threshold except `None`. See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build that - passed before may now correctly fail. - -- [**#120**](https://github.com/psake/PowerShellBuild/issues/120) - **Breaking:** the module manifest now requires PowerShell 5.1 or newer - (`PowerShellVersion = '5.1'`, previously `'3.0'`) and declares - `CompatiblePSEditions = @('Desktop', 'Core')`. The support floor is - Windows PowerShell 5.1 or PowerShell 7.4+ (CI runs Windows PowerShell - 5.1 and the runners' current PowerShell 7 release). See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) for - details. - -### Added - -- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) - `Test-PSBuildScriptAnalysis` accepts `Any` as a `SeverityThreshold`, failing - the build on any diagnostic record regardless of severity. `Any` was already - documented in `build.properties.ps1` but was missing from the parameter's - `ValidateSet`, so setting - `$PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Any'` failed - parameter binding instead of working as documented. - -### Fixed - -- [**#147**](https://github.com/psake/PowerShellBuild/issues/147) - `Test-PSBuildScriptAnalysis` retries the analysis when a PSScriptAnalyzer rule - crashes on an internal race - ([PSScriptAnalyzer#1538](https://github.com/PowerShell/PSScriptAnalyzer/issues/1538)), - which is unrelated to the code being analyzed and succeeds on a re-run. - Consumers who set `$ErrorActionPreference = 'Stop'` — common in a build script — - previously got a randomly red build. A crash that survives every attempt is - still surfaced, so a persistent failure behaves as it did before. - -- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) - `Test-PSBuildScriptAnalysis` now fails the build when PSScriptAnalyzer - reports findings at or above the configured severity threshold. The - severity counts were computed from `$_Severity` — an undefined variable — - instead of `$_.Severity`, so all three counts were always zero and the - `Error`, `Warning`, and `Information` thresholds could never fail a build. - Script analysis reported its findings and the build passed regardless. - Because the default `FailBuildOnSeverityLevel` is `Error`, any consumer - running the `Analyze` task had a gate that only ever looked like it was - working. See the - [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build - that passed before may now correctly fail. -- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) - `Test-PSBuildScriptAnalysis` no longer fails with a path-resolution error - when `SettingsPath` is not supplied. An unsupplied path was forwarded to - PSScriptAnalyzer as `-Settings ''`, which resolved against the current - directory and threw before any analysis ran, so the function's own - documented example could not run as written. -- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) - `Test-PSBuildPester` no longer raises a parameter-binding error from its - cleanup logic when the optional `ModuleName` parameter is not supplied. -- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) - `Test-PSBuildPester` now respects a Pester module that is already loaded in - the session instead of unconditionally importing the newest installed - version on top of it, which crashed with a Pester.dll version conflict when - two Pester versions were installed side by side. When no Pester is loaded, - the newest installed version (5.0.0 minimum) is imported as before, and a - loaded Pester older than 5.0.0 now produces a clear error. -- [**#138**](https://github.com/psake/PowerShellBuild/issues/138) - `Test-PSBuildPester` now reports real code coverage percentages and compares - them against `CodeCoverageThreshold` correctly. Each percentage was passed - through `[Math]::Truncate`, which collapses any fraction to zero, so the - coverage report always printed `0.00%` (or `100.00%`) and every threshold - above zero failed the build unless coverage was exactly 100%. Consumers who - set `$PSBPreference.Test.CodeCoverage.Threshold` could not use coverage - gating at all. The comparison is now strictly more permissive than before, - so a build that passed with a coverage threshold set still passes. - -## [0.8.2] 2026-07-08 - -### Fixed - -- [**#133**](https://github.com/psake/PowerShellBuild/pull/133) - `Test-PSBuildPester` now fails the build when a Pester run fails for any - reason, not only when individual tests fail. Previously the function gated - only on `FailedCount`, so a `BeforeAll`/`AfterAll` that threw or a test file - that errored during discovery left the count at zero and the build passed - despite tests never running. The gate now checks the run's aggregate - `Result` property, which Pester derives from all failure categories. - Companion to [#128](https://github.com/psake/PowerShellBuild/pull/128), - which fixes the same gap in this repository's own build file. - -## [0.8.1] 2026-06-03 - -### Fixed - -- Restore Windows PowerShell 5.1 (Desktop edition) compatibility, which regressed - in 0.8.0. `Get-PSBuildCertificate` used the PowerShell 7+-only ternary operator, - causing the file to fail to parse and the whole module to fail to import under - Windows PowerShell 5.1 — even though the manifest still declares support for it. - The ternary is replaced with an `if`/`else` expression, and the `$IsWindows` - platform guard now treats the absent automatic variable on Desktop edition as - Windows (matching the existing pattern in `Build-PSBuildUpdatableHelp`). Behavior - on PowerShell 7+ is unchanged. - -## [0.8.0] 2026-02-20 - -### Added - -- [**#92**](https://github.com/psake/PowerShellBuild/pull/92) Add Authenticode - code-signing support for PowerShell modules with three new public functions: - - `Get-PSBuildCertificate` - Resolves code-signing X509Certificate2 objects - from certificate store, PFX files, Base64-encoded environment variables, - or pre-resolved certificate objects - - `Invoke-PSBuildModuleSigning` - Signs PowerShell module files (*.psd1, - *.psm1, *.ps1) with Authenticode signatures supporting configurable - timestamp servers and hash algorithms - - `New-PSBuildFileCatalog` - Creates Windows catalog (.cat) files for - tamper detection -- New build tasks for module signing pipeline: `SignModule`, `BuildCatalog`, - `SignCatalog`, `Sign` (meta-task) -- Extended `$PSBPreference.Sign` configuration section with certificate - source selection, timestamp server configuration, hash algorithm options, - and catalog generation settings - -### Fixed - -- Remove extra backticks during localization text migration. - -## [0.7.3] 2025-08-01 - -### Added - -- Add new dependencies variables to allow end user to modify which tasks are - run. -- Add localization support. - -## [0.7.2] 2025-05-21 - -### Added - -- The `$PSBPreference` variable now supports the following PlatyPS - `New-MarkdownHelp` and `Update-MarkdownHelp` boolean options: - - `$PSBPreference.Docs.AlphabeticParamsOrder` - - `$PSBPreference.Docs.ExcludeDontShow` - - `$PSBPreference.Docs.UseFullTypeName` -- The `$PSBPreference` variable now supports the following Pester test - configuration options: - - `$PSBPreference.Test.SkipRemainingOnFailure` can be set to **None**, - **Run**, **Container** and **Block**. The default value is **None**. - - `$PSBPreference.Test.OutputVerbosity` can be set to **None**, **Normal**, - **Detailed**, and **Diagnostic**. The default value is **Detailed**. - -## [0.7.1] 2025-04-01 - -### Fixes - -- Fix a bug in `Build-PSBuildMarkdown` where a hashtable item was added twice. - -## [0.7.0] 2025-03-31 - -### Changed - -- [**#71**](https://github.com/psake/PowerShellBuild/pull/71) Compiled modules - are now explicitly created as UTF-8 files. -- [**#67**](https://github.com/psake/PowerShellBuild/pull/67) You can now - overwrite existing markdown files using `$PSBPreference.Docs.Overwrite` and - setting it to `$true`. -- [**#72**](https://github.com/psake/PowerShellBuild/pull/72) Loosen - dependencies by allowing them to be overwritten with - `$PSBPreference.TaskDependencies`. - -## [0.6.2] 2024-10-06 - -### Changed - -- Bump Pester to latest 5.6.1 - -### Fixed - -- [**#52**](https://github.com/psake/PowerShellBuild/pull/52) Pester object - wasn't being passed back after running tests, causing the Pester task to never - fail (via [@webtroter](https://github.com/webtroter)) -- [**#55**](https://github.com/psake/PowerShellBuild/pull/55) Add `-Module` - parameter to `Build-PSBuildUpdatableHelp` (via - [@IMJLA](https://github.com/IMJLA)) -- [**#60**](https://github.com/psake/PowerShellBuild/pull/60) Fix Windows - PowerShell compatibility in `Initialize-PSBuild` (via - [@joshooaj](https://github.com/joshooaj)) -- [**#62**](https://github.com/psake/PowerShellBuild/pull/62) Fix code coverage - output fle format not working (via - [@OpsM0nkey](https://github.com/OpsM0nkey)) - -## [0.6.1] 2021-03-14 - -### Fixed - -- Fixed bug in IB task `GenerateMarkdown` when dot sourcing precondition - -## [0.6.0] 2021-03-14 - -### Changed - -- [**#50**](https://github.com/psake/PowerShellBuild/pull/50) Invoke-Build tasks - brought inline with psake equivalents (via - [@JustinGrote](https://github.com/JustinGrote)) - -## [0.5.0] 2021-02-27 - -### Added - -- New code coverage parameters for setting output path and format: - - `$PSBPreference.Test.CodeCoverage.OutputFile` - Output file path for code - coverage results - - `$PSBPreference.Test.CodeCoverage.OutputFileFormat` - Code coverage output - format - -## [0.5.0] (beta1) - 2020-11-15 - -### Added - -- When "compiling" a monolithic PSM1, add support for both inserting - headers/footers for the entire PSM1, and for each script file. Control these - via the following new build parameters (via - [@pauby](https://github.com/pauby)) - - `$PSBPreference.Build.CompileHeader` - - `$PSBPreference.Build.CompileFooter` - - `$PSBPreference.Build.CompileScriptHeader` - - `$PSBPreference.Build.CompileScriptFooter` - -- Add ability to import project module from output directory prior to executing - Pester tests. Toggle this with `$PSBPreference.Test.ImportModule`. Defaults to - `$false`. (via [@joeypiccola](https://github.com/joeypiccola)) - -- Use `$PSBPreference.Build.CompileDirectories` to control directories who's - contents will be concatenated into the PSM1 when - `$PSBPreference.Build.CompileModule` is `$true`. Defaults to - `@('Enum', 'Classes', 'Private', 'Public')`. -- Use `$PSBPreference.Build.CopyDirectories` to control directories that will be - copied "as is" into the built module. Default is an empty array. - -### Changed - -- `$PSBPreference.Build.Exclude` now should be a list of regex expressions when - `$PSBPreference.Build.CompileModule` is `$false` (default). - -- Use Pester v5 - -### Fixed - -- Overriding `$PSBPreference.Build.OutDir` now correctly determines the final - module output directory. `$PSBPreference.Build.ModuleOutDir` is now computed - internally and **SHOULD NOT BE SET DIRECTLY**. `$PSBPreference.Build.OutDir` - will accept both relative and fully-qualified paths. - -- Before, when `$PSBPreference.Build.CompileModule` was set to `$true`, any - files listed in `$PSBPreference.Build.Exclude` weren't being excluded like - they should have been. Now, when it is `$true`, files matching regex - expressions in `$PSBPreference.Build.Exclude` will be properly excluded (via - [@pauby](https://github.com/pauby)) - -- `$PSBPreference.Help.DefaultLocale` now defaults to `en-US` on Linux since it - is not correctly determined with `Get-UICulture`. - -## [0.4.0] - 2019-08-31 - -### Changed - -- Allow using both `Credential` and `ApiKey` when publishing a module (via - [@pauby](https://github.com/pauby)) - -### Fixed - -- Don't overwrite Pester parameters when specifying `OutputPath` or - `OutputFormat` (via [@ChrisLGardner](https://github.com/ChrisLGardner)) - -## [0.3.1] - 2019-06-09 - -### Fixed - -- Don't create module page MD file. - -## [0.3.0] - 2019-04-23 - -### Fixed - -- [**#24**](https://github.com/psake/PowerShellBuild/pull/24) Fix case of - 'Public' folder when dot sourcing functions in PSM1 (via - [@pauby](https://github.com/pauby)) - -### Breaking changes - -- Refactor build properties into a single hashtable `$PSBPreference` - -### Changed - -- [**#11**](https://github.com/psake/PowerShellBuild/pull/11) The Invoke-Build - tasks are now auto-generated from the psake tasks via a converter script (via - [@JustinGrote](https://github.com/JustinGrote)) - -- [**#19**](https://github.com/psake/PowerShellBuild/pull/19) Allow the - `BHBuildOutput` environment variable defined by `BuildHelpers` to be set via - the `$PSBPreference.Build.ModuleOutDir` property of the build tasks (via - [@pauby](https://github.com/pauby)) - -## [0.2.0] - 2018-11-15 - -### Added - -- Add `Publish` task to publish the module to the defined PowerShell Repository - (PSGallery by default). - -## [0.1.1] - 2018-11-09 - -### Fixed - -- [**#4**](https://github.com/psake/PowerShellBuild/pull/4) Fix syntax for - `Analyze` task in `IB.tasks.ps1` (via - [@nightroman](https://github.com/nightroman)) - -## [0.1.0] - 2018-11-07 - -### Added - -- Initial commit - - +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## Unreleased + +### Changed + +- [**#105**](https://github.com/psake/PowerShellBuild/issues/105) + **Breaking:** help generation moved from `platyPS` 0.14.x to + [`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) + 1.x. PlatyPS is also no longer a `RequiredModules` entry, so + `Install-Module PowerShellBuild` no longer installs it — the two PlatyPS + modules cannot be loaded into one process, so forcing the new one into every + session would break any consumer still holding the old one. Install it + yourself if you build help. `$PSBPreference.Docs.AlphabeticParamsOrder` is + removed, because PlatyPS 1.x always sorts parameters alphabetically and + offers no way back. Generated markdown carries the 1.x schema, though its + on-disk layout is unchanged. `Build-PSBuildUpdatableHelp` warns and returns + until the cabinet pipeline migrates in + [#152](https://github.com/psake/PowerShellBuild/issues/152); it could never + succeed in 0.8.x either, see + [#169](https://github.com/psake/PowerShellBuild/issues/169). See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md). + +- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) + **Breaking:** `Test-PSBuildScriptAnalysis` now counts PSScriptAnalyzer + `ParseError` records alongside `Error`. A file that does not parse at all + previously satisfied no threshold — not even the strictest validated value, + `Information` — so it was reported and the build passed anyway. It now fails + every threshold except `None`. See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build that + passed before may now correctly fail. + +- [**#120**](https://github.com/psake/PowerShellBuild/issues/120) + **Breaking:** the module manifest now requires PowerShell 5.1 or newer + (`PowerShellVersion = '5.1'`, previously `'3.0'`) and declares + `CompatiblePSEditions = @('Desktop', 'Core')`. The support floor is + Windows PowerShell 5.1 or PowerShell 7.4+ (CI runs Windows PowerShell + 5.1 and the runners' current PowerShell 7 release). See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) for + details. + +### Added + +- [**#144**](https://github.com/psake/PowerShellBuild/issues/144) + `Test-PSBuildScriptAnalysis` accepts `Any` as a `SeverityThreshold`, failing + the build on any diagnostic record regardless of severity. `Any` was already + documented in `build.properties.ps1` but was missing from the parameter's + `ValidateSet`, so setting + `$PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Any'` failed + parameter binding instead of working as documented. + +### Fixed + +- [**#147**](https://github.com/psake/PowerShellBuild/issues/147) + `Test-PSBuildScriptAnalysis` retries the analysis when a PSScriptAnalyzer rule + crashes on an internal race + ([PSScriptAnalyzer#1538](https://github.com/PowerShell/PSScriptAnalyzer/issues/1538)), + which is unrelated to the code being analyzed and succeeds on a re-run. + Consumers who set `$ErrorActionPreference = 'Stop'` — common in a build script — + previously got a randomly red build. A crash that survives every attempt is + still surfaced, so a persistent failure behaves as it did before. + +- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) + `Test-PSBuildScriptAnalysis` now fails the build when PSScriptAnalyzer + reports findings at or above the configured severity threshold. The + severity counts were computed from `$_Severity` — an undefined variable — + instead of `$_.Severity`, so all three counts were always zero and the + `Error`, `Warning`, and `Information` thresholds could never fail a build. + Script analysis reported its findings and the build passed regardless. + Because the default `FailBuildOnSeverityLevel` is `Error`, any consumer + running the `Analyze` task had a gate that only ever looked like it was + working. See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md) — a build + that passed before may now correctly fail. +- [**#96**](https://github.com/psake/PowerShellBuild/issues/96) + `Test-PSBuildScriptAnalysis` no longer fails with a path-resolution error + when `SettingsPath` is not supplied. An unsupplied path was forwarded to + PSScriptAnalyzer as `-Settings ''`, which resolved against the current + directory and threw before any analysis ran, so the function's own + documented example could not run as written. +- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) + `Test-PSBuildPester` no longer raises a parameter-binding error from its + cleanup logic when the optional `ModuleName` parameter is not supplied. +- [**#102**](https://github.com/psake/PowerShellBuild/issues/102) + `Test-PSBuildPester` now respects a Pester module that is already loaded in + the session instead of unconditionally importing the newest installed + version on top of it, which crashed with a Pester.dll version conflict when + two Pester versions were installed side by side. When no Pester is loaded, + the newest installed version (5.0.0 minimum) is imported as before, and a + loaded Pester older than 5.0.0 now produces a clear error. +- [**#138**](https://github.com/psake/PowerShellBuild/issues/138) + `Test-PSBuildPester` now reports real code coverage percentages and compares + them against `CodeCoverageThreshold` correctly. Each percentage was passed + through `[Math]::Truncate`, which collapses any fraction to zero, so the + coverage report always printed `0.00%` (or `100.00%`) and every threshold + above zero failed the build unless coverage was exactly 100%. Consumers who + set `$PSBPreference.Test.CodeCoverage.Threshold` could not use coverage + gating at all. The comparison is now strictly more permissive than before, + so a build that passed with a coverage threshold set still passes. + +## [0.8.2] 2026-07-08 + +### Fixed + +- [**#133**](https://github.com/psake/PowerShellBuild/pull/133) + `Test-PSBuildPester` now fails the build when a Pester run fails for any + reason, not only when individual tests fail. Previously the function gated + only on `FailedCount`, so a `BeforeAll`/`AfterAll` that threw or a test file + that errored during discovery left the count at zero and the build passed + despite tests never running. The gate now checks the run's aggregate + `Result` property, which Pester derives from all failure categories. + Companion to [#128](https://github.com/psake/PowerShellBuild/pull/128), + which fixes the same gap in this repository's own build file. + +## [0.8.1] 2026-06-03 + +### Fixed + +- Restore Windows PowerShell 5.1 (Desktop edition) compatibility, which regressed + in 0.8.0. `Get-PSBuildCertificate` used the PowerShell 7+-only ternary operator, + causing the file to fail to parse and the whole module to fail to import under + Windows PowerShell 5.1 — even though the manifest still declares support for it. + The ternary is replaced with an `if`/`else` expression, and the `$IsWindows` + platform guard now treats the absent automatic variable on Desktop edition as + Windows (matching the existing pattern in `Build-PSBuildUpdatableHelp`). Behavior + on PowerShell 7+ is unchanged. + +## [0.8.0] 2026-02-20 + +### Added + +- [**#92**](https://github.com/psake/PowerShellBuild/pull/92) Add Authenticode + code-signing support for PowerShell modules with three new public functions: + - `Get-PSBuildCertificate` - Resolves code-signing X509Certificate2 objects + from certificate store, PFX files, Base64-encoded environment variables, + or pre-resolved certificate objects + - `Invoke-PSBuildModuleSigning` - Signs PowerShell module files (*.psd1, + *.psm1, *.ps1) with Authenticode signatures supporting configurable + timestamp servers and hash algorithms + - `New-PSBuildFileCatalog` - Creates Windows catalog (.cat) files for + tamper detection +- New build tasks for module signing pipeline: `SignModule`, `BuildCatalog`, + `SignCatalog`, `Sign` (meta-task) +- Extended `$PSBPreference.Sign` configuration section with certificate + source selection, timestamp server configuration, hash algorithm options, + and catalog generation settings + +### Fixed + +- Remove extra backticks during localization text migration. + +## [0.7.3] 2025-08-01 + +### Added + +- Add new dependencies variables to allow end user to modify which tasks are + run. +- Add localization support. + +## [0.7.2] 2025-05-21 + +### Added + +- The `$PSBPreference` variable now supports the following PlatyPS + `New-MarkdownHelp` and `Update-MarkdownHelp` boolean options: + - `$PSBPreference.Docs.AlphabeticParamsOrder` + - `$PSBPreference.Docs.ExcludeDontShow` + - `$PSBPreference.Docs.UseFullTypeName` +- The `$PSBPreference` variable now supports the following Pester test + configuration options: + - `$PSBPreference.Test.SkipRemainingOnFailure` can be set to **None**, + **Run**, **Container** and **Block**. The default value is **None**. + - `$PSBPreference.Test.OutputVerbosity` can be set to **None**, **Normal**, + **Detailed**, and **Diagnostic**. The default value is **Detailed**. + +## [0.7.1] 2025-04-01 + +### Fixes + +- Fix a bug in `Build-PSBuildMarkdown` where a hashtable item was added twice. + +## [0.7.0] 2025-03-31 + +### Changed + +- [**#71**](https://github.com/psake/PowerShellBuild/pull/71) Compiled modules + are now explicitly created as UTF-8 files. +- [**#67**](https://github.com/psake/PowerShellBuild/pull/67) You can now + overwrite existing markdown files using `$PSBPreference.Docs.Overwrite` and + setting it to `$true`. +- [**#72**](https://github.com/psake/PowerShellBuild/pull/72) Loosen + dependencies by allowing them to be overwritten with + `$PSBPreference.TaskDependencies`. + +## [0.6.2] 2024-10-06 + +### Changed + +- Bump Pester to latest 5.6.1 + +### Fixed + +- [**#52**](https://github.com/psake/PowerShellBuild/pull/52) Pester object + wasn't being passed back after running tests, causing the Pester task to never + fail (via [@webtroter](https://github.com/webtroter)) +- [**#55**](https://github.com/psake/PowerShellBuild/pull/55) Add `-Module` + parameter to `Build-PSBuildUpdatableHelp` (via + [@IMJLA](https://github.com/IMJLA)) +- [**#60**](https://github.com/psake/PowerShellBuild/pull/60) Fix Windows + PowerShell compatibility in `Initialize-PSBuild` (via + [@joshooaj](https://github.com/joshooaj)) +- [**#62**](https://github.com/psake/PowerShellBuild/pull/62) Fix code coverage + output fle format not working (via + [@OpsM0nkey](https://github.com/OpsM0nkey)) + +## [0.6.1] 2021-03-14 + +### Fixed + +- Fixed bug in IB task `GenerateMarkdown` when dot sourcing precondition + +## [0.6.0] 2021-03-14 + +### Changed + +- [**#50**](https://github.com/psake/PowerShellBuild/pull/50) Invoke-Build tasks + brought inline with psake equivalents (via + [@JustinGrote](https://github.com/JustinGrote)) + +## [0.5.0] 2021-02-27 + +### Added + +- New code coverage parameters for setting output path and format: + - `$PSBPreference.Test.CodeCoverage.OutputFile` - Output file path for code + coverage results + - `$PSBPreference.Test.CodeCoverage.OutputFileFormat` - Code coverage output + format + +## [0.5.0] (beta1) - 2020-11-15 + +### Added + +- When "compiling" a monolithic PSM1, add support for both inserting + headers/footers for the entire PSM1, and for each script file. Control these + via the following new build parameters (via + [@pauby](https://github.com/pauby)) + - `$PSBPreference.Build.CompileHeader` + - `$PSBPreference.Build.CompileFooter` + - `$PSBPreference.Build.CompileScriptHeader` + - `$PSBPreference.Build.CompileScriptFooter` + +- Add ability to import project module from output directory prior to executing + Pester tests. Toggle this with `$PSBPreference.Test.ImportModule`. Defaults to + `$false`. (via [@joeypiccola](https://github.com/joeypiccola)) + +- Use `$PSBPreference.Build.CompileDirectories` to control directories who's + contents will be concatenated into the PSM1 when + `$PSBPreference.Build.CompileModule` is `$true`. Defaults to + `@('Enum', 'Classes', 'Private', 'Public')`. +- Use `$PSBPreference.Build.CopyDirectories` to control directories that will be + copied "as is" into the built module. Default is an empty array. + +### Changed + +- `$PSBPreference.Build.Exclude` now should be a list of regex expressions when + `$PSBPreference.Build.CompileModule` is `$false` (default). + +- Use Pester v5 + +### Fixed + +- Overriding `$PSBPreference.Build.OutDir` now correctly determines the final + module output directory. `$PSBPreference.Build.ModuleOutDir` is now computed + internally and **SHOULD NOT BE SET DIRECTLY**. `$PSBPreference.Build.OutDir` + will accept both relative and fully-qualified paths. + +- Before, when `$PSBPreference.Build.CompileModule` was set to `$true`, any + files listed in `$PSBPreference.Build.Exclude` weren't being excluded like + they should have been. Now, when it is `$true`, files matching regex + expressions in `$PSBPreference.Build.Exclude` will be properly excluded (via + [@pauby](https://github.com/pauby)) + +- `$PSBPreference.Help.DefaultLocale` now defaults to `en-US` on Linux since it + is not correctly determined with `Get-UICulture`. + +## [0.4.0] - 2019-08-31 + +### Changed + +- Allow using both `Credential` and `ApiKey` when publishing a module (via + [@pauby](https://github.com/pauby)) + +### Fixed + +- Don't overwrite Pester parameters when specifying `OutputPath` or + `OutputFormat` (via [@ChrisLGardner](https://github.com/ChrisLGardner)) + +## [0.3.1] - 2019-06-09 + +### Fixed + +- Don't create module page MD file. + +## [0.3.0] - 2019-04-23 + +### Fixed + +- [**#24**](https://github.com/psake/PowerShellBuild/pull/24) Fix case of + 'Public' folder when dot sourcing functions in PSM1 (via + [@pauby](https://github.com/pauby)) + +### Breaking changes + +- Refactor build properties into a single hashtable `$PSBPreference` + +### Changed + +- [**#11**](https://github.com/psake/PowerShellBuild/pull/11) The Invoke-Build + tasks are now auto-generated from the psake tasks via a converter script (via + [@JustinGrote](https://github.com/JustinGrote)) + +- [**#19**](https://github.com/psake/PowerShellBuild/pull/19) Allow the + `BHBuildOutput` environment variable defined by `BuildHelpers` to be set via + the `$PSBPreference.Build.ModuleOutDir` property of the build tasks (via + [@pauby](https://github.com/pauby)) + +## [0.2.0] - 2018-11-15 + +### Added + +- Add `Publish` task to publish the module to the defined PowerShell Repository + (PSGallery by default). + +## [0.1.1] - 2018-11-09 + +### Fixed + +- [**#4**](https://github.com/psake/PowerShellBuild/pull/4) Fix syntax for + `Analyze` task in `IB.tasks.ps1` (via + [@nightroman](https://github.com/nightroman)) + +## [0.1.0] - 2018-11-07 + +### Added + +- Initial commit + + From 2ec2ea1104146e69920ca49714e2fb28f0b5c417 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Mon, 24 Aug 2026 17:09:26 -0400 Subject: [PATCH 3/3] fix: Pin the MAML file name through front matter, not a post-export rename PlatyPS 1.x names the MAML file after the document's "external help file" front matter key, which it defaults to "-Help.xml" where 0.14.x wrote "-help.xml". The previous commit corrected the casing by renaming the file after export, which fixed the name and left the markdown still claiming the other one. That disagreement is the exact condition upstream punishes: PowerShell/platyPS#797 was closed as expected behavior with "You need to be consistent with the name you use in .EXTERNALHELPFILE", because inconsistent names across a batch cause files to be silently skipped or truncated. Build-PSBuildMarkdown now sets the key explicitly through -Metadata, so the markdown, the exported MAML file name, and any existing .ExternalHelp directive all agree, and the export step no longer renames anything. Verified: generated front matter reads "external help file: TestModule-help.xml" and the exported file matches. Suite: 460 passed, 0 failed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012AKaM9i6NyMFDcJNeC34h5 --- PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 | 9 ++++----- PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 | 13 ++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 index a1e9d67..79e754b 100644 --- a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 @@ -62,11 +62,10 @@ function Build-PSBuildMAMLHelp { } foreach ($file in $mamlFile) { - # PlatyPS 1.x capitalizes the suffix as "-Help.xml" where 0.14.x wrote - # "-help.xml". Preserving the old casing keeps existing .ExternalHelp - # directives resolving on case-sensitive file systems. - $destinationFileName = $file.Name -replace '-Help\.xml$', '-help.xml' - $destinationFilePath = Join-Path -Path $localeDestinationPath -ChildPath $destinationFileName + # The file name is whatever the document's "external help file" front matter + # says, which Build-PSBuildMarkdown pins to the 0.14.x casing. Renaming here + # instead would leave the markdown and the MAML disagreeing about the name. + $destinationFilePath = Join-Path -Path $localeDestinationPath -ChildPath $file.Name Move-Item -LiteralPath $file.FullName -Destination $destinationFilePath -Force } } finally { diff --git a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 index eddbeb9..0f44807 100644 --- a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 @@ -95,7 +95,18 @@ function Build-PSBuildMarkdown { ModuleInfo = $moduleInfo OutputFolder = $stagingPath Locale = $Locale - Verbose = $VerbosePreference + # PlatyPS 1.x defaults this front matter key to "-Help.xml", where + # 0.14.x wrote "-help.xml". The key is what Export-MamlCommandHelp + # names the MAML file after, so pinning it here keeps the markdown, the MAML + # file name, and any existing .ExternalHelp directive in agreement -- and + # keeps help resolving on case-sensitive file systems. Renaming after export + # would fix the file name while leaving the front matter disagreeing with it. + Metadata = @{ 'external help file' = "$ModuleName-help.xml" } + # Compared explicitly rather than passing $VerbosePreference through. The + # preference is an ActionPreference, and converting it to a switch uses the + # underlying number, so Stop and Inquire turn verbose output on even though + # neither asked for it. + Verbose = ($VerbosePreference -eq 'Continue') } if ($ExcludeDontShow) { $newMarkdownParams.ExcludeDontShow = $true