Skip to content

v0.5.0: Parallel execution, health reporting, and one-command install - #3

Merged
likeBloodMoon merged 4 commits into
mainfrom
claude/software-roadmap-powershell-enl3sh
Sep 30, 2026
Merged

likeBloodMoon merged 4 commits into
mainfrom
claude/software-roadmap-powershell-enl3sh

Conversation

@likeBloodMoon

Copy link
Copy Markdown
Owner

This release adds ~40 new commands, a performance-focused refactor of hot paths, and a one-command installer that works from the PowerShell Gallery.

Summary

PC Tools v0.5 is a major expansion: the module grows from ~30 commands to ~74, with new categories for health reporting, storage analysis, and system automation. The GUI gains a Dashboard page showing machine health at a glance. Performance is measured and optimized—network diagnostics that waited out timeouts serially now run concurrently.

Key Changes

New Commands (40+)

  • Health reporting: Get-PCHealthReport, Get-PCSecurityStatus, Get-PCBootPerformance, Get-PCEventSummary, Get-PCBatteryReport, Get-PCDiskHealth, Get-PCSystemInfo
  • Storage analysis: Get-PCDiskUsage, Get-PCDiskSpace, Optimize-PCVolume, Clear-PCWindowsOld, Clear-PCCrashDump, Clear-PCEventLog, Clear-PCDeliveryOptimization, Clear-PCThumbnailCache
  • Software management: Get-PCAppxPackage, Remove-PCAppxPackage, Get-PCWindowsUpdate, Install-PCWindowsUpdate, Update-PCApplication, Get-PCDriverIssue
  • Startup control: Get-PCStartupItem, Get-PCService, Disable-PCStartupItem, Enable-PCStartupItem, Set-PCServiceStartup
  • Automation: Get-PCHistory, Save-PCHistory, Register-PCScheduledMaintenance, Unregister-PCScheduledMaintenance, Get-PCScheduledMaintenance, Register-PCExtension, Get-PCExtension, Invoke-PCTools
  • Network: Test-PCDnsServer, Test-PCThroughput
  • Utilities: Get-PCResultSummary, Export-PCReport (expanded to HTML/CSV)

Performance Optimization

  • New Invoke-PCParallel function runs independent I/O-bound probes concurrently using runspace pools
  • Test-PCConnectivity and Test-PCRoute refactored to probe in parallel rather than serially
  • Test-PCMtu now sends payload probes concurrently instead of binary search
  • Invoke-PCProcess eliminates temp file overhead by reading pipes directly
  • Clear-PCFolderContent walks trees once instead of twice

Installation & Distribution

  • New install.ps1 bootstrapper: one command to install from Gallery or verified release archive
  • pctools command installed to %LOCALAPPDATA%\Microsoft\WindowsApps (no PATH edit needed)
  • GUI now ships inside the module; Start-PCTools command opens it
  • Shell script moved to src/PCTools/Shell/ and integrated with module lifecycle

GUI Enhancements

  • New Dashboard page showing health score and key findings
  • -Page parameter to open directly to a specific tab
  • Additional control references for new pages (HealthScore, FindingGrid, StorageGrid, etc.)

Build & Testing

  • New Measure-Performance.ps1 benchmark harness with baseline comparison
  • New test suites: Parallel.Tests.ps1, Safety.Tests.ps1, Extension.Tests.ps1, Install.Tests.ps1, Compile.Tests.ps1
  • Build tasks: Compile (merge sources to .psm1), Docs (generate COMMANDS.md), Bench (run benchmarks)
  • CI now validates compiled module is importable

Safety Guards

  • Remove-PCAppxPackage and Set-PCServiceStartup use allowlists, not blocklists
  • Get-PCCriticalServiceName prevents disabling load-bearing services
  • Extension model with file-based plugin loading

Documentation

  • New docs/COMMANDS.md: auto-generated command reference
  • New docs/PERFORMANCE.md: benchmark methodology and results

https://claude.ai/code/session_01KkdwqfkUYsNSkp9f3AVDqg

Three things this release delivers, against a v0.4 that had the right
architecture but the wrong ergonomics.

One command. The GUI shell moves from src/Shell into the module, so a
PowerShell Gallery install now carries the window as well as the commands -
previously the Gallery shipped the module only and the GUI needed a separate
archive download. install.ps1 is a bootstrapper pinned to a release tag that
prefers the signed Gallery package, falls back to a SHA256-verified release
archive with no way to skip the check, and installs a `pctools` command into a
directory already on PATH. Invoke-PCTools gives the same actions a scriptable
front door with real exit codes.

Measured performance. Nothing here had ever been measured, and the hot paths
were all the same mistake in different places: independent I/O performed one
item at a time. Nine connectivity probes ran in sequence, each waiting out its
own timeout; a traceroute walked up to twenty TTLs one at a time; every temp
directory was walked twice, once to size and once to delete. They now run
concurrently behind a single Invoke-PCParallel helper, and the shipped module
is compiled to one file. build/Measure-Performance.ps1 is the arbiter, and
docs/PERFORMANCE.md records both the numbers and what was deliberately not
done.

Thirty-five new commands: storage analysis, startup and service control,
health and security reporting, Windows Update and winget, scheduled
maintenance, run history, HTML reports and a drop-in extension model.

Safety held constant. Every mutating action still supports -WhatIf. The two
sharpest new commands are allowlist-driven with no -Force: Set-PCServiceStartup
refuses a fixed list of services whose loss breaks a machine, and
Remove-PCAppxPackage will only remove preinstalled apps on a curated list that
deliberately excludes the Store, App Installer, Photos, Calculator and every
framework package. Get-PCSecurityStatus reports posture and has no counterpart
that changes it.

Bugs found and fixed while building it:
- Get-PCResultSummary and Export-PCReport threw on an empty batch, because
  Measure-Object emits nothing for an empty collection and reading .Sum off
  nothing is a terminating error under strict mode. A network-only report
  reaching the HTML writer would have hit this.
- Invoke-PCProcess mangled any argument containing a quote. It now applies the
  escaping rules CommandLineToArgvW actually uses on Windows PowerShell 5.1.
- Save-PCHistory overwrote an entry when two runs finished in the same second.
- Assigning the result of an `if` unrolls a one-element array to a scalar, so
  .Count on it threw under strict mode - in four places, each on the common
  single-item path.
- Test-PCMtu used GetNewClosure(), which rebinds a scriptblock to a scope
  detached from the module's session state; the probe could not see the private
  helper it needed and every call failed.
- Passing a live scriptblock across a runspace boundary corrupts the caller's
  session state. Invoke-PCParallel marshals the body as text and recompiles it
  in the target runspace.

Tests: 713 assertions across ten suites, four of them new - Parallel, Safety,
Extension, Compile and Install. Compile.Tests asserts the compiled module
exports exactly what the source does, so the generated artifact cannot drift
from the code the tests ran against. The Test-PCMtu search was verified
exhaustively against all 1473 possible MTU values.

The release pipeline now signs the compiled module before packaging rather than
after, so the file users actually execute carries the signature, and publishes
that same compiled module to the Gallery.

ROADMAP.md is rewritten around v0.6 (trust: a real signing certificate, winget,
verifiable builds), v0.7 (fit) and v1.0 (a stable command surface), plus a set
of permanent non-goals: no telemetry, no unexplainable registry tweaks, no
memory "optimisation", no bulk service-disabling preset, no forced restarts,
and no silent changes to security settings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkdwqfkUYsNSkp9f3AVDqg

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0068a70e15

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/PCTools/Public/Start-PCTools.ps1 Outdated
Comment thread src/PCTools/Public/Automation/Register-PCScheduledMaintenance.ps1 Outdated
Comment thread src/PCTools/Private/Invoke-PCParallel.ps1
Comment thread .github/workflows/release.yml
Codex review and the first CI run between them found four real defects and
three stale assertions. All of them are in v0.5.0, which has not shipped.

Two bugs came from the same root cause: the source tree and the compiled
module nest functions at different depths, so any path built by walking up
from $PSScriptRoot is correct in one and wrong in the other.

- Start-PCTools resolved the GUI shell as "$PSScriptRoot\..\Shell". In the
  source tree the function lives in Public/ and that is right; in the compiled
  module $PSScriptRoot is already the module root, so it pointed at a sibling
  folder that does not exist. Every Gallery and archive install would have
  thrown "the shell is missing" - on the one command this release is named
  after. Verified against a simulated install: the old expression resolved a
  path that is not there, the new one resolves the shell.
- Register-PCScheduledMaintenance built its manifest path two parents up, which
  landed outside the versioned module folder and fell back to Import-Module by
  name. A scheduled task runs as SYSTEM, whose module path does not include a
  CurrentUser install, so every task registered from a normal install would
  have failed before running its profile.

Both now read $ExecutionContext.SessionState.Module.ModuleBase, which is the
module root in either layout, and a test asserts neither file goes back to
depending on its own nesting depth.

- Invoke-PCParallel discarded results that had already completed once the batch
  deadline passed. The tasks run concurrently, so a slow item early in the list
  could burn the whole budget while every later item had finished - and those
  finished results were then reported as timeouts. Test-PCConnectivity is where
  this would have bitten: the gateway probe is both first and the likeliest to
  hang. Completion is now checked before the budget. The new test fails against
  the old logic and passes against the fix.
- The release notes named pc-tools-v0.5.0.zip; the build stages the archive
  without the tag's leading v, so the documented verification step named a file
  that is not attached.

CI:
- docs/COMMANDS.md was written with Set-Content -Encoding UTF8, which emits a
  BOM on Windows PowerShell 5.1 and none on PowerShell 7. The generated file
  therefore differed by three bytes depending on who ran the task, which is
  what the freshness check reported as stale. It is now written as UTF-8
  without a BOM, with LF endings, identically on every host.
- Three assertions had gone stale against my own changes: two expected error
  text I had deliberately improved or profile lists I had added to, and the
  third - in Install.Tests - had the very array-unwrapping bug this release
  fixes in the module code, where a single regex match assigns a scalar and
  .Count on it throws under strict mode.

Local verification: 718 assertions across ten suites, 0 failures; analyzer
clean at 197 warnings against a 210 budget; the Docs task is now idempotent,
the release stages, and the compiled module is still byte-reproducible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkdwqfkUYsNSkp9f3AVDqg
CI on c5f9a8f was down to one failure, and it was a real bug rather than a
stale assertion: Import-PCConfiguration's error for an action that is neither
a command nor a registered extension printed literal {0} and {1} where the
profile and action names belong.

The format operator binds tighter than string concatenation, so

    "Profile '{0}' references '{1}'. " + "Run Get-Command ..." -f $a, $b

formats only the second string - which has no placeholders - and leaves the
first exactly as written. The concatenation needs its own parentheses. This is
the same precedence trap that produced the earlier HTML-report bug, where a -f
inside a method call had its arguments taken as method arguments instead.

Audited every other site in the repository where a concatenation is followed
by -f: three exist and all three already parenthesise the concatenation
correctly, so this was the only one.

The local test runner in the scratchpad was ignoring Should -Throw's
-ExpectedMessage, which is precisely why this passed locally and failed in CI -
something threw, so it counted as a pass regardless of what it said. It now
compares the message, and with that change it reproduces the CI failure against
the old code and passes against the fix.

718 assertions, 0 failures; analyzer clean at 197 warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkdwqfkUYsNSkp9f3AVDqg
All 714 tests pass on Windows PowerShell 5.1 now. The job failed on the
analyzer instead: 275 warnings against a budget of 210, on a tree whose
sources had not changed.

The cause is that Analyze scanned obj/, which holds the compiled module - the
same functions, merged into one file. Compile.Tests builds it as part of the
suite, so by the time the Analyze step ran, obj/ existed and every finding in
module code was counted twice. The filter already excluded out/ and dist/ but
not obj/. Locally I had excluded obj/ in my own analyzer invocation, which is
why I measured 197 and CI measured 275 for identical code.

Excluding it is right on its own merits: obj/ is generated, its findings are
duplicates of ones already reported against the file a person would actually
edit, and a budget that moves depending on whether a build has run is not a
budget. With it excluded the count is 197, inside the existing 210 - so the
budget itself did not need raising.

tests/Syntax.Tests.ps1 had the same gap in its discovery filter, which is why
it found 232 files in a working tree and 228 in CI, where obj/ does not exist
at discovery time. Both now agree at 714 assertions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkdwqfkUYsNSkp9f3AVDqg
@likeBloodMoon
likeBloodMoon merged commit dd145b3 into main Sep 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants