Skip to content

Commit adbba6b

Browse files
authored
Merge pull request #15 from AsBuiltReport/dev
v0.1.3 public release
2 parents bc981af + 8894a48 commit adbba6b

56 files changed

Lines changed: 1061 additions & 423 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Copilot Instructions
2+
3+
## Project Overview
4+
5+
This is **AsBuiltReport.System.Resources**, a PowerShell module for the [AsBuiltReport](https://github.com/AsBuiltReport) framework. It generates "As-Built" documentation reports (HTML, Word, Text) describing system resources (date/time, timezone, uptime, PowerShell host info, and top CPU processes) from a local or remote machine.
6+
7+
## Lint & Validation Commands
8+
9+
```powershell
10+
# Validate the module manifest
11+
Test-ModuleManifest .\AsBuiltReport.System.Resources\AsBuiltReport.System.Resources.psd1
12+
13+
# Run PSScriptAnalyzer with project settings
14+
Invoke-ScriptAnalyzer -Path .\AsBuiltReport.System.Resources\Src -Settings .\.github\workflows\PSScriptAnalyzerSettings.psd1 -Recurse
15+
16+
# Run PSScriptAnalyzer on a single file
17+
Invoke-ScriptAnalyzer -Path .\AsBuiltReport.System.Resources\Src\Private\Get-AbrDate.ps1 -Settings .\.github\workflows\PSScriptAnalyzerSettings.psd1
18+
```
19+
20+
No automated test suite exists. PSScriptAnalyzer linting is the CI quality gate, enforced via `.github/workflows/PSScriptAnalyzer.yml` on every push and PR.
21+
22+
## Generating a Report (Manual Testing)
23+
24+
```powershell
25+
# Install prerequisites
26+
Install-Module AsBuiltReport.Core, AsBuiltReport.Chart, AsBuiltReport.Diagram -Force
27+
28+
# Generate a report against localhost
29+
New-AsBuiltReport -Report System.Resources -Target localhost -Format Html -OutputFolderPath C:\Reports -Verbose
30+
31+
# Generate a default config file
32+
New-AsBuiltReportConfig -Report System.Resources -FolderPath C:\Config
33+
```
34+
35+
## Architecture
36+
37+
### Entry Point Flow
38+
39+
```
40+
New-AsBuiltReport (AsBuiltReport.Core framework)
41+
└─ Invoke-AsBuiltReport.System.Resources [Src/Public/]
42+
└─ For each $Target:
43+
├─ Get-AbrDate
44+
├─ Get-AbrTimeZone
45+
├─ Get-AbrUptime
46+
│ └─ Get-SystemUptime (WMI fallback for PS 5.1)
47+
├─ Get-AbrPSHost
48+
└─ Get-AbrProcessInfo
49+
├─ Get-AbrProcessDiagram
50+
└─ Export-AbrDiagram
51+
```
52+
53+
### Module Loader
54+
55+
`AsBuiltReport.System.Resources.psm1` auto-discovers and dot-sources all `.ps1` files under `Src/Public/` and `Src/Private/`, then exports **both** public and private functions. Private functions must be exported because the AsBuiltReport.Core framework invokes them within its document script block scope.
56+
57+
### Framework-Injected Variables
58+
59+
The AsBuiltReport.Core framework injects these variables into module scope before execution — do not redefine them:
60+
61+
| Variable | Purpose |
62+
|---|---|
63+
| `$ReportConfig` | Parsed JSON configuration object |
64+
| `$InfoLevel` | Per-section detail level (0=disabled, 1=summary, 2=detailed) |
65+
| `$Options` | Feature flags (diagrams, themes, exports) |
66+
| `$Target` | Array of system names to document |
67+
| `$System` | Current target being iterated |
68+
| `$reportTranslate` | Localization string hashtable |
69+
| `$Report` | Report metadata (ShowTableCaptions, etc.) |
70+
71+
### Report Section Pattern
72+
73+
Every section in `Src/Private/` follows the same structure:
74+
75+
1. **Narrow localization scope**`$reportTranslate = $reportTranslate.GetAbr<Feature>`
76+
2. **Collect data** — use standard PowerShell cmdlets or WMI
77+
3. **Check InfoLevel** — wrap output in `if ($InfoLevel.<Section> -ge 1)` blocks
78+
4. **Render with PScribo** — use `Section`, `Table`, `Paragraph`, `Image` etc.
79+
80+
### PowerShell Edition Detection
81+
82+
Use `$PSVersionTable.PSEdition` to branch between PS 5.1 (Desktop) and PS 7+ (Core):
83+
84+
```powershell
85+
if ($PSVersionTable.PSEdition -eq 'Core') {
86+
# Use modern cmdlets (e.g., Get-Uptime)
87+
} else {
88+
# Use WMI / CIM (e.g., Get-SystemUptime helper)
89+
}
90+
```
91+
92+
## Key Conventions
93+
94+
### Naming
95+
96+
- **Private functions:** `Get-Abr<Feature>` (e.g., `Get-AbrDate`, `Get-AbrProcessInfo`)
97+
- **WMI/compatibility helpers:** `Get-System<Task>` (e.g., `Get-SystemUptime`)
98+
- **Public entry point:** `Invoke-AsBuiltReport.System.Resources`
99+
- One function per file; filename matches function name exactly.
100+
101+
### Table Data Pattern
102+
103+
Always build table rows as ordered hashtables promoted to `[PSCustomObject]`, using localized strings as keys:
104+
105+
```powershell
106+
$InObj = [Ordered]@{
107+
$($reportTranslate.Date) = $Date.ToString('yyyy-MM-dd')
108+
$($reportTranslate.Hour) = $Date.ToString('HH:mm:ss')
109+
}
110+
$SystemDateInfo += [PSCustomObject]$InObj
111+
```
112+
113+
### Table Rendering Pattern
114+
115+
Always set explicit `ColumnWidths` and conditionally add a caption:
116+
117+
```powershell
118+
$TableParams = @{
119+
Name = "Table Name"
120+
List = $true
121+
ColumnWidths = 40, 60
122+
}
123+
if ($Report.ShowTableCaptions) {
124+
$TableParams['Caption'] = "- $($TableParams.Name)"
125+
}
126+
$data | Table @TableParams
127+
```
128+
129+
### Localization
130+
131+
- Each language lives in `Language/<locale>/SystemResources.psd1` as a nested hashtable.
132+
- Narrow to the relevant subtable at the top of each function: `$reportTranslate = $reportTranslate.GetAbr<Feature>`
133+
- When adding new string keys, add them to **all 26+ language files** under `Language/`.
134+
135+
### Diagram Pipeline
136+
137+
Diagrams use Graphviz via `AsBuiltReport.Diagram`. The pipeline is always:
138+
1. `Get-AbrProcessDiagram` — builds the graph object
139+
2. `Export-AbrDiagram` — calls `New-Diagrammer`, embeds base64 in report, and optionally writes to disk
140+
141+
Diagram features are gated by `$Options.EnableDiagrams`.
142+
143+
### PSScriptAnalyzer Exclusions
144+
145+
The following rules are intentionally suppressed (see `.github/workflows/PSScriptAnalyzerSettings.psd1`):
146+
- `PSUseToExportFieldsInManifest`
147+
- `PSReviewUnusedParameter`
148+
- `PSUseDeclaredVarsMoreThanAssignments`
149+
- `PSAvoidGlobalVars`
150+
- `PSUseSingularNouns`
151+
- `PSAvoidUsingWriteHost`
152+
153+
Do not add `[SuppressMessage]` attributes for these — the settings file handles them globally.
154+
155+
### Code Style
156+
157+
- Indentation: **4 spaces** (no tabs)
158+
- Line length: **115 characters** max
159+
- Opening brace on same line; closing brace on its own line
160+
- PascalCase for all function and parameter names
161+
- Use correct PowerShell cmdlet casing (`Get-ChildItem`, not `get-childitem`)
162+
163+
## Branch & Release Strategy
164+
165+
- Feature branches merge into **`dev`** (never directly into `master`)
166+
- `master` is the release branch; a GitHub release publication triggers the CI pipeline to publish to PowerShell Gallery
167+
- Follow [Keep a Changelog](https://keepachangelog.com/) format for `CHANGELOG.md` entries

.github/workflows/Release.yml

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,61 @@
11
name: Publish PowerShell Module
22

33
on:
4-
release:
5-
types: [published]
4+
release:
5+
types: [published]
66

77
jobs:
8-
publish-to-gallery:
9-
runs-on: windows-latest
10-
steps:
11-
- uses: actions/checkout@v6
12-
- name: Set PSRepository to Trusted for PowerShell Gallery
13-
shell: pwsh
14-
run: |
15-
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
16-
- name: Install AsBuiltReport.Core module
17-
shell: pwsh
18-
run: |
19-
Install-Module -Name AsBuiltReport.Core -Repository PSGallery -Force
20-
- name: Install AsBuiltReport.Chart module
21-
shell: pwsh
22-
run: |
23-
Install-Module -Name AsBuiltReport.Chart -Repository PSGallery -Force
24-
- name: Install Diagrammer.Core module
25-
shell: pwsh
26-
run: |
27-
Install-Module -Name Diagrammer.Core -Repository PSGallery -Force
28-
- name: Test Module Manifest
29-
shell: pwsh
30-
run: |
31-
Test-ModuleManifest .\AsBuiltReport.System.Resources.psd1
32-
- name: Publish module to PowerShell Gallery
33-
shell: pwsh
34-
run: |
35-
Publish-Module -Path ./ -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose
36-
tweet:
37-
needs: publish-to-gallery
38-
runs-on: ubuntu-latest
39-
steps:
40-
- uses: Eomm/why-don-t-you-tweet@v2
41-
# We don't want to tweet if the repository is not a public one
42-
if: ${{ !github.event.repository.private }}
43-
with:
44-
# GitHub event payload
45-
# https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release
46-
tweet-message: "[New Release] ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}! Check out what's new! ${{ github.event.release.html_url }} #System #Resources #AsBuiltReport #PowerShell"
47-
env:
48-
TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
49-
TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
50-
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
51-
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
52-
bsky-post:
53-
needs: publish-to-gallery
54-
runs-on: ubuntu-latest
55-
steps:
56-
- uses: zentered/bluesky-post-action@v0.3.0
57-
with:
58-
post: "[New Release] ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}! Check out what's new! ${{ github.event.release.html_url }} #System #Resources #AsBuiltReport #PowerShell"
59-
env:
60-
BSKY_IDENTIFIER: ${{ secrets.BSKY_IDENTIFIER }}
61-
BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }}
8+
publish-to-gallery:
9+
runs-on: windows-latest
10+
steps:
11+
- uses: actions/checkout@v6
12+
- name: Set PSRepository to Trusted for PowerShell Gallery
13+
shell: pwsh
14+
run: |
15+
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
16+
- name: Install AsBuiltReport.Core module
17+
shell: pwsh
18+
run: |
19+
Install-Module -Name AsBuiltReport.Core -Repository PSGallery -Force
20+
- name: Install AsBuiltReport.Chart module
21+
shell: pwsh
22+
run: |
23+
Install-Module -Name AsBuiltReport.Chart -Repository PSGallery -Force
24+
- name: Install AsBuiltReport.Diagram module
25+
shell: pwsh
26+
run: |
27+
Install-Module -Name AsBuiltReport.Diagram -Repository PSGallery -Force
28+
- name: Test Module Manifest
29+
shell: pwsh
30+
run: |
31+
Test-ModuleManifest .\AsBuiltReport.System.Resources\AsBuiltReport.System.Resources.psd1
32+
- name: Publish module to PowerShell Gallery
33+
shell: pwsh
34+
run: |
35+
Publish-Module -Path .\AsBuiltReport.System.Resources\ -NuGetApiKey ${{ secrets.PSGALLERY_API_KEY }} -Verbose
36+
tweet:
37+
needs: publish-to-gallery
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: Eomm/why-don-t-you-tweet@v2
41+
# We don't want to tweet if the repository is not a public one
42+
if: ${{ !github.event.repository.private }}
43+
with:
44+
# GitHub event payload
45+
# https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release
46+
tweet-message: "[New Release] ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}! Check out what's new! ${{ github.event.release.html_url }} #System #Resources #AsBuiltReport #PowerShell"
47+
env:
48+
TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
49+
TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
50+
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
51+
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
52+
bsky-post:
53+
needs: publish-to-gallery
54+
runs-on: ubuntu-latest
55+
steps:
56+
- uses: zentered/bluesky-post-action@v0.4.0
57+
with:
58+
post: "[New Release] ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}! Check out what's new! ${{ github.event.release.html_url }} #System #Resources #AsBuiltReport #PowerShell"
59+
env:
60+
BSKY_IDENTIFIER: ${{ secrets.BSKY_IDENTIFIER }}
61+
BSKY_PASSWORD: ${{ secrets.BSKY_PASSWORD }}

AsBuiltReport.System.Resources.psm1

Lines changed: 0 additions & 14 deletions
This file was deleted.

AsBuiltReport.System.Resources.Style.ps1 renamed to AsBuiltReport.System.Resources/AsBuiltReport.System.Resources.Style.ps1

File renamed without changes.

AsBuiltReport.System.Resources.json renamed to AsBuiltReport.System.Resources/AsBuiltReport.System.Resources.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@
3333
"PSHost": 2,
3434
"ProcessInfo": 1
3535
},
36-
"HealthCheck": {}
36+
"HealthCheck": {
37+
"Uptime": true
38+
}
3739
}

AsBuiltReport.System.Resources.psd1 renamed to AsBuiltReport.System.Resources/AsBuiltReport.System.Resources.psd1

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
RootModule = 'AsBuiltReport.System.Resources.psm1'
1313

1414
# Version number of this module.
15-
ModuleVersion = '0.1.2'
15+
ModuleVersion = '0.1.3'
1616

1717
# Supported PSEditions
1818
# CompatiblePSEditions = @()
@@ -59,11 +59,11 @@
5959
},
6060
@{
6161
ModuleName = 'AsBuiltReport.Chart';
62-
ModuleVersion = '0.2.0'
62+
ModuleVersion = '0.3.0'
6363
},
6464
@{
65-
ModuleName = 'Diagrammer.Core';
66-
ModuleVersion = '0.2.38'
65+
ModuleName = 'AsBuiltReport.Diagram';
66+
ModuleVersion = '1.0.5'
6767
}
6868
)
6969

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Module loader for AsBuiltReport.System.Resources
2+
#
3+
# This script is executed automatically by PowerShell when the module is imported. It uses a
4+
# common AsBuiltReport pattern of separating functions into two directories:
5+
#
6+
# Src/Public/ - Functions exported to the caller (visible after Import-Module).
7+
# Typically a single Invoke-AsBuiltReport.<ModuleName> entry point.
8+
# Src/Private/ - Internal helper functions used only within the module. They are dot-sourced
9+
# into the module scope but are also exported so that AsBuiltReport.Core can
10+
# call them from within the report document script block, which runs in the
11+
# caller's scope.
12+
#
13+
# Any file that fails to dot-source (e.g. due to a syntax error) will emit an error message
14+
# via Write-Error but will not prevent the remaining files from being loaded.
15+
16+
# Collect all public and private function files.
17+
$Public = @(Get-ChildItem -Path $PSScriptRoot\Src\Public\*.ps1 -ErrorAction SilentlyContinue)
18+
$Private = @(Get-ChildItem -Path $PSScriptRoot\Src\Private\*.ps1 -ErrorAction SilentlyContinue)
19+
20+
foreach ($Module in @($Public + $Private)) {
21+
try {
22+
. $Module.FullName
23+
} catch {
24+
Write-Error -Message "Failed to import function $($Module.FullName): $_"
25+
}
26+
}
27+
28+
# Export public functions by name so they are available to module consumers.
29+
Export-ModuleMember -Function $Public.BaseName
30+
# Export private functions so that AsBuiltReport.Core can invoke them from within the
31+
# PScribo document script block, which executes in the caller's session scope.
32+
Export-ModuleMember -Function $Private.BaseName

icons/AsBuiltReport_Logo.png renamed to AsBuiltReport.System.Resources/Icons/AsBuiltReport_Logo.png

File renamed without changes.

icons/AsBuiltReport_Signature.png renamed to AsBuiltReport.System.Resources/Icons/AsBuiltReport_Signature.png

File renamed without changes.

icons/Process.png renamed to AsBuiltReport.System.Resources/Icons/Process.png

File renamed without changes.

0 commit comments

Comments
 (0)