Skip to content

Fix reinstall hardening modules - #16

Merged
Timpan4 merged 6 commits into
mainfrom
fix/reinstall-hardening-modules
Jun 6, 2026
Merged

Fix reinstall hardening modules#16
Timpan4 merged 6 commits into
mainfrom
fix/reinstall-hardening-modules

Conversation

@Timpan4

@Timpan4 Timpan4 commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Split bootstrap, WinGet, backup manifest, staged payload, and declarative config behavior into reusable modules.
  • Wire ISO staging to copy and validate modules so C:\Setup payload stays complete.
  • Add architecture/static coverage for module boundaries, conflict markers, parser checks, reinstall warnings, and restore remapping.

Testing

  • Invoke-Pester -Path .\tests -PassThru
  • Parser check for all .ps1 files
  • git diff --check -- . ':!testResults.xml'
  • Conflict-marker scan

Summary by CodeRabbit

Release Notes

  • New Features

    • Added persistent progress tracking for setup phases with real-time status updates
    • Implemented automatic retry mechanism for packages requiring user-scope installation
    • Added backup path remapping to support restores across different drive configurations
    • Introduced Setup Summary and Failed Installs reporting during installation
  • Bug Fixes

    • Improved registry value type handling for DWord entries
    • Enhanced WinGet package verification to detect installation status accurately
  • Documentation

    • Added Context and Glossary documentation for key setup concepts
    • Expanded troubleshooting guide with WinGet and backup manifest guidance
  • Tests

    • Added architecture and quality validation checks

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Timpan4, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 5 minutes and 58 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 92b183aa-c1dd-4aa4-afbd-9f9e8d8e9abd

📥 Commits

Reviewing files that changed from the base of the PR and between 1850901 and b5251f3.

📒 Files selected for processing (15)
  • apply-registry.ps1
  • bootstrap.ps1
  • build-iso.ps1
  • docs/TROUBLESHOOTING.md
  • modules/BackupManifest.ps1
  • modules/BootstrapRun.ps1
  • modules/DeclarativeConfig.ps1
  • modules/StagedSetupPayload.ps1
  • modules/WinGetInstall.ps1
  • restore-backup.ps1
  • tests/ArchitectureModules.Tests.ps1
  • tests/BackupRestore.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • tests/BuildIso.Tests.ps1
  • tests/Quality.Tests.ps1
📝 Walkthrough

Walkthrough

This PR refactors the declarative Windows setup automation into a modular, state-driven architecture. It introduces PowerShell modules for bootstrap state management, WinGet package installation with verification and retry, backup/restore path remapping, declarative registry configuration, and ISO payload validation. Progress is persisted to progress.json and step outcomes are tracked. Tests and documentation cover the new flows comprehensively.

Changes

Modular Architecture and Infrastructure

Layer / File(s) Summary
Context glossary and module architecture foundation
CONTEXT.md, build-iso.ps1, apply-registry.ps1
Adds context glossary defining Bootstrap run, Staged setup payload, Backup manifest, and Canonical repo; establishes conditional module loading pattern used across entry scripts.
Bootstrap state and progress tracking system
modules/BootstrapRun.ps1, bootstrap.ps1
Introduces BootstrapRun module with state initialization, step execution control, progress/summary/failure reporting; integrates progress.json persistence and progress helpers into bootstrap.ps1.
Registry declarative configuration system
modules/DeclarativeConfig.ps1, apply-registry.ps1, bootstrap.ps1
Introduces DeclarativeConfig module for JSON-driven registry configuration; refactors apply-registry.ps1 to delegate to the module; hardens registry writes with type coercion in Set-RegistryValueSafe.

WinGet Installation with Progress and Elevated Retry

Layer / File(s) Summary
WinGetInstall module helpers and core functions
modules/WinGetInstall.ps1
Introduces WinGetInstall module with package ID extraction, installation status verification via winget list, output filtering, elevation detection, and progress parsing from console output.
Per-package install execution with admin and unelevated modes
modules/WinGetInstall.ps1
Implements Invoke-WingetPackageInstall supporting admin-mode execution and user-scope retry via scheduled task with JSON result/progress file polling and cleanup.
Manifest-driven package scanning, install, and verification
modules/WinGetInstall.ps1
Implements Invoke-WingetManifestInstall that scans packages to identify missing ones, installs and verifies each package individually, tracks verified/unverified/failed outcomes, and triggers user-scope retry when needed.
Bootstrap WinGet integration and manifest-level changes
bootstrap.ps1
Integrates WinGetInstall functions into bootstrap, adds WinGet output helpers and progress parsing, refactors manifest install with per-package scanning/installation/verification, and manages retry cleanup.

Backup and Restore Path Remapping

Layer / File(s) Summary
BackupManifest module with manifest utilities and path resolution
modules/BackupManifest.ps1
Introduces BackupManifest module with functions to locate manifests, extract backup roots with environment expansion, resolve restore target mappings, and remap paths across different filesystem roots.
Preflight backup refactoring to use BackupManifest module
preflight-backup.ps1
Refactors to load BackupManifest module at runtime and use New-BackupManifest factory function instead of inline hashtable construction.
Restore backup refactoring with path remapping integration
restore-backup.ps1
Refactors to load BackupManifest module and use Resolve-BackupSourcePath and Resolve-RestoreTargetPath for cross-root path remapping in both repo-file and rule-based content restoration.

ISO Build System with Module Payload

Layer / File(s) Summary
StagedSetupPayload module for ISO validation
modules/StagedSetupPayload.ps1
Introduces module with functions to extract setup file references from autounattend.xml, compute required staged files, and validate that all referenced and required files exist in the staged ISO layout.
Build-iso.ps1 modules directory handling and validation
build-iso.ps1
Adds module loading support, requires modules directory to exist, validates it during build, and copies it into the staged ISO setup environment.

Bootstrap Execution Integration

Layer / File(s) Summary
Bootstrap module loading, progress tracking, and step state coordination
bootstrap.ps1
Adds module auto-loading from modules/ directory, initializes progress tracking at bootstrap start, updates progress state during setup phases including dry-run and optional-apps-only modes, adjusts step state outcomes for missing backup manifest and optional apps.

Documentation, Testing, and Quality Assurance

Layer / File(s) Summary
Troubleshooting documentation for verification and backup issues
docs/TROUBLESHOOTING.md
Adds troubleshooting subsections documenting WinGet package verification warnings and backup-manifest-not-found fallback behavior with recovery steps.
Architecture module validation tests
tests/ArchitectureModules.Tests.ps1
Introduces static checks that verify module files are referenced, expected functions are defined, and module interdependencies are properly declared.
Backup and restore path remapping tests
tests/BackupRestore.Tests.ps1
Extends with static checks for path remapping logic, backup root metadata usage, remapped source/target resolution, and module function presence.
Bootstrap execution and WinGet flow tests
tests/Bootstrap.Tests.ps1
Updates with comprehensive static checks for per-package installation, progress tracking, WinGet output handling, elevation detection, retry behavior, and registry safe writes.
ISO build tests and quality checks
tests/BuildIso.Tests.ps1, tests/Quality.Tests.ps1
Updates BuildIso.Tests.ps1 with modules copy assertions and improved validation patterns; adds Quality.Tests.ps1 with PowerShell parse validation and merge conflict marker detection.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Timpan4/declarative-windows#6: Adds marker file (winget.completed) to WinGet execution, directly related to the per-package installation flow refactoring in the main PR.
  • Timpan4/declarative-windows#15: Refactors WinGet manifest/install flow to use individual package installs with user-scope retry, overlapping with the main PR's complete rewrite of the WinGet installation and verification path.
  • Timpan4/declarative-windows#8: Introduces or modifies Find-BackupManifest and adjusts WinGet failure step states, directly related to the backup manifest module and bootstrap state handling introduced in the main PR.

Poem

🐰 Hops with glee,
Modules dancing free,
Progress traced with care,
Backup paths remapped through the air,
PowerShell dreams come true!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Fix reinstall hardening modules' is vague and does not clearly convey the primary changes. While the PR adds and refactors modules for bootstrap, WinGet, and backup functionality, the word 'Fix' suggests bug fixes rather than architectural refactoring and new module creation. Consider a more descriptive title such as 'Refactor bootstrap and backup into reusable modules' or 'Split core setup logic into modularized components' to better reflect the architectural changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reinstall-hardening-modules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 1850901adb

ℹ️ 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 modules/WinGetInstall.ps1 Outdated
$taskUser = if ($env:USERDOMAIN) { "$($env:USERDOMAIN)\$($env:USERNAME)" } else { $env:USERNAME }
$taskCommand = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$runnerPath`""

$createOutput = @(schtasks.exe /Create /F /TN $taskName /SC ONCE /ST $taskTime /TR $taskCommand /RL LIMITED /RU $taskUser 2>&1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid prompting during WinGet user-scope retry

When an admin WinGet install reports that it cannot run elevated, this retry path creates a task with /RU $taskUser but no /RP, /NP, or /IT; Microsoft's schtasks /create documentation says /rp is the password for the /ru account and that omitting it prompts for that user's run-as password (see the /rp parameter and alternate-account examples at https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks-create). In the unattended/elevated bootstrap flow that prompt is not handled, so packages that require the non-admin retry can hang or fail instead of continuing the reinstall.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
build-iso.ps1 (1)

103-170: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Local functions overridden by module.

Get-UnattendSetupFileReferences and Validate-StagedIsoLayout are defined locally but StagedSetupPayload.ps1 (dot-sourced at lines 172-176) also defines them. The module's versions will override these, making this local code dead. Either remove the local definitions or remove the module loading.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-iso.ps1` around lines 103 - 170, The local functions
Get-UnattendSetupFileReferences and Validate-StagedIsoLayout are duplicated by
the dot-sourced StagedSetupPayload.ps1 and thus get overridden; fix by keeping
only one authoritative definition: either delete these local function
definitions and rely on the implementations in StagedSetupPayload.ps1, or stop
dot-sourcing that file and instead import/namespace or rename the module’s
functions (or rename these local functions) so there is no collision; update any
call sites to use the chosen implementation (referencing
Get-UnattendSetupFileReferences and Validate-StagedIsoLayout) and ensure only
one definition remains in scope.
🧹 Nitpick comments (4)
tests/Quality.Tests.ps1 (2)

25-25: ⚡ Quick win

Rename variable to avoid shadowing $matches automatic variable.

PSScriptAnalyzer correctly flags that $matches is a PowerShell automatic variable set by the -match operator. While the code works in this scope, shadowing automatic variables is poor practice and can cause confusion.

♻️ Proposed fix
-        $matches = foreach ($file in $files) {
+        $conflictMarkers = foreach ($file in $files) {
             Select-String -LiteralPath $file.FullName -Pattern '^(<<<<<<<|\|\|\|\|\|\|\||=======|>>>>>>>)'
         }
 
-        $matches | Should -BeNullOrEmpty
+        $conflictMarkers | Should -BeNullOrEmpty
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Quality.Tests.ps1` at line 25, The variable $matches is shadowing
PowerShell's automatic $matches; rename the loop-assigned variable (e.g., change
"$matches = foreach ($file in $files) {" to "$fileMatches = foreach ($file in
$files) {") and update all references inside the foreach block and any later
uses from $matches to the new name (e.g., $fileMatches) to avoid colliding with
the automatic $matches variable.

Source: Linters/SAST tools


22-22: 💤 Low value

Consider including .yml files in conflict marker check.

The file type filter includes .ps1, .md, .json, and .xml, but excludes .yml files. GitHub Actions workflows (.github/workflows/*.yml) are text files that could also contain unresolved merge conflicts. Consider adding .yml to the extension list unless the omission is intentional.

♻️ Proposed enhancement
             Where-Object {
                 $_.FullName -notmatch '\\.git\\' -and
-                $_.Extension -in @(".ps1", ".md", ".json", ".xml")
+                $_.Extension -in @(".ps1", ".md", ".json", ".xml", ".yml")
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Quality.Tests.ps1` at line 22, The conflict-check filter in
tests/Quality.Tests.ps1 uses the expression $_.Extension -in @(".ps1", ".md",
".json", ".xml") and omits YAML workflow files; update that array in the test to
include ".yml" (and optionally ".yaml") so GitHub Actions workflow files are
scanned for conflict markers by the conflict marker check in this script.
modules/BackupManifest.ps1 (1)

64-64: 💤 Low value

Inconsistent TrimStart argument.

Line 64 uses TrimStart('\\') (two backslash chars) while line 96 uses TrimStart('\') (single). Both work since TrimStart removes any characters in the set, but the double-backslash is misleading. Consider using TrimStart('\') for consistency with the rest of the file.

Suggested fix
-        $relativePath = $expandedPath.Substring($ManifestBackupRoot.Length).TrimStart('\\')
+        $relativePath = $expandedPath.Substring($ManifestBackupRoot.Length).TrimStart('\')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/BackupManifest.ps1` at line 64, The TrimStart call that computes
$relativePath uses TrimStart('\\') which is inconsistent and misleading compared
to other uses (e.g., the TrimStart('\') at line 96); update the TrimStart
invocation on the $relativePath assignment to use a single-escaped backslash
character (TrimStart('\')) to match the rest of the file and remove the
misleading double-backslash.
apply-registry.ps1 (1)

20-42: Dead code after module delegation in apply-registry.ps1

Normalize-RegistryPath and Convert-RegistryType are defined in apply-registry.ps1 (lines 20-42) but never called: when Invoke-DeclarativeConfig exists the script immediately returns (lines 44-46), otherwise it throws (line 48). These helpers are instead implemented and used in modules/DeclarativeConfig.ps1, so the duplicates here are redundant—removing them would reduce maintenance/confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apply-registry.ps1` around lines 20 - 42, Remove the unused duplicate helper
functions Normalize-RegistryPath and Convert-RegistryType from
apply-registry.ps1: locate and delete both function definitions
(Normalize-RegistryPath { ... } and Convert-RegistryType { ... }) since
Invoke-DeclarativeConfig short-circuits this script and the canonical
implementations live in modules/DeclarativeConfig.ps1; after removal, verify
there are no other references to these symbols in the file and run the
test/validation steps to ensure no regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/TROUBLESHOOTING.md`:
- Around line 131-133: The new fenced code blocks in TROUBLESHOOTING.md (e.g.,
the block containing "WinGet reported success but winget list did not verify the
package" and the other blocks noted around the same sections) are missing a
language identifier; update each triple-backtick fence to include `text` (for
example change ``` to ```text) so MD040 is satisfied and plain output snippets
are explicitly marked.

In `@modules/BootstrapRun.ps1`:
- Around line 184-186: The loop building $summaryLines currently prints raw
status strings from $SummaryItems; change it to map those statuses to the
required symbols (OK -> ✓, WARN -> ⚠, FAIL -> ✗) before formatting. Inside the
foreach over $SummaryItems, derive a $symbol using a switch or hashtable keyed
by $item.Status and then use that $symbol in the format string when appending to
$summaryLines; update the reference to $item.Status in the format to $symbol so
the summary shows ✓/⚠/✗ for completed/skipped/failed entries.

In `@modules/StagedSetupPayload.ps1`:
- Line 85: The call to Write-Success in StagedSetupPayload.ps1 may fail when the
module is used standalone because Write-Success isn't guaranteed to be defined;
update the end of the validation flow to check for the presence of Write-Success
(e.g., via Get-Command -Name Write-Success -ErrorAction SilentlyContinue) and
only call it if present, otherwise emit an equivalent fallback message (using
Write-Host or Write-Output) so the module runs safely outside build-iso.ps1;
reference the Write-Success invocation in StagedSetupPayload.ps1 to locate where
to add the conditional guard and fallback.

In `@modules/WinGetInstall.ps1`:
- Around line 339-345: The current check uses -not $missingPackages which fails
for an empty generic list; replace the condition with an explicit count check
(e.g. use $missingPackages.Count -eq 0, or to be defensive: if (-not
$missingPackages -or $missingPackages.Count -eq 0)) so the fast-path that calls
Write-Log, Set-Content (MarkerPath, appsHash), Add-SummaryItem (SummaryStep) and
Set-StepState (StepId) executes when no packages are missing.

In `@restore-backup.ps1`:
- Around line 112-149: The local Resolve-BackupSourcePath function duplicates
the one provided by the BackupManifest.ps1 module and is being overridden;
remove the local Resolve-BackupSourcePath definition and instead ensure the
BackupManifest.ps1 module is dot-sourced before any code that calls
Resolve-BackupSourcePath so the module implementation is used consistently;
update code ordering to load BackupManifest.ps1 early (or keep only one
canonical implementation in BackupManifest.ps1) and delete the redundant local
function block.

In `@tests/Quality.Tests.ps1`:
- Line 8: The path filter in the Where-Object pipeline uses a Windows-only
backslash pattern (the expression $_.FullName -notmatch '\\.git\\'), so update
the regex to handle both POSIX and Windows separators; replace the pattern with
a cross-platform check such as $_.FullName -notmatch '([\\/]\.git([\\/]|$))' in
the Where-Object clause to exclude .git directories on all platforms.
- Line 21: The -notmatch regex is Windows-specific: $_.FullName -notmatch
'\\.git\\' won't exclude .git directories on Unix. Update the match used with
$_.FullName to be platform-agnostic (e.g., match either slash direction or check
path segments) so .git is excluded on all OSes; replace the '\\.git\\' literal
with a cross-platform pattern (e.g., use a regex that allows both '/' and '\' or
check Path.DirectorySeparatorChar or split the path) where the -notmatch is
applied.

---

Outside diff comments:
In `@build-iso.ps1`:
- Around line 103-170: The local functions Get-UnattendSetupFileReferences and
Validate-StagedIsoLayout are duplicated by the dot-sourced
StagedSetupPayload.ps1 and thus get overridden; fix by keeping only one
authoritative definition: either delete these local function definitions and
rely on the implementations in StagedSetupPayload.ps1, or stop dot-sourcing that
file and instead import/namespace or rename the module’s functions (or rename
these local functions) so there is no collision; update any call sites to use
the chosen implementation (referencing Get-UnattendSetupFileReferences and
Validate-StagedIsoLayout) and ensure only one definition remains in scope.

---

Nitpick comments:
In `@apply-registry.ps1`:
- Around line 20-42: Remove the unused duplicate helper functions
Normalize-RegistryPath and Convert-RegistryType from apply-registry.ps1: locate
and delete both function definitions (Normalize-RegistryPath { ... } and
Convert-RegistryType { ... }) since Invoke-DeclarativeConfig short-circuits this
script and the canonical implementations live in modules/DeclarativeConfig.ps1;
after removal, verify there are no other references to these symbols in the file
and run the test/validation steps to ensure no regressions.

In `@modules/BackupManifest.ps1`:
- Line 64: The TrimStart call that computes $relativePath uses TrimStart('\\')
which is inconsistent and misleading compared to other uses (e.g., the
TrimStart('\') at line 96); update the TrimStart invocation on the $relativePath
assignment to use a single-escaped backslash character (TrimStart('\')) to match
the rest of the file and remove the misleading double-backslash.

In `@tests/Quality.Tests.ps1`:
- Line 25: The variable $matches is shadowing PowerShell's automatic $matches;
rename the loop-assigned variable (e.g., change "$matches = foreach ($file in
$files) {" to "$fileMatches = foreach ($file in $files) {") and update all
references inside the foreach block and any later uses from $matches to the new
name (e.g., $fileMatches) to avoid colliding with the automatic $matches
variable.
- Line 22: The conflict-check filter in tests/Quality.Tests.ps1 uses the
expression $_.Extension -in @(".ps1", ".md", ".json", ".xml") and omits YAML
workflow files; update that array in the test to include ".yml" (and optionally
".yaml") so GitHub Actions workflow files are scanned for conflict markers by
the conflict marker check in this script.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6eef5b72-19da-4e6f-a753-7193b4d2c84a

📥 Commits

Reviewing files that changed from the base of the PR and between 92cf6a2 and 1850901.

📒 Files selected for processing (17)
  • CONTEXT.md
  • apply-registry.ps1
  • bootstrap.ps1
  • build-iso.ps1
  • docs/TROUBLESHOOTING.md
  • modules/BackupManifest.ps1
  • modules/BootstrapRun.ps1
  • modules/DeclarativeConfig.ps1
  • modules/StagedSetupPayload.ps1
  • modules/WinGetInstall.ps1
  • preflight-backup.ps1
  • restore-backup.ps1
  • tests/ArchitectureModules.Tests.ps1
  • tests/BackupRestore.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • tests/BuildIso.Tests.ps1
  • tests/Quality.Tests.ps1

Comment thread docs/TROUBLESHOOTING.md Outdated
Comment thread modules/BootstrapRun.ps1
Comment thread modules/StagedSetupPayload.ps1 Outdated
Comment thread modules/WinGetInstall.ps1 Outdated
Comment thread restore-backup.ps1 Outdated
Comment thread tests/Quality.Tests.ps1 Outdated
Comment thread tests/Quality.Tests.ps1 Outdated

@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: e294c901ee

ℹ️ 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 modules/BackupManifest.ps1 Outdated
[Parameter(Mandatory)][object[]]$Rules,
[Parameter(Mandatory)][object[]]$RepoFiles,
[Parameter(Mandatory)][object]$Exports,
[Parameter(Mandatory)][object[]]$Failures

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow empty failure lists in backup manifests

When a backup completes without failed rules, preflight-backup.ps1 calls New-BackupManifest -Failures @($failedRules) with an empty collection. Mandatory collection parameters reject empty arrays unless they opt in with AllowEmptyCollection, so the normal successful backup path can fail before writing backup-manifest.json; the same pattern can also affect RepoFiles when repo-file backup is disabled.

Useful? React with 👍 / 👎.

@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

Set-RegistryValueSafe -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "HideFileExt" -Value 0 -Type DWord

P2 Badge Preserve registry value kinds when updating tweaks

When these tweak values already exist with the wrong registry kind (for example a REG_SZ "0" left by a prior manual tweak), this now only casts the data and calls Set-ItemProperty without -Type, so PowerShell updates the value but does not force it back to REG_DWORD/REG_SZ; Windows policies such as Explorer DWORDs can then keep being ignored despite the data looking correct. The Registry provider does support Set-ItemProperty -Type <RegistryValueKind> on Windows (see Microsoft docs for the Registry-provider parameter), so the previous type argument should be preserved or replaced with an equivalent New-ItemProperty -PropertyType ... -Force path.

ℹ️ 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".

@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: c2786064d0

ℹ️ 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 modules/DeclarativeConfig.ps1 Outdated
continue
}

Set-ItemProperty -LiteralPath $registryPath -Name $entry.name -Value $desiredValue -Force

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve registry value kind when applying config

When a customized config\registry.json contains a DWord entry that needs to be created, this refactor converts the value to an int but no longer passes the converted $valueType to the Registry provider. The previous implementation supplied the requested type, and the bootstrap tweak path still uses New-ItemProperty -PropertyType for the same reason; without doing that here, new registry values can be created with the wrong kind and Windows policies/tweaks that require REG_DWORD may be ignored even though the script reports success.

Useful? React with 👍 / 👎.

@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: c2786064d0

ℹ️ 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 modules/DeclarativeConfig.ps1 Outdated
continue
}

Set-ItemProperty -LiteralPath $registryPath -Name $entry.name -Value $desiredValue -Force

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the requested registry value type

When registry.json contains a DWORD entry whose value is missing or has the wrong kind, the new apply-registry.ps1 path delegates here and this call no longer passes the computed $valueType. That lets the registry provider infer/create the value kind instead of enforcing the declared type, so the fallback can report success while leaving policies that require REG_DWORD as a string/default-kind value and the bootstrap then marks the registry step done.

Useful? React with 👍 / 👎.

@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: a3b8843bb9

ℹ️ 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 modules/WinGetInstall.ps1 Outdated
}
}

return $packageIds | Sort-Object -Unique

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return an array for single-package manifests

When apps.json or optional-apps.json contains exactly one PackageIdentifier, this pipeline return is assigned as a scalar string in Invoke-WingetManifestInstall; the later $packageIds[$index] access then indexes the string, so an id like Microsoft.PowerToys becomes M and WinGet checks/installs the wrong package. Wrap the sorted result or the call site in an array so single-entry manifests are processed as one package id.

Useful? React with 👍 / 👎.

@Timpan4
Timpan4 merged commit dd2ebb7 into main Jun 6, 2026
4 checks passed
@Timpan4
Timpan4 deleted the fix/reinstall-hardening-modules branch June 6, 2026 15:31
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.

1 participant