Skip to content

Commit 59e056c

Browse files
⚙️ [Maintenance]: PowerShell guidance scripts are centrally available (#508)
Maintainers can now find the published PowerShell guidance examples alongside Process-PSModule, giving the framework a single maintained home for the scripts that explain common implementation patterns. ## New: Published PowerShell guidance scripts The repository now carries the complete current set of guidance scripts for collections, strings, call stacks, pipeline execution, module loading, file access, and web calls. The published documentation includes the purpose of every script and links directly to the tracked directory. These are reference examples; run an individual script only when its scenario is appropriate for the local environment. --- <details> <summary>Technical details</summary> -Imported the 14 current `guidance/` Git blobs from `PSModule/docs` without changing their contents and verified every imported blob ID against the source repository. -Added a scoped `.gitattributes` rule so the imported source stays LF-normalized in Git on Windows checkouts. -Added the guidance-script reference page, Reference landing-page entry, and site navigation entry. `guidance/` remains outside `src/` because these scripts are framework reference assets, not Process-PSModule module source; no manifest wiring is required. -Implementation plan progress: source import and published discoverability are complete. -Issue convergence sweep: searched open guidance-related issues. `#423` is related documentation-consolidation context but is not fully satisfied by this import; no issue is closed. -Strict documentation validation exposes 28 pre-existing migrated-link warnings outside this diff; the normal build generates the new guidance page successfully. The bounded follow-up is `#509`. | Changed surface | Standards checked | Framework docs checked | Result | | --- | --- | --- | --- | | `guidance/**` (PowerShell) | PowerShell syntax parsing, source fidelity | Repository layout and module source layout | Aligned | | `docs/content/**`, `docs/zensical.toml` | Markdown structure and navigation | Documentation publishing | Aligned; strict baseline tracked in #509 | | `.gitattributes` | Repository text normalization | Repository standard | Aligned | </details> <details> <summary>Relevant issues (or links)</summary> -No scoped delivery issue was provided; this import was requested directly. -#423 -#509 </details> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 0e45a1c commit 59e056c

18 files changed

Lines changed: 847 additions & 0 deletions

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Needed for publishing of examples, build worker defaults to core.autocrlf=input.
22
* text eol=autocrlf
33

4+
# Preserve the published guidance scripts' upstream LF representation.
5+
guidance/* text eol=lf
6+
47
*.mof text eol=crlf
58
*.sh text eol=lf
69
*.svg eol=lf

docs/content/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Look up the framework's exact contracts and the module-development standards it
6363
| [Scenario matrix](reference/scenario-matrix.md) | Which jobs run for each trigger scenario. |
6464
| [Framework test IDs](reference/framework-test-ids.md) | The framework tests enforced on source code and on the built module. |
6565
| [Dependencies](reference/dependencies.md) | The actions, modules, and services the workflow composes. |
66+
| [PowerShell guidance scripts](reference/guidance-scripts.md) | Runnable reference scripts for common PowerShell implementation patterns. |
6667

6768
## Specification
6869

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: PowerShell guidance scripts
3+
description: Reference PowerShell scripts that demonstrate implementation patterns used by the PSModule framework.
4+
---
5+
6+
# PowerShell guidance scripts
7+
8+
The [guidance directory](https://github.com/PSModule/Process-PSModule/tree/main/guidance) contains runnable reference scripts for common PowerShell implementation patterns. They are framework learning assets, not Process-PSModule module source, so they are intentionally kept outside `src/` and are not included in a module manifest.
9+
10+
Run an individual script only when its scenario is suitable for the local environment. Several scripts create temporary files, make web requests, or measure execution time.
11+
12+
| Script | Focus |
13+
| --- | --- |
14+
| `Add-Array.ps1` | Array and generic list population |
15+
| `Add-HashTable.ps1` | Hashtable population styles |
16+
| `Add-String.ps1` | String construction approaches |
17+
| `Caller.ps1` | Caller discovery through the PowerShell call stack |
18+
| `ClassExtension.ps1` | Class inheritance and base-method invocation |
19+
| `Loops.ps1` | Loop and function-call overhead |
20+
| `Out-Null.ps1` | Discarding command output |
21+
| `PipelineExecution.ps1` | Pipeline parameter evaluation and lifecycle blocks |
22+
| `PSCallStack.ps1` | Nested-call stack inspection |
23+
| `PSCmdlet.ps1` | The `$PSCmdlet` variable at nested call levels |
24+
| `PSModuleTest.psm1` | Module-component import and exports |
25+
| `Read-File.ps1` | File-reading approaches |
26+
| `root.ps1` | Nested PSScriptAnalyzer binary-module loading |
27+
| `WebCalls.ps1` | Web-request protocol comparisons |
28+
29+
## Maintenance
30+
31+
The files were imported byte-for-byte from [`PSModule/docs/guidance`](https://github.com/PSModule/docs/tree/main/guidance). When that published set changes, import the complete current file from its Git blob into this directory and preserve its contents. Keep this index synchronized with the directory so users can discover every available script.

docs/zensical.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ nav = [
4747
{"Scenario matrix" = "reference/scenario-matrix.md"},
4848
{"Framework test IDs" = "reference/framework-test-ids.md"},
4949
{"Dependencies" = "reference/dependencies.md"},
50+
{"PowerShell guidance scripts" = "reference/guidance-scripts.md"},
5051
]},
5152
{"Specification" = [
5253
"specification/index.md",

guidance/Add-Array.ps1

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
$tests = @{
2+
'PowerShell Explicit Assignment' = {
3+
param($count)
4+
5+
$result = foreach ($i in 1..$count) {
6+
$i
7+
}
8+
$null = $result # just added for linter issues
9+
}
10+
'.Add(..) to List<T>' = {
11+
param($count)
12+
13+
$result = [Collections.Generic.List[int]]::new()
14+
foreach ($i in 1..$count) {
15+
$result.Add($i)
16+
}
17+
}
18+
'+= Operator to Array' = {
19+
param($count)
20+
21+
$result = @()
22+
foreach ($i in 1..$count) {
23+
$result += $i
24+
}
25+
}
26+
}
27+
28+
5kb, 10kb, 100kb | ForEach-Object {
29+
$groupResult = foreach ($test in $tests.GetEnumerator()) {
30+
$ms = (Measure-Command { & $test.Value -Count $_ }).TotalMilliseconds
31+
32+
[pscustomobject]@{
33+
CollectionSize = $_
34+
Test = $test.Key
35+
TotalMilliseconds = [math]::Round($ms, 2)
36+
}
37+
38+
[GC]::Collect()
39+
[GC]::WaitForPendingFinalizers()
40+
}
41+
42+
$groupResult = $groupResult | Sort-Object TotalMilliseconds
43+
$groupResult | Select-Object *, @{
44+
Name = 'RelativeSpeed'
45+
Expression = {
46+
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
47+
[math]::Round($relativeSpeed, 2).ToString() + 'x'
48+
}
49+
}
50+
}

guidance/Add-HashTable.ps1

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Adding 10000 items property-style
2+
Measure-Command {
3+
$HashProp = @{}
4+
1..10000 | ForEach-Object { $HashProp.$_ = $_ }
5+
}
6+
7+
# Adding 10000 items using the Add method
8+
Measure-Command {
9+
$HashMethod = @{}
10+
1..10000 | ForEach-Object { $HashMethod.Add($_, $_) }
11+
}
12+
13+
# Adding 10000 items dictionary-style
14+
Measure-Command {
15+
$HashDict = @{}
16+
1..10000 | ForEach-Object { $HashDict[$_] = $_ }
17+
}

guidance/Add-String.ps1

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
$tests = @{
2+
'StringBuilder' = {
3+
$sb = [System.Text.StringBuilder]::new()
4+
foreach ($i in 0..$args[0]) {
5+
$sb = $sb.AppendLine("Iteration $i")
6+
}
7+
$sb.ToString()
8+
}
9+
'Join operator' = {
10+
$string = @(
11+
foreach ($i in 0..$args[0]) {
12+
"Iteration $i"
13+
}
14+
) -join "`n"
15+
$string
16+
}
17+
'Addition Assignment +=' = {
18+
$string = ''
19+
foreach ($i in 0..$args[0]) {
20+
$string += "Iteration $i`n"
21+
}
22+
$string
23+
}
24+
}
25+
26+
10kb, 50kb, 100kb | ForEach-Object {
27+
$groupResult = foreach ($test in $tests.GetEnumerator()) {
28+
$ms = (Measure-Command { & $test.Value $_ }).TotalMilliseconds
29+
30+
[pscustomobject]@{
31+
Iterations = $_
32+
Test = $test.Key
33+
TotalMilliseconds = [math]::Round($ms, 2)
34+
}
35+
36+
[GC]::Collect()
37+
[GC]::WaitForPendingFinalizers()
38+
}
39+
40+
$groupResult = $groupResult | Sort-Object TotalMilliseconds
41+
$groupResult | Select-Object *, @{
42+
Name = 'RelativeSpeed'
43+
Expression = {
44+
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
45+
[math]::Round($relativeSpeed, 2).ToString() + 'x'
46+
}
47+
}
48+
}

guidance/Caller.ps1

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
function Invoke-Function4 {
2+
<#
3+
.SYNOPSIS
4+
Demonstrates caller detection using Get-PSCallStack.
5+
#>
6+
[CmdletBinding()]
7+
param()
8+
'In: ' + $MyInvocation.InvocationName
9+
$caller = (Get-PSCallStack)[1].Command
10+
'Caller: ' + $caller
11+
}
12+
13+
function Invoke-Function3 {
14+
<#
15+
.SYNOPSIS
16+
Demonstrates nested caller detection at depth 3.
17+
#>
18+
[CmdletBinding()]
19+
param()
20+
'In: ' + $MyInvocation.InvocationName
21+
$caller = (Get-PSCallStack)[1].Command
22+
'Caller: ' + $caller
23+
Invoke-Function4
24+
}
25+
26+
function Invoke-Function2 {
27+
<#
28+
.SYNOPSIS
29+
Demonstrates nested caller detection at depth 2.
30+
#>
31+
[CmdletBinding()]
32+
param()
33+
'In: ' + $MyInvocation.InvocationName
34+
$caller = (Get-PSCallStack)[1].Command
35+
'Caller: ' + $caller
36+
Invoke-Function3
37+
}
38+
39+
function Invoke-Function1 {
40+
<#
41+
.SYNOPSIS
42+
Entry point demonstrating caller detection through the call stack.
43+
#>
44+
[CmdletBinding()]
45+
param()
46+
'In: ' + $MyInvocation.InvocationName
47+
Get-PSCallStack
48+
$caller = (Get-PSCallStack)[1].Command
49+
'Caller: ' + $caller
50+
Invoke-Function2
51+
}
52+
53+
# Test the functions
54+
Invoke-Function1

guidance/ClassExtension.ps1

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
class C {
2+
[string]$Name
3+
4+
C([string]$Name) {
5+
$this.Name = $Name
6+
}
7+
8+
[string]GetInfo() {
9+
return "Name: $($this.Name)"
10+
}
11+
}
12+
13+
class B : C {
14+
[int]$Age
15+
16+
B([string]$Name, [int]$Age) : base($Name) {
17+
$this.Age = $Age
18+
}
19+
20+
[string]GetInfo() {
21+
# Cast $this to the parent class (C) to call its GetInfo()
22+
return "$(([C]$this).GetInfo()), Age: $($this.Age)"
23+
}
24+
}
25+
26+
class A : B {
27+
[string]$Role
28+
29+
A([string]$Name, [int]$Age, [string]$Role) : base($Name, $Age) {
30+
$this.Role = $Role
31+
}
32+
33+
[string]GetInfo() {
34+
# Cast $this to B to call B’s GetInfo(), which itself calls C’s GetInfo()
35+
return "$(([B]$this).GetInfo()), Role: $($this.Role)"
36+
}
37+
}
38+
39+
# Creating and testing an instance
40+
$person = [A]::new('John Doe', 30, 'Manager')
41+
$person.GetInfo()

guidance/Loops.ps1

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
$ranGen = New-Object System.Random
2+
$RepeatCount = 10000
3+
4+
'Basic for-loop = {0}ms' -f (Measure-Command -Expression {
5+
for ($i = 0; $i -lt $RepeatCount; $i++) {
6+
$Null = $ranGen.Next()
7+
}
8+
}).TotalMilliseconds
9+
10+
'Wrapped in a function = {0}ms' -f (Measure-Command -Expression {
11+
function Get-RandNum_Core {
12+
<#
13+
.SYNOPSIS
14+
Gets a random number using a shared Random instance.
15+
#>
16+
param ($ranGen)
17+
$ranGen.Next()
18+
}
19+
20+
for ($i = 0; $i -lt $RepeatCount; $i++) {
21+
$Null = Get-RandNum_Core $ranGen
22+
}
23+
}).TotalMilliseconds
24+
25+
'For-loop in a function = {0}ms' -f (Measure-Command -Expression {
26+
function Get-RandNum_All {
27+
<#
28+
.SYNOPSIS
29+
Gets random numbers in a loop using a shared Random instance.
30+
#>
31+
param ($ranGen)
32+
for ($i = 0; $i -lt $RepeatCount; $i++) {
33+
$Null = $ranGen.Next()
34+
}
35+
}
36+
37+
Get-RandNum_All $ranGen
38+
}).TotalMilliseconds

0 commit comments

Comments
 (0)