From a46824855b857c8f54fbe962f86522eddddaf75a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 14:14:02 +0200 Subject: [PATCH 1/7] docs: add .INPUTS and .OUTPUTS format rules to PS function help standards Document pipeline-input-only scope of .INPUTS, fully-qualified .NET type name convention for both sections, the 'None.' template when no pipeline input is accepted, per-type repetition of the keyword, and the PlatyPS single-line constraint. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Coding-Standards/PowerShell/Functions.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index 1f76f67..7c34c4f 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -88,3 +88,21 @@ Send each kind of message to the stream built for it, so a caller can capture, r ## Comment-based help (required) Every function carries comment-based help — including internal and private helpers, not only the public surface. It is what lets a reader or an agent understand what the function does and how to call it without reading its body, and a private helper needs that as much as a public command does. Put it first inside the body, with sections in this order: `.SYNOPSIS` (one imperative sentence), `.DESCRIPTION`, at least one `.EXAMPLE` per behaviour, then `.INPUTS`, `.OUTPUTS` (matching `[OutputType()]`), `.NOTES`, `.LINK`. Document each parameter with an inline comment above it rather than a `.PARAMETER` block, and let comments explain *why*, not *what*. + +### `.INPUTS` and `.OUTPUTS` + +**`.INPUTS`** documents **pipeline input only** — types accepted via `ValueFromPipeline` or `ValueFromPipelineByPropertyName` parameters. It does not document ordinary parameters. + +- When no parameters accept pipeline input: `None. You can't pipe objects to .` (use the actual command name). +- When pipeline input is accepted: `System.FullTypeName. Description of what is piped.` +- Use the fully-qualified .NET type name (`System.String`, `System.IO.FileInfo`), not a PowerShell type accelerator (`[string]`, `[fileinfo]`). +- Repeat the `.INPUTS` keyword once per accepted pipeline type when there are multiple. + +**`.OUTPUTS`** documents what the function emits to the output stream. + +- Format: `System.FullTypeName. Description of what is returned.` +- Use the fully-qualified .NET type name — same convention as `.INPUTS`. +- Repeat `.OUTPUTS` once per return type when the function can return multiple types. +- Must match `[OutputType()]`. + +> **PlatyPS note:** PlatyPS renders each line under `.INPUTS` / `.OUTPUTS` as a `###` heading in the generated Markdown — keep each entry to a single concise line. From a520b24e27de0f9995406ac51aaae2599d1f784b Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 14:29:19 +0200 Subject: [PATCH 2/7] docs: correct .INPUTS/.OUTPUTS format to two-line type + description PlatyPS renders the type name as a ### heading - putting type and description on one line causes trailing-period MD026 violations in generated docs. Canonical format: type name alone on first line, description indented on the next line. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Coding-Standards/PowerShell/Functions.md | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index 7c34c4f..148c2e8 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -93,16 +93,26 @@ Every function carries comment-based help — including internal and private hel **`.INPUTS`** documents **pipeline input only** — types accepted via `ValueFromPipeline` or `ValueFromPipelineByPropertyName` parameters. It does not document ordinary parameters. -- When no parameters accept pipeline input: `None. You can't pipe objects to .` (use the actual command name). -- When pipeline input is accepted: `System.FullTypeName. Description of what is piped.` -- Use the fully-qualified .NET type name (`System.String`, `System.IO.FileInfo`), not a PowerShell type accelerator (`[string]`, `[fileinfo]`). -- Repeat the `.INPUTS` keyword once per accepted pipeline type when there are multiple. +**`.OUTPUTS`** documents what the function emits to the output stream. Must match `[OutputType()]`. + +**Format:** type name alone on the first line, description indented on the next line. PlatyPS renders the type name as a `###` subheading and the description as body text below it — putting both on one line causes trailing-period heading violations in the generated Markdown. -**`.OUTPUTS`** documents what the function emits to the output stream. +```powershell +.INPUTS +None + You can't pipe objects to Get-Example. -- Format: `System.FullTypeName. Description of what is returned.` -- Use the fully-qualified .NET type name — same convention as `.INPUTS`. -- Repeat `.OUTPUTS` once per return type when the function can return multiple types. -- Must match `[OutputType()]`. +.INPUTS +System.String + The name of the user to look up. -> **PlatyPS note:** PlatyPS renders each line under `.INPUTS` / `.OUTPUTS` as a `###` heading in the generated Markdown — keep each entry to a single concise line. +.OUTPUTS +System.IO.FileInfo + The file object written to disk. +``` + +Rules that apply to both sections: + +- Use the fully-qualified .NET type name (`System.String`, `System.IO.FileInfo`), not a PowerShell type accelerator (`[string]`, `[fileinfo]`). +- When no parameters accept pipeline input, write `None` as the type with `You can't pipe objects to .` as the description (use the actual command name). +- Repeat the keyword once per type when multiple types are accepted or returned. From c344e13d7020f2a1585b5b563d252e082620847a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 14:54:29 +0200 Subject: [PATCH 3/7] docs: align Section structure example with .INPUTS/.OUTPUTS rules Update the Get-UserData snippet to use the two-line format, add the missing .INPUTS None block, and replace [PSCustomObject] with the fully-qualified System.Management.Automation.PSCustomObject type in both the comment-based help and [OutputType()]. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/docs/Coding-Standards/PowerShell/Functions.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index 148c2e8..e86a898 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -29,10 +29,15 @@ function Get-UserData { Get-UserData -UserId 'jdoe' Returns the record for the user 'jdoe'. + .INPUTS + None + You can't pipe objects to Get-UserData. + .OUTPUTS - [PSCustomObject] + System.Management.Automation.PSCustomObject + The user record for the requested id. #> - [OutputType([PSCustomObject])] + [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding()] param( # The unique identifier of the user. From f57d6e7f97233e212c612bdab8945ca48c32cb4f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 15:00:13 +0200 Subject: [PATCH 4/7] docs: correct .INPUTS/.OUTPUTS to canonical single-line format Official about_Comment_Based_Help and PowerShell/PowerShell source both use 'TypeName. Description.' on one line - not a two-line type/description split. Also revert [OutputType] to [PSCustomObject] (type literal, no full namespace needed in the attribute). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Coding-Standards/PowerShell/Functions.md | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index e86a898..3fbbf34 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -30,14 +30,12 @@ function Get-UserData { Returns the record for the user 'jdoe'. .INPUTS - None - You can't pipe objects to Get-UserData. + None. You can't pipe objects to Get-UserData. .OUTPUTS - System.Management.Automation.PSCustomObject - The user record for the requested id. + System.Management.Automation.PSCustomObject. The user record for the requested id. #> - [OutputType([System.Management.Automation.PSCustomObject])] + [OutputType([PSCustomObject])] [CmdletBinding()] param( # The unique identifier of the user. @@ -100,24 +98,21 @@ Every function carries comment-based help — including internal and private hel **`.OUTPUTS`** documents what the function emits to the output stream. Must match `[OutputType()]`. -**Format:** type name alone on the first line, description indented on the next line. PlatyPS renders the type name as a `###` subheading and the description as body text below it — putting both on one line causes trailing-period heading violations in the generated Markdown. +**Format:** type name, a period, a space, then the description — all on one line. This is the canonical format from [`about_Comment_Based_Help`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help) and matches how the PowerShell project itself writes these sections. Long descriptions wrap to the next line as a continuation. ```powershell .INPUTS -None - You can't pipe objects to Get-Example. +None. You can't pipe objects to Get-Example. .INPUTS -System.String - The name of the user to look up. +System.String. The name of the user to look up. .OUTPUTS -System.IO.FileInfo - The file object written to disk. +System.Management.Automation.PSCustomObject. The user record for the requested id. ``` Rules that apply to both sections: -- Use the fully-qualified .NET type name (`System.String`, `System.IO.FileInfo`), not a PowerShell type accelerator (`[string]`, `[fileinfo]`). -- When no parameters accept pipeline input, write `None` as the type with `You can't pipe objects to .` as the description (use the actual command name). +- Use the fully-qualified .NET type name (`System.String`, `System.Management.Automation.PSCustomObject`), not a PowerShell type accelerator (`[string]`, `[pscustomobject]`). +- When no parameters accept pipeline input, write `None. You can't pipe objects to .` (use the actual command name). - Repeat the keyword once per type when multiple types are accepted or returned. From ef67a6d94d687153be611ab9f38932f03c279990 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 15:04:06 +0200 Subject: [PATCH 5/7] docs: update .INPUTS/.OUTPUTS guidance based on PlatyPS v2 test results PlatyPS 1.0.3 renders the first line of each .INPUTS/.OUTPUTS entry as a ### heading. Single-line 'TypeName. Description.' creates trailing-period MD026 violations and puts a full sentence in a heading. Two-line with indented description renders the description as a code block (4 spaces). Correct format for PlatyPS-based modules: type name only, no period, no inline description. Description goes in the generated markdown file. Also note the divergence from about_Comment_Based_Help single-line examples which work fine in Get-Help but not PlatyPS. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Coding-Standards/PowerShell/Functions.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index 3fbbf34..ac37690 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -30,10 +30,10 @@ function Get-UserData { Returns the record for the user 'jdoe'. .INPUTS - None. You can't pipe objects to Get-UserData. + None .OUTPUTS - System.Management.Automation.PSCustomObject. The user record for the requested id. + System.Management.Automation.PSCustomObject #> [OutputType([PSCustomObject])] [CmdletBinding()] @@ -98,21 +98,23 @@ Every function carries comment-based help — including internal and private hel **`.OUTPUTS`** documents what the function emits to the output stream. Must match `[OutputType()]`. -**Format:** type name, a period, a space, then the description — all on one line. This is the canonical format from [`about_Comment_Based_Help`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help) and matches how the PowerShell project itself writes these sections. Long descriptions wrap to the next line as a continuation. +**Format for PlatyPS-generated docs:** put the type name alone on its own line — no period, no inline description. PlatyPS v2 (`Microsoft.PowerShell.PlatyPS`) renders the first line of each entry as a `###` heading in the generated Markdown; a trailing period or an inline description both end up inside that heading, violating MD026 and producing ugly output. The description belongs in the generated Markdown file, not the comment-based help. ```powershell .INPUTS -None. You can't pipe objects to Get-Example. +None .INPUTS -System.String. The name of the user to look up. +System.String .OUTPUTS -System.Management.Automation.PSCustomObject. The user record for the requested id. +System.Management.Automation.PSCustomObject ``` +> **Note:** The official `about_Comment_Based_Help` examples show `System.String. Description.` on one line — that format works fine in `Get-Help` output but produces poor Markdown when processed by PlatyPS v2. Follow the type-only format when your module uses PlatyPS for documentation. + Rules that apply to both sections: - Use the fully-qualified .NET type name (`System.String`, `System.Management.Automation.PSCustomObject`), not a PowerShell type accelerator (`[string]`, `[pscustomobject]`). -- When no parameters accept pipeline input, write `None. You can't pipe objects to .` (use the actual command name). +- When no parameters accept pipeline input, write `None` as the type. - Repeat the keyword once per type when multiple types are accepted or returned. From f31a62ff2bc738b4ca70cb05b378792507f38df5 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 15:23:19 +0200 Subject: [PATCH 6/7] docs: use blank-line format for .INPUTS/.OUTPUTS in source and example PlatyPS v2 test confirms: type on first line, blank line, description as paragraph produces the cleanest markdown (clean ### heading, body text below). Update both the guidance section and the Get-UserData example. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Coding-Standards/PowerShell/Functions.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/docs/Coding-Standards/PowerShell/Functions.md b/src/docs/Coding-Standards/PowerShell/Functions.md index ac37690..fccbeeb 100644 --- a/src/docs/Coding-Standards/PowerShell/Functions.md +++ b/src/docs/Coding-Standards/PowerShell/Functions.md @@ -32,8 +32,12 @@ function Get-UserData { .INPUTS None + You can't pipe objects to Get-UserData. + .OUTPUTS System.Management.Automation.PSCustomObject + + The user record for the requested UserId. #> [OutputType([PSCustomObject])] [CmdletBinding()] @@ -98,23 +102,29 @@ Every function carries comment-based help — including internal and private hel **`.OUTPUTS`** documents what the function emits to the output stream. Must match `[OutputType()]`. -**Format for PlatyPS-generated docs:** put the type name alone on its own line — no period, no inline description. PlatyPS v2 (`Microsoft.PowerShell.PlatyPS`) renders the first line of each entry as a `###` heading in the generated Markdown; a trailing period or an inline description both end up inside that heading, violating MD026 and producing ugly output. The description belongs in the generated Markdown file, not the comment-based help. +**Format for PlatyPS-generated docs:** type name on the first line, a blank line, then the description as a plain paragraph. PlatyPS v2 (`Microsoft.PowerShell.PlatyPS`) renders the first line as a `###` heading and the paragraph after the blank line as body text below it — producing clean, well-structured Markdown. Without the blank line, the description attaches directly below the heading with no separator; with 4-space indent it becomes a code block; with the type and description on the same line the entire sentence ends up inside the heading. ```powershell .INPUTS None +You can't pipe objects to Get-Example. + .INPUTS System.String +The name of the user to look up, piped in. + .OUTPUTS System.Management.Automation.PSCustomObject + +The user record for the requested id. ``` -> **Note:** The official `about_Comment_Based_Help` examples show `System.String. Description.` on one line — that format works fine in `Get-Help` output but produces poor Markdown when processed by PlatyPS v2. Follow the type-only format when your module uses PlatyPS for documentation. +> **Note:** The official `about_Comment_Based_Help` examples show `System.String. Description.` on one line — that format works in `Get-Help` output but causes MD026 violations and puts a full sentence inside a `###` heading when processed by PlatyPS v2. Use the blank-line format above for modules that use PlatyPS for documentation. Rules that apply to both sections: - Use the fully-qualified .NET type name (`System.String`, `System.Management.Automation.PSCustomObject`), not a PowerShell type accelerator (`[string]`, `[pscustomobject]`). -- When no parameters accept pipeline input, write `None` as the type. +- When no parameters accept pipeline input, write `None` as the type with `You can't pipe objects to .` as the description paragraph (use the actual command name). - Repeat the keyword once per type when multiple types are accepted or returned. From 158276d6f4bb1c5beae81817867f18dec0fa9cbc Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 25 Jul 2026 15:26:20 +0200 Subject: [PATCH 7/7] docs: add .INPUTS/.OUTPUTS example to script section structure Show the blank-line format in the Rotate-Secret.ps1 code example, aligning Scripts with the Functions guidance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/docs/Coding-Standards/PowerShell/Scripts.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/docs/Coding-Standards/PowerShell/Scripts.md b/src/docs/Coding-Standards/PowerShell/Scripts.md index e4c0ce2..a74993a 100644 --- a/src/docs/Coding-Standards/PowerShell/Scripts.md +++ b/src/docs/Coding-Standards/PowerShell/Scripts.md @@ -30,6 +30,16 @@ A script file is laid out top to bottom in this order: .EXAMPLE ./Rotate-Secret.ps1 -ValidityDays 365 + + .INPUTS + None + + You can't pipe objects to Rotate-Secret.ps1. + + .OUTPUTS + None + + This script produces no output — it operates by side effect. #> [CmdletBinding(SupportsShouldProcess)] param(