Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions .github/skills/document-powershell-functions/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
name: document-powershell-functions
description: 'Write or complete PowerShell comment-based help. Use when a module contains top-level functions with no help, undocumented parameters, or parameter sets without examples. Preserve complete help and existing documented segments; add only missing documentation and syntax-check each changed file.'
argument-hint: 'Optionally specify files, folders, or function names'
user-invocable: true
---

# Document PowerShell Functions

Create or complete comment-based help for PowerShell functions without rewriting documentation that already satisfies the requirements.

## Scope

- Process functions declared with the `function` keyword.
- Exclude functions nested inside another function.
- Respect any file, folder, module, or function scope supplied by the user.
- When no scope is supplied, inspect the current module or workspace surface relevant to the request.
- Change a function only when it has no comment-based help or when required coverage is missing.
- Leave a function's help unchanged when all required sections, parameters, and parameter sets are already documented.

## Required Help

Help created for a previously undocumented function contains only these sections:

- `.SYNOPSIS`: one sentence summarizing what the function does.
- `.DESCRIPTION`: the command's purpose, behavior, filtering or output details, and other facts a user needs.
- `.PARAMETER <Name>`: one entry for every declared parameter, explaining its use. Also generate help for `-WhatIf` and `-Confirm` if the command implements ShouldProcess.
- `.EXAMPLE`: at least one example for every parameter set. Put the command first, followed by a blank line and prose explaining what executing it does.

Do not add `.NOTES`, `.LINK`, `.INPUTS`, `.OUTPUTS`, or any other unrequested help section.

## Style

- Write for users of the command, not maintainers of its implementation.
- Keep the synopsis to one direct sentence.
- For Parameters listed in the help `Parameter Help Override` section below, do not invent your own help text and use the override text instead.
- Keep parameter descriptions concise. Do not narrate parameter-set selection unless that fact helps a user invoke the command correctly. Do not narrate whether it accepts input from the pipeline.
- Parameters that have a default value should explain this in a separate line with `Defaults to: {{value}}`. This does not apply to Switch parameters.
- Use concrete, realistic values in examples.
- Use `PS C:\>` as the example prompt.
- Explain the observable result of each example rather than merely repeating its syntax.
- Follow established wording for recurring parameters. For example, when most commands of a module use a `-ServiceMap`` parameter, prefer its existing documentation text and style over inventing a new variant.
- Match the indentation, line endings, spelling, terminology, and voice of nearby manually maintained help.

## Procedure

1. Inventory explicit `function` declarations in scope and identify nesting from the PowerShell AST or surrounding syntax.
2. Read each top-level function's current help, attributes, parameter block, parameter-set declarations, default parameter set, and behavior-controlling implementation.
3. Build a coverage list for each function:
- comment-based help is absent;
- `.SYNOPSIS` is absent or empty;
- `.DESCRIPTION` is absent or empty;
- a declared parameter has no matching `.PARAMETER` section or its section is empty;
- an explicitly assigned parameter default is not described;
- a parameter set has no `.EXAMPLE` that demonstrates a valid invocation and explains its result.
4. Skip functions whose coverage list is empty.
5. For a function with no help, add one complete help block containing only the required sections.
6. For partial help, make additive, localized changes only:
- preserve existing wording and formatting;
- add only missing or empty required sections;
- add only missing parameter documentation;
- add only examples needed for uncovered parameter sets;
- amend a parameter description only when needed to document a newly introduced explicit default;
- do not reorder, normalize, or rewrite already documented sections.
7. Place a new help block immediately beneath the line containing the `function` keyword and above attributes such as `[CmdletBinding()]` and the `param` block. Insert missing sections into an existing block without moving that block.
8. After completing all edits, run `.\tests\pester.ps1 -TestFunctions $false -Include Help*` to verify edits. A Test run without errors implies success. In case of error, use the test results to identify which functions' help needs fixing, fix the issue and test again.

## Parameter-Set Coverage

- Count named parameter sets declared through `ParameterSetName` and account for `DefaultParameterSetName`.
- Treat parameters without a `ParameterSetName` as common parameters available across sets.
- An example covers a set only when its arguments form a valid invocation of that set.
- A single example may cover only the set selected by its set-specific arguments. If it uses only common parameters and is ambiguous, count it for the default parameter set only.
- When no named parameter sets exist, require at least one example.

## Preservation Rules

- Never replace an entire existing help block merely to improve its prose.
- Never change a documented synopsis, description, parameter, or example unless it is empty, factually invalidated by the current function, or must be minimally amended to describe a new explicit default.
- Do not remove extra sections from pre-existing help during a coverage-only update; the instruction against extra sections applies to newly generated content.
- Do not document nested helper functions unless the user explicitly asks for them.
- Do not modify function behavior while documenting it.
- Do not change files that require no documentation additions.

## Parameter Help Override

When documenting the following parameters, always use the override text provided under the parameter's section, rather than inventing your own text.

### WhatIf

```text
If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
```

### Confirm

```text
If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
```

### Cmdlet

```text
The $PSCmdlet variable of the calling command, used to ensure errors and messages happen within the scope of the caller, hiding this internal helper command from the user.
```

### EnableException

```text
This parameters disables user-friendly warnings and enables the throwing of exceptions.
This is less user friendly, but allows catching exceptions in calling scripts.
```

## Syntax Validation

For each changed file, use the PowerShell parser and fail on parser errors. An equivalent validation is:

```powershell
$tokens = $null
$errors = $null
$null = [System.Management.Automation.Language.Parser]::ParseFile(
(Resolve-Path $file),
[ref] $tokens,
[ref] $errors
)

if ($errors.Count) {
$errors | ForEach-Object { Write-Error $_.Message }
throw "PowerShell syntax validation failed for $file"
}
```

Validation must run after the final edit of all updated files in scope.
Do not run validation earlz, before going through all files.
Do not claim syntax correctness based only on editor diagnostics or visual review.
5 changes: 4 additions & 1 deletion PSFramework/PSFramework.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
RootModule = 'PSFramework.psm1'

# Version number of this module.
ModuleVersion = '1.14.457'
ModuleVersion = '1.15.472'

# ID used to uniquely identify this module
GUID = '8028b914-132b-431f-baa9-94a6952f21ff'
Expand Down Expand Up @@ -42,6 +42,7 @@
'Clear-PSFMessage'
'Clear-PSFresultCache'
'Compare-PSFArray'

'ConvertFrom-PSFArray'
'ConvertFrom-PSFClixml'
'ConvertTo-PSFClixml'
Expand Down Expand Up @@ -170,8 +171,10 @@
'Test-PSFFeature'
'Test-PSFFilter'
'Test-PSFFunctionInterrupt'
'Test-PSFHashtableEquality'
'Test-PSFLanguageMode'
'Test-PSFParameterBinding'
'Test-PSFParameterSet'
'Test-PSFPowerShell'
'Test-PSFTaskEngineCache'
'Test-PSFTaskEngineTask'
Expand Down
Binary file modified PSFramework/bin/PSFramework.dll
Binary file not shown.
Binary file modified PSFramework/bin/PSFramework.pdb
Binary file not shown.
94 changes: 94 additions & 0 deletions PSFramework/bin/PSFramework.xml
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,21 @@
Enables adding empty keys for explicitly included keys that were not found on the input
</summary>
</member>
<member name="F:PSFramework.Commands.ConvertToPSFHashtableCommand.ExcludeNull">
<summary>
Exclude keys whose value is null
</summary>
</member>
<member name="F:PSFramework.Commands.ConvertToPSFHashtableCommand.ExcludeEmptyString">
<summary>
Exclude keys whose value is an empty string
</summary>
</member>
<member name="F:PSFramework.Commands.ConvertToPSFHashtableCommand.ExcludeEmptyCollection">
<summary>
Exclude keys whose value is an empty collection
</summary>
</member>
<member name="F:PSFramework.Commands.ConvertToPSFHashtableCommand.Inherit">
<summary>
Specifically designed for use in a command when passing through parameters with default values.
Expand Down Expand Up @@ -3524,6 +3539,41 @@
<param name="Instance">Instance of the Logging Provider with the issue</param>
<param name="ErrorRecord">The Issue</param>
</member>
<member name="T:PSFramework.Logging.FileSystemWriter">
<summary>
Helper class used by the FileSystem logging provider to write data at max performance
</summary>
</member>
<member name="P:PSFramework.Logging.FileSystemWriter.Path">
<summary>
The Path to where is written. Changing this recalculates converters and establishes a filestream
</summary>
</member>
<member name="P:PSFramework.Logging.FileSystemWriter.Size">
<summary>
Size of the logfile.
Defaults to 0 if file not present.
Used to determine file-split based on size.
</summary>
</member>
<member name="M:PSFramework.Logging.FileSystemWriter.WriteLine(System.String)">
<summary>
Writes a line to the logfile
</summary>
<param name="Line">The line of text to write</param>
</member>
<member name="M:PSFramework.Logging.FileSystemWriter.WriteObject(System.Management.Automation.PSObject)">
<summary>
Writes an object to the logfile.
Will convert it to csv first.
</summary>
<param name="Item">The item to write</param>
</member>
<member name="M:PSFramework.Logging.FileSystemWriter.End">
<summary>
Clean up both converter and writer
</summary>
</member>
<member name="T:PSFramework.Logging.LogFileFileType">
<summary>
The data format to log to in the logfile logging provider
Expand Down Expand Up @@ -3599,6 +3649,11 @@
Each logging provider has a name. Make sure it's unique
</summary>
</member>
<member name="F:PSFramework.Logging.Provider.Description">
<summary>
A description for the logging provider
</summary>
</member>
<member name="F:PSFramework.Logging.Provider.Enabled">
<summary>
Whether the logging provider is enabled. Only when this is set to true will the logging script execute its events.
Expand Down Expand Up @@ -8380,6 +8435,14 @@
Remove all content in the queue
</summary>
</member>
<member name="M:PSFramework.Runspace.RSQueue.ToArray(System.Boolean)">
<summary>
Get all contents as an Array.
Possibly also clearing it out afterwards.
</summary>
<param name="Clear">If true, clear after reading as one threadsafe operation.</param>
<returns>To content of the queued items</returns>
</member>
<member name="M:PSFramework.Runspace.RSQueue.Peek">
<summary>
Take a look without removing anything
Expand Down Expand Up @@ -12683,6 +12746,37 @@
<param name="Level">How many levels to go down the script callstack</param>
<returns>Metadata describing who called</returns>
</member>
<member name="M:PSFramework.Utility.UtilityHost.Compare(System.Collections.Hashtable,System.Collections.Hashtable)">
<summary>
Compare two hashtables.
Value comparison uses C#-based comparison logic.
</summary>
<param name="Table1">First Hashtable to compare</param>
<param name="Table2">Second Hashtable to compare</param>
<returns>Whether the two tables are equal</returns>
</member>
<member name="M:PSFramework.Utility.UtilityHost.ComparePS(System.Collections.Hashtable,System.Collections.Hashtable,System.Boolean,System.Boolean,System.Boolean)">
<summary>
Compare two hashtables.
Value comparison uses PowerShell-based comparison logic.
</summary>
<param name="Table1">First Hashtable to compare</param>
<param name="Table2">Second Hashtable to compare</param>
<param name="CaseSensitive">Whether the comparison is case sensitive</param>
<param name="Recurse">Whether to recursively compare nested hashtables</param>
<param name="OneDirectional">If enabled, all entries in Table1 must be present in Table2, but not necessarily all entries in Table2 in Table1</param>
<returns>Whether the two tables are equal</returns>
</member>
<member name="M:PSFramework.Utility.UtilityHost.TestParameterSetAny(System.Management.Automation.CommandInfo,System.String[],System.String[])">
<summary>
Checks, whether the specified parameters would resolve to one of the selected parameter sets.
Will return false, if the provided parameters would lead to an ambiguous parameter set, even if the specified sets would be among the still valid sets.
</summary>
<param name="Command">The command for the parameters of which the test should be performed.</param>
<param name="Parameters">The names of the parameters specified.</param>
<param name="Sets">The sets checked for. The resultant parameter set must be one of those specified.</param>
<returns>Whether the specified parameters would resolve to one of the selected parameter sets</returns>
</member>
<member name="F:PSFramework.Utility.UtilityHost.ScriptBlocks">
<summary>
Stored scriptblocks that can be retrieved on demand anywhere within the process
Expand Down
18 changes: 18 additions & 0 deletions PSFramework/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# CHANGELOG

## 1.15.472 (2026-10-23)

- New: Logging Provider: Azure LogAnalytics V2 - sends logs to Log Analytics via Data Collection Rule
- New: Test-PSFParameterSet - Tests, whether the command specified would resolve to the specified parameter set with the parameters provided.
- New: Test-PSFHashtableEquality - Compares hashtables on a per-entry (key and value) basis.
- Upd: Logging Provider FileSystem - Significantly improved performance of builtin default debug log.
- Upd: ConvertTo-PSFHashtable - added `-ExcludeNull` parameter, to remove keys whose value is $null
- Upd: ConvertTo-PSFHashtable - added `-ExcludeEmptyString` parameter, to remove keys whose value is an empty string
- Upd: ConvertTo-PSFHashtable - added `-ExcludeEmptyCollection` parameter, to remove keys whose value is an empty collection
- Upd: Register-PSFLoggingProvider - added `-Description` parameter.
- Upd: Logging Providers - updated the `Get-ConfigValue` command available to Logging Providers to support `-Fallback` parameter, defining a fallback value in case the provider setting is $null.
- Fix: Compare-PSFArray - fails to accept empty arrays
- Fix: Read-PSFRunspaceQueue - the `-Continual` parameter will wait and immediately close
- Fix: Read-PSFRunspaceQueue - the `-Continual` parameter will not wait correctly even with the previous issue fixed
- Fix: Read-PSFRunspaceQueue - rare concurrency issue when reading all data from a queue that might have lead to a lost item
- Fix: Invoke-PSFRunspace - specifying a function as scriptblock leads to an error
- Fix: Set-PSFLoggingProvider - tries to register a Logging Provider from config when it doesn't contain a Name.

## 1.14.457 (2026-07-02)

- New: ConfigValidation rstimeout - Validates input as a legal setting for the Runspace Workflow Worker's timeout
Expand Down
Loading