Skip to content

feat: add ISO build script and update docs to Implementation#5

Merged
Timpan4 merged 1 commit intomainfrom
feat-add-iso-build-script
Jan 11, 2026
Merged

feat: add ISO build script and update docs to Implementation#5
Timpan4 merged 1 commit intomainfrom
feat-add-iso-build-script

Conversation

@Timpan4
Copy link
Copy Markdown
Owner

@Timpan4 Timpan4 commented Jan 11, 2026

  • Update README.md and FAQ.md: set project status to "Implementation Phase", note that MVP scripts exist, and point to remaining tasks in TODO.md.
  • Add build-iso.ps1: PowerShell script to automate creating a custom Windows 11 ISO with:
    • Parameters for source ISO, output path, and debug temp
    • Discovery of oscdimg.exe from Windows ADK and prerequisite validation
    • Mounting, preparation, and injection of autounattend and OEM files (bootstrap, apps.json, Sophia-Preset) into the ISO structure
    • Colored, step-wise console output and robust error handling
    • Header with usage examples and requirements

Summary by CodeRabbit

  • New Features

    • Added a Windows bootstrap automation to orchestrate setup, network checks, package imports, per-step reporting, and a desktop summary.
    • Added an ISO builder that assembles a customized Windows installer with embedded setup and one-command ISO generation.
  • Documentation

    • Project status moved from Planning to Implementation; README and FAQ updated with an MVP workflow, commands, and next steps.

✏️ Tip: You can customize this high-level summary in your review settings.

Update project status to "Implementation Phase" in README.md
and FAQ.md. Clarify that MVP scripts exist and point to remaining
tasks in TODO.md.

Add build-iso.ps1, a new PowerShell script that automates creating
a custom Windows 11 ISO. The script:
- Provides parameters for source ISO, output path, and debug temp.
- Locates oscdimg.exe from Windows ADK and validates prerequisites.
- Mounts, prepares, and injects autounattend and OEM files (bootstrap,
  apps.json, Sophia-Preset) into the ISO structure.
- Offers colored, step-wise console output and robust error handling.
- Includes usage examples and requirements in the header comment.

Motivation: move the repository from planning to an actionable MVP by
including the core automation for producing a customized Windows ISO
and updating documentation to reflect active development.
feat: improve network checks and error reporting in scripts

Enhance bootstrap network probing to use multiple ping targets and
fallback HTTPS checks. Add checks for Test-NetConnection and
Invoke-WebRequest availability and attempt HTTPS TCP or HEAD requests
to more reliably detect connectivity. This reduces false negatives
when a single ICMP target is unreachable.

Refactor build-iso error output: rename Write-Error to
Write-ErrorMessage and update all call sites. Replace a removed
unused Get-BootImage function. Improve error messages when tools or
files are missing and ensure consistent red error printing.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

Project phase updated from PLANNING to IMPLEMENTATION. Documentation reflects existing MVP scripts. Two new PowerShell scripts added: bootstrap.ps1 (declarative setup orchestrator) and build-iso.ps1 (custom Windows 11 ISO builder injecting automation assets).

Changes

Cohort / File(s) Change Summary
Documentation Updates
CLAUDE.md, FAQ.md, README.md
Phase moved to IMPLEMENTATION; narratives and headers updated from "Planned" to "MVP"; README includes MVP workflow and example commands referencing bootstrap.ps1 and build-iso.ps1.
Bootstrap Orchestrator
bootstrap.ps1
New script enforcing elevation, init logging, network wait, parse apps.json, detect/install missing WinGet packages, execute Sophia-Preset.ps1, create desktop shortcut and Setup Summary.txt, per-step error handling and temp-file cleanup. Adds functions: Write-Log, Add-SummaryItem, Write-SummaryReport, Wait-ForNetwork, Get-WingetPackageIdsFromJson, Test-WingetPackageInstalled, Write-FilteredAppsJson.
ISO Builder
build-iso.ps1
New script validating required files, locating oscdimg.exe (ADK), mounting/copying source ISO, injecting autounattend.xml and $OEM$\Setup with bootstrap.ps1/apps.json/Sophia-Preset.ps1, generating helper shortcut, building final ISO via oscdimg, and robust error handling and cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Administrator
    participant Bootstrap as bootstrap.ps1
    participant Network as Network
    participant WinGet as WinGet
    participant Apps as apps.json
    participant Sophia as Sophia-Preset

    Admin->>Bootstrap: Run (elevated)
    Bootstrap->>Bootstrap: Init logging, paths, summary
    Bootstrap->>Network: Wait-ForNetwork
    Network-->>Bootstrap: Ready
    Bootstrap->>Apps: Parse apps.json
    Apps-->>Bootstrap: Package list
    Bootstrap->>WinGet: Test-WingetPackageInstalled / Install missing
    WinGet-->>Bootstrap: Install results
    Bootstrap->>Sophia: Execute preset (if present)
    Sophia-->>Bootstrap: Result
    Bootstrap->>Admin: Create desktop shortcut & Summary report
Loading
sequenceDiagram
    participant User as User
    participant BuildISO as build-iso.ps1
    participant Files as File Validation
    participant ADK as ADK/Registry
    participant ISO as Source ISO (mount/copy)
    participant OSC as oscdimg.exe
    participant Output as Output ISO

    User->>BuildISO: Invoke with source & output paths
    BuildISO->>Files: Verify autounattend.xml, bootstrap.ps1, apps.json, Sophia-Preset.ps1
    Files-->>BuildISO: OK
    BuildISO->>ADK: Locate oscdimg.exe
    ADK-->>BuildISO: Path or error
    BuildISO->>ISO: Mount source ISO & copy contents
    ISO-->>BuildISO: Copied to workdir
    BuildISO->>BuildISO: Inject autounattend.xml and $OEM$\Setup assets
    BuildISO->>OSC: Run oscdimg to create ISO
    OSC-->>Output: ISO created
    BuildISO->>User: Report size, validate, cleanup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped from notes into scripts tonight,
PowerShell paws arranging files just right,
ISOs stitched, a bootstrap trail in sight,
I nibble bugs and polish every byte,
Implementation dances into light. ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding the ISO build script (build-iso.ps1) and updating documentation to reflect the Implementation phase status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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.

Copy link
Copy Markdown

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

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: 8b5d6f1112

ℹ️ 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 bootstrap.ps1 Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
CLAUDE.md (1)

40-42: Resolve phase inconsistency in documentation.

Line 42 states "planning phase" but contradicts the phase declared at line 5-7 (IMPLEMENTATION). Update this section to reflect the current implementation phase.

♻️ Suggested update
  ## Current State
  
- This is an early-stage project currently in the planning phase. See `brainstorm.md` for research and design discussions.
+ This project is now in the implementation phase. MVP scripts (bootstrap.ps1, build-iso.ps1) are under active development. See `brainstorm.md` for prior research and design discussions.
🤖 Fix all issues with AI agents
In @build-iso.ps1:
- Around line 63-66: The custom function named Write-Error shadows PowerShell's
built-in cmdlet; rename it (e.g., to Write-ErrorMessage or Write-LogError) and
update all internal calls that use Write-Error to the new name (replace the
custom Write-Error definition and any invocations such as those later in the
script that log failures). Ensure the new function keeps the same parameter
signature and behavior (printing with red color) so callers work the same after
renaming.
- Around line 110-126: Delete the unused Get-BootImage function declaration to
remove dead code: remove the entire function block named Get-BootImage (the
param and body that builds $bootImages and iterates to return a path) since the
script currently hardcodes boot image paths elsewhere; alternatively, if you
prefer to centralize logic, replace the hardcoded boot image selection with a
call to Get-BootImage and remove the hardcoded paths — either delete the unused
Get-BootImage definition or replace the hardcoded usage with a call to
Get-BootImage so there is no unused dead code.
🧹 Nitpick comments (4)
README.md (1)

137-138: Update stale "(planned)" comments to reflect implementation status.

Lines 137-138 indicate the scripts are "(planned)" but the PR is implementing them as part of the IMPLEMENTATION phase. Update the comments to remove "(planned)" or rephrase to reflect that they are being implemented.

♻️ Suggested update
- ├── bootstrap.ps1          # Main orchestration script (planned)
- ├── build-iso.ps1          # ISO generation script (planned)
+ ├── bootstrap.ps1          # Main orchestration script
+ ├── build-iso.ps1          # ISO generation script
build-iso.ps1 (1)

34-36: Consider validating that the source ISO is Windows 11.

The script currently only validates that the source file exists but doesn't verify it's a Windows 11 ISO. Consider adding validation to check for Windows 11 markers (e.g., version info from install.wim metadata) to prevent issues downstream.

🔍 Example validation approach

After mounting the ISO, you could add a check like:

# Verify Windows 11 ISO
$installWim = Join-Path $sourceRoot "sources\install.wim"
if (Test-Path $installWim) {
    $wimInfo = dism /Get-WimInfo /WimFile:$installWim /Index:1 | Select-String "Version"
    if ($wimInfo -notmatch "10\.0\.22") {
        throw "Source ISO does not appear to be Windows 11 (22H2+)"
    }
}

Based on learnings, all scripts must target Windows 11 (22H2+) only.

bootstrap.ps1 (2)

22-22: Reconsider ErrorActionPreference setting.

Setting $ErrorActionPreference = "Continue" is unusual for a script with structured error handling. This allows non-terminating errors to proceed silently, which can mask issues. Consider using "Stop" to ensure errors are caught by your try/catch blocks, or document why "Continue" is necessary for idempotency.

💡 Suggested approach
-$ErrorActionPreference = "Continue"
+$ErrorActionPreference = "Stop"

If certain operations should continue on error (like checking if packages are installed), handle those specifically with -ErrorAction Continue or -ErrorAction SilentlyContinue on individual commands rather than globally.


131-140: Add WinGet availability check.

The function assumes winget is available in PATH but doesn't verify this. If WinGet is not installed or not in PATH, the command will fail ungracefully. Consider adding a check before first use to provide a clearer error message.

🔍 Suggested check

Before first WinGet use (around line 190), add:

# Verify WinGet is available
if (-not (Get-Command winget -ErrorAction SilentlyContinue)) {
    Write-Log "ERROR: WinGet is not installed or not in PATH" -Level ERROR
    Write-Log "WinGet is required for application installation" -Level ERROR
    Add-SummaryItem -Step "WinGet" -Status "" -Message "WinGet not available"
    # Continue with rest of script instead of exiting
} else {
    # ... existing WinGet logic
}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cda0d41 and 8b5d6f1.

📒 Files selected for processing (5)
  • CLAUDE.md
  • FAQ.md
  • README.md
  • bootstrap.ps1
  • build-iso.ps1
🧰 Additional context used
📓 Path-based instructions (4)
{README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md}

📄 CodeRabbit inference engine (CLAUDE.md)

All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support

Files:

  • README.md
  • CLAUDE.md
**/*.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ps1: Do not create any PowerShell scripts (.ps1) during the planning phase
All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Files:

  • build-iso.ps1
  • bootstrap.ps1
build-iso.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Files:

  • build-iso.ps1
bootstrap.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

bootstrap.ps1: bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
bootstrap.ps1 must produce logs: Desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
Provide a desktop shortcut to re-run bootstrap.ps1 manually

Files:

  • bootstrap.ps1
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md} : All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {autounattend.xml,apps.json,config/**/*.json} : All configuration files must assume Windows 11 (22H2+) only; do not include Windows 10 compatibility logic
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step

Applied to files:

  • README.md
  • FAQ.md
  • build-iso.ps1
  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : Do not create any PowerShell scripts (.ps1) during the planning phase

Applied to files:

  • README.md
  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Applied to files:

  • README.md
  • build-iso.ps1
  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Applied to files:

  • build-iso.ps1
  • bootstrap.ps1
  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {autounattend.xml,apps.json,config/**/*.json} : All configuration files must assume Windows 11 (22H2+) only; do not include Windows 10 compatibility logic

Applied to files:

  • build-iso.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : Provide a desktop shortcut to re-run bootstrap.ps1 manually

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: During planning, only work on documentation, planning/design docs, and configuration schemas/examples

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md} : All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support

Applied to files:

  • CLAUDE.md
🔇 Additional comments (15)
FAQ.md (1)

1-48: No issues found. FAQ.md correctly reflects the project status and is well-aligned with the PR objectives.

README.md (1)

1-180: Documentation phase transition is well-executed. The project status updates, workflow examples, and Windows version support are all appropriately aligned with the IMPLEMENTATION phase transition. Windows 11 (22H2+) support is correctly stated throughout, with Windows 10 support explicitly excluded per coding guidelines.

CLAUDE.md (1)

1-203: Documentation correctly reflects implementation architecture and Windows 11 requirements. The ISO structure documentation (lines 99-111) accurately reflects the required file placement with autounattend.xml at the ISO root and configuration files in the $OEM$\$$\Setup directory. Windows 11 (22H2+) support is correctly emphasized throughout, with Windows 10 explicitly excluded per coding guidelines. The workflows and feature descriptions align well with the MVP objectives.

build-iso.ps1 (6)

73-108: LGTM! Robust oscdimg.exe discovery logic.

The function properly searches common installation paths, falls back to registry lookup, and provides helpful guidance when ADK is not found. The error message includes a direct link to installation instructions.


170-190: LGTM! Proper ISO mounting and content extraction.

The script correctly mounts the source ISO, extracts its contents to a working directory, and promptly unmounts it before modifications. The use of Resolve-Path ensures absolute paths for mounting operations.


192-236: LGTM! Correct file injection per requirements.

The script properly:

  • Places autounattend.xml at the ISO root
  • Creates the $OEM$\$$\Setup directory structure (which maps to C:\Setup during installation)
  • Copies bootstrap.ps1, apps.json, and Sophia-Preset.ps1 into the setup directory
  • Generates a desktop shortcut script for re-running bootstrap

This aligns with the requirement that build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$$$\Setup directory. Based on learnings.


238-286: LGTM! ISO building logic is sound.

The script correctly:

  • Resolves output paths to handle relative and absolute paths
  • Creates output directory if needed
  • Uses appropriate oscdimg parameters for dual-boot (BIOS + UEFI) Windows 11 ISO creation
  • Validates the build succeeded and reports file size

The -bootdata parameter formatting with backtick escaping is correct for PowerShell string handling.


287-339: LGTM! Comprehensive completion and cleanup.

The script provides excellent user experience with:

  • Clear success messaging and next steps
  • Detailed error reporting with stack traces
  • Robust cleanup in the finally block that safely unmounts the ISO even on failure
  • Configurable temp file retention via -KeepTemp for debugging

The defensive programming with ErrorAction SilentlyContinue during cleanup prevents cascading errors.


143-158: No issues found. The code correctly uses Sophia-Preset.ps1 (the actual file that exists in the repository) and properly places all required files: autounattend.xml at the ISO root and bootstrap.ps1, apps.json, and Sophia-Preset.ps1 in the $OEM$\$$\Setup directory as specified.

bootstrap.ps1 (6)

30-89: LGTM! Logging infrastructure meets requirements.

The logging functions provide:

  • Timestamped, color-coded console output with severity levels
  • Persistent logging to C:\Setup\install.log
  • Summary collection and desktop report generation at Setup Summary.txt

This aligns with the requirement to produce a desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log. Based on learnings.


176-182: Admin privilege check is redundant but provides better UX.

The script includes #Requires -RunAsAdministrator (line 1), which prevents non-admin execution. The manual check here is defensive and provides a clearer error message, which is good for user experience, but is technically redundant.


190-257: LGTM! Excellent idempotent WinGet installation logic.

The script properly implements idempotency by:

  • Checking which packages are already installed before attempting installation
  • Skipping installation when all packages are present
  • Creating a filtered import file containing only missing packages
  • Providing clear status feedback for each scenario

This aligns with the requirement that bootstrap.ps1 must be idempotent: skip already-installed apps and produce clear status for each step. Based on learnings.


259-285: LGTM! Proper Sophia Script execution with defensive error handling.

The script correctly:

  • Uses the call operator (&) to execute the Sophia preset
  • Checks both zero and null $LASTEXITCODE values (important as not all PowerShell scripts set exit codes)
  • Treats non-zero exit codes as warnings rather than fatal errors, allowing the setup to continue

287-316: LGTM! Desktop assets meet requirements.

The script creates:

  • Desktop shortcut (Run Windows Setup.lnk) to re-run bootstrap.ps1 manually
  • Desktop summary report (Setup Summary.txt) with all setup results

Both assets have proper error handling that logs failures without stopping execution. This aligns with the requirement to provide a desktop shortcut to re-run bootstrap.ps1 manually. Based on learnings.


318-329: LGTM! Comprehensive completion and error handling.

The script provides:

  • Clear completion logging with log file location
  • Fatal error handling with detailed stack traces for debugging
  • Appropriate exit code (1) on failure

The error handling complements the per-step try/catch blocks throughout the script.

Comment thread build-iso.ps1 Outdated
Comment thread build-iso.ps1 Outdated
@Timpan4
Copy link
Copy Markdown
Owner Author

Timpan4 commented Jan 11, 2026

@codex review

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @build-iso.ps1:
- Around line 225-227: Add existence checks for the boot image variables
$bootImage and $efiBootImage before invoking oscdimg: verify both paths
(constructed with Join-Path) exist, and if either is missing, write a clear
error via Write-Error/Throw (including the missing path) and exit with a
non-zero code; place this validation immediately after the assignments to
$bootImage and $efiBootImage so the script fails fast with an informative
message instead of letting oscdimg produce a cryptic error.
🧹 Nitpick comments (5)
build-iso.ps1 (2)

249-258: Consider capturing oscdimg output for debugging.

When oscdimg fails, the current implementation only reports the exit code. Capturing stdout/stderr would aid troubleshooting.

Proposed enhancement to capture oscdimg output
-    Write-Info "Running: oscdimg $($oscdimgArgs -join ' ')"
-
-    $process = Start-Process -FilePath $oscdimgPath -ArgumentList $oscdimgArgs -NoNewWindow -Wait -PassThru
+    Write-Info "Running: oscdimg $($oscdimgArgs -join ' ')"
+    
+    $oscdimgLog = Join-Path $TempDir "oscdimg.log"
+    $process = Start-Process -FilePath $oscdimgPath -ArgumentList $oscdimgArgs -NoNewWindow -Wait -PassThru -RedirectStandardOutput $oscdimgLog -RedirectStandardError "$oscdimgLog.err"
 
     if ($process.ExitCode -eq 0) {
         Write-Success "ISO built successfully!"
     }
     else {
+        if (Test-Path "$oscdimgLog.err") {
+            Write-Info "oscdimg error output:"
+            Get-Content "$oscdimgLog.err" | ForEach-Object { Write-Info $_ }
+        }
         throw "oscdimg.exe failed with exit code: $($process.ExitCode)"
     }

304-311: Cleanup may fail if source ISO path was relative and working directory changed.

Using Resolve-Path $SourceISO in the finally block could fail if the original path was relative and the working directory changed during execution. Consider storing the resolved path earlier.

Proposed fix to store resolved path early

At the top of the try block (around line 157), store the resolved path:

$resolvedSourceISO = (Resolve-Path $SourceISO).Path
$mount = Mount-DiskImage -ImagePath $resolvedSourceISO -PassThru

Then update the cleanup:

     try {
         if ($mount) {
-            Dismount-DiskImage -ImagePath (Resolve-Path $SourceISO).Path -ErrorAction SilentlyContinue | Out-Null
+            Dismount-DiskImage -ImagePath $resolvedSourceISO -ErrorAction SilentlyContinue | Out-Null
         }
     }
bootstrap.ps1 (3)

158-167: Consider stricter package ID matching.

Using -match with [regex]::Escape($PackageId) could match partial strings if the package ID appears as a substring in other output. Since --exact is used, the output should be precise, but consider anchoring the match or checking for the ID in a structured way.

Alternative approach using line-based matching
 function Test-WingetPackageInstalled {
     param([string]$PackageId)
 
     $result = winget list --id $PackageId --exact 2>&1
     if ($LASTEXITCODE -ne 0) {
         return $false
     }
 
-    return $result -match [regex]::Escape($PackageId)
+    # With --exact, presence of package lines beyond headers indicates installed
+    $lines = $result -split "`n" | Where-Object { $_ -match [regex]::Escape($PackageId) }
+    return $lines.Count -gt 0
 }

286-312: Consider tracking Sophia Script execution state for idempotency.

Per coding guidelines, the bootstrap should "skip already-applied tweaks." Currently, Sophia Script runs on every bootstrap execution. For MVP this may be acceptable if Sophia's internal logic is safe to re-run, but consider adding a marker file check for full idempotency.

Optional marker file approach
+    $sophiaMarker = Join-Path $SetupPath ".sophia-applied"
+
     if (Test-Path $SophiaPreset) {
+        if (Test-Path $sophiaMarker) {
+            Write-Log "Sophia Script already applied (marker exists)" -Level SUCCESS
+            Add-SummaryItem -Step "Sophia" -Status "✓" -Message "Already applied (skipped)"
+        }
+        else {
             try {
                 Write-Log "Found Sophia preset at $SophiaPreset" -Level INFO
                 Write-Log "Executing Sophia Script..." -Level INFO
 
                 & $SophiaPreset
 
                 if ($LASTEXITCODE -eq 0 -or $null -eq $LASTEXITCODE) {
                     Write-Log "Sophia Script execution completed" -Level SUCCESS
                     Add-SummaryItem -Step "Sophia" -Status "✓" -Message "Sophia preset applied"
+                    New-Item -Path $sophiaMarker -ItemType File -Force | Out-Null
                 } else {
                     ...
                 }
             }
+        }
     }

351-356: Add summary item for fatal errors before exiting.

If a fatal error occurs, the desktop summary won't reflect the failure since Write-SummaryReport is only called in the success path.

Proposed fix to write summary on failure
 catch {
     Write-Log "FATAL ERROR: $($_.Exception.Message)" -Level ERROR
     Write-Log "Stack Trace: $($_.ScriptStackTrace)" -Level ERROR
+    Add-SummaryItem -Step "Bootstrap" -Status "✗" -Message "Fatal error: $($_.Exception.Message)"
+    try {
+        $desktopPath = [Environment]::GetFolderPath("Desktop")
+        Write-SummaryReport -DesktopPath $desktopPath | Out-Null
+    } catch { }
     exit 1
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b5d6f1 and 02079a4.

📒 Files selected for processing (2)
  • bootstrap.ps1
  • build-iso.ps1
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ps1: Do not create any PowerShell scripts (.ps1) during the planning phase
All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Files:

  • bootstrap.ps1
  • build-iso.ps1
bootstrap.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

bootstrap.ps1: bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
bootstrap.ps1 must produce logs: Desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
Provide a desktop shortcut to re-run bootstrap.ps1 manually

Files:

  • bootstrap.ps1
build-iso.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Files:

  • build-iso.ps1
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md} : All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : Provide a desktop shortcut to re-run bootstrap.ps1 manually

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Applied to files:

  • bootstrap.ps1
  • build-iso.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Applied to files:

  • bootstrap.ps1
  • build-iso.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {autounattend.xml,apps.json,config/**/*.json} : All configuration files must assume Windows 11 (22H2+) only; do not include Windows 10 compatibility logic

Applied to files:

  • build-iso.ps1
🔇 Additional comments (8)
build-iso.ps1 (3)

1-43: LGTM! Script header and parameters are well-structured.

The #Requires -RunAsAdministrator directive, comprehensive documentation block, and parameter validation using ValidateScript are appropriate for an ISO build tool.


53-108: LGTM! Utility functions and ADK discovery logic are solid.

The fallback to registry lookup for Windows ADK path and the user-friendly error message with installation link are helpful. The colored output functions provide good UX.


175-199: LGTM! File placement follows project requirements.

The script correctly places autounattend.xml at the ISO root and populates $OEM$\$$\Setup with bootstrap.ps1, apps.json, and Sophia-Preset.ps1 as specified in the coding guidelines.

bootstrap.ps1 (5)

1-28: LGTM! Script configuration and initialization are well-structured.

The #Requires -RunAsAdministrator directive, documentation block stating idempotency, and configuration paths align with the coding guidelines requiring logs at C:\Setup\install.log.


30-89: LGTM! Logging and summary functions meet requirements.

The implementation produces logs at C:\Setup\install.log and desktop summary at Setup Summary.txt as specified in the coding guidelines.


91-138: LGTM! Robust network connectivity check.

The multi-layered approach with ICMP ping fallback to HTTPS checks, command availability detection, and configurable timeout provides reliable network detection in various environments.


217-284: LGTM! WinGet import logic is idempotent.

The implementation correctly checks for already-installed packages and only imports missing ones, satisfying the idempotency requirement from the coding guidelines. Error handling and summary reporting are comprehensive.


314-349: LGTM! Desktop assets creation meets requirements.

The desktop shortcut for re-running bootstrap and the summary report generation fulfill the coding guidelines for providing a manual re-run option and desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt.

Comment thread build-iso.ps1
Copy link
Copy Markdown

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

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: 02079a434f

ℹ️ 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 build-iso.ps1 Outdated
@Timpan4 Timpan4 force-pushed the feat-add-iso-build-script branch from 02079a4 to 0e6a832 Compare January 11, 2026 12:47
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @bootstrap.ps1:
- Around line 158-167: In Test-WingetPackageInstalled, remove the early exit
that returns $false when $LASTEXITCODE -ne 0 and instead rely solely on matching
the captured winget output ($result) against the escaped package id; keep the
existing STDERR redirection (2>&1) so warnings/errors are included in $result,
and return the boolean of ($result -match [regex]::Escape($PackageId)) as the
authoritative presence check.

In @README.md:
- Around line 9-13: The README shows MVP scripts as implemented but the Project
Structure still labels bootstrap.ps1 and build-iso.ps1 as "(planned)"; update
the Project Structure entries for bootstrap.ps1 and build-iso.ps1 to remove the
"(planned)" label and ensure the MVP Workflow section and any mentions in lines
26-35 and 137-138 reflect that these scripts exist and include the concrete
usage examples already present (i.e., remove the planned marker and keep the
existing usage text for bootstrap.ps1 and build-iso.ps1).
🧹 Nitpick comments (4)
bootstrap.ps1 (4)

22-22: Consider using "Stop" ErrorActionPreference for more reliable error detection.

Setting $ErrorActionPreference = "Continue" allows the script to proceed even when cmdlets encounter errors, which might mask critical failures. Since the script already uses comprehensive try-catch blocks for error handling (lines 223, 271, 290, 304, 319, 332, 337, 352), consider using "Stop" to ensure errors are properly caught and logged.

♻️ Proposed adjustment
-$ErrorActionPreference = "Continue"
+$ErrorActionPreference = "Stop"

140-156: Consider adding structure validation for robustness.

While the function correctly parses the winget import JSON format, it assumes the structure is valid (e.g., $data.Sources exists and is enumerable). Since the caller (line 231) has try-catch protection, this is acceptable, but adding a null check for $data.Sources could improve error messages.

♻️ Optional defensive check
 function Get-WingetPackageIdsFromJson {
     param([string]$Path)
 
     $content = Get-Content -Path $Path -Raw
     $data = $content | ConvertFrom-Json
+    
+    if (-not $data.Sources) {
+        return @()
+    }
+    
     $packageIds = @()
 
     foreach ($source in $data.Sources) {

203-209: Optional: Remove redundant administrator check.

The manual admin check on lines 204-208 is redundant with the #Requires -RunAsAdministrator directive on line 1, which already prevents the script from executing without admin privileges. While harmless, removing this check would reduce code duplication.

♻️ Optional simplification
-    # Verify admin privileges
-    $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
-    if (-not $isAdmin) {
-        Write-Log "ERROR: This script must be run as Administrator" -Level ERROR
-        exit 1
-    }
     Write-Log "Administrator privileges verified" -Level SUCCESS

320-327: Use dynamic script path for better portability.

The shortcut currently hardcodes the script path as C:\Setup\bootstrap.ps1 (line 324). If the script is moved or copied to a different location, the shortcut will break. Consider using $PSCommandPath to reference the current script's location dynamically.

♻️ Proposed enhancement for portability
         $shortcutPath = Join-Path $desktopPath "Run Windows Setup.lnk"
         $shell = New-Object -ComObject WScript.Shell
         $shortcut = $shell.CreateShortcut($shortcutPath)
         $shortcut.TargetPath = "powershell.exe"
-        $shortcut.Arguments = "-ExecutionPolicy Bypass -File C:\Setup\bootstrap.ps1"
-        $shortcut.WorkingDirectory = "C:\Setup"
+        $shortcut.Arguments = "-ExecutionPolicy Bypass -File `"$PSCommandPath`""
+        $shortcut.WorkingDirectory = Split-Path -Parent $PSCommandPath
         $shortcut.Description = "Re-run declarative Windows setup"
         $shortcut.Save()
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02079a4 and 0e6a832.

📒 Files selected for processing (5)
  • CLAUDE.md
  • FAQ.md
  • README.md
  • bootstrap.ps1
  • build-iso.ps1
🚧 Files skipped from review as they are similar to previous changes (1)
  • build-iso.ps1
🧰 Additional context used
📓 Path-based instructions (3)
{README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md}

📄 CodeRabbit inference engine (CLAUDE.md)

All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support

Files:

  • CLAUDE.md
  • README.md
**/*.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ps1: Do not create any PowerShell scripts (.ps1) during the planning phase
All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Files:

  • bootstrap.ps1
bootstrap.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

bootstrap.ps1: bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
bootstrap.ps1 must produce logs: Desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
Provide a desktop shortcut to re-run bootstrap.ps1 manually

Files:

  • bootstrap.ps1
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {autounattend.xml,apps.json,config/**/*.json} : All configuration files must assume Windows 11 (22H2+) only; do not include Windows 10 compatibility logic
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : Do not create any PowerShell scripts (.ps1) during the planning phase

Applied to files:

  • FAQ.md
  • CLAUDE.md
  • README.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step

Applied to files:

  • FAQ.md
  • bootstrap.ps1
  • README.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: During planning, only work on documentation, planning/design docs, and configuration schemas/examples

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to {README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md} : All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : Provide a desktop shortcut to re-run bootstrap.ps1 manually

Applied to files:

  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Applied to files:

  • bootstrap.ps1
  • README.md
🔇 Additional comments (15)
FAQ.md (1)

9-9: LGTM!

Status update accurately reflects the project transition to Implementation Phase with appropriate references to MVP scripts.

README.md (1)

148-152: Windows version support is correctly documented.

The file properly restricts scope to Windows 11 (22H2+) and explicitly excludes Windows 10 support, aligning with project guidelines and documentation requirements.

CLAUDE.md (4)

5-15: Phase transition properly documented.

The project phase is clearly updated from planning to implementation, with explicit identification of the two MVP scripts being built (bootstrap.ps1 and build-iso.ps1) and acknowledgment that configuration files are already in place.


19-25: Windows 11 (22H2+) requirement is clearly established.

The Windows Version Support section properly restricts scope to Windows 11 exclusively and explicitly excludes Windows 10 support. This aligns with project documentation guidelines.


99-111: ISO structure correctly documents file placement requirements.

The ISO structure diagram accurately reflects the required file layout:

  • autounattend.xml at root (line 104)
  • bootstrap.ps1, apps.json, and Sophia.ps1 in $OEM$\$$\Setup directory (lines 108-110)

This aligns with the specified build-iso.ps1 behavior.


142-158: Idempotency and logging requirements are properly documented.

The Key Features section correctly documents that bootstrap.ps1 is idempotent (safe to run multiple times with status reporting) and produces the required dual-location logging:

  • Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt
  • Detailed log at C:\Setup\install.log

This aligns with established requirements for the bootstrap script.

bootstrap.ps1 (9)

1-19: LGTM! Well-structured script header.

The #Requires -RunAsAdministrator directive ensures proper elevation, and the comment-based help clearly documents the script's purpose and idempotent design.


30-52: LGTM! Robust logging implementation.

The centralized logging with color-coded console output and file persistence provides excellent observability. The use of -ErrorAction SilentlyContinue on file writes prevents logging failures from disrupting the setup process.


54-71: LGTM! Clean summary tracking mechanism.

The function provides a straightforward way to collect step results for the final report. Using a generic list and PSCustomObject is efficient and idiomatic for PowerShell.


73-89: LGTM! Meets desktop summary requirement.

The function correctly writes the summary report to the user's desktop as specified in the coding guidelines. The format is clear and includes all necessary information.

As per coding guidelines, this implementation aligns with the requirement to produce a summary at C:\Users\[User]\Desktop\Setup Summary.txt.


91-138: LGTM! Comprehensive network connectivity check.

The multi-method approach (ICMP ping to multiple targets, fallback HTTPS checks) with cmdlet availability detection ensures robust network readiness validation across different system configurations. The 300-second timeout is reasonable for post-installation network initialization.


169-195: LGTM! Effective JSON filtering preserves winget import structure.

The function correctly filters packages while maintaining the required JSON structure, including the schema reference and source details. The depth of 10 for JSON serialization should accommodate typical package configurations.


217-284: LGTM! Excellent idempotency implementation.

The WinGet step correctly implements idempotency by checking for already-installed packages before attempting installation (lines 240-244), which aligns with the coding guidelines. The network wait, error handling, and temp file cleanup (finally block) are all well-designed.

The interpretation of winget exit codes (lines 259-266) as either success (0) or warning (non-zero) is pragmatic, though be aware that winget can return various exit codes that may represent different severity levels.

As per coding guidelines, this implementation fulfills the requirement for bootstrap.ps1 to be idempotent.


286-312: LGTM! Appropriate external script execution.

The Sophia Script execution handles both exit code scenarios and exceptions appropriately. Checking for $null -eq $LASTEXITCODE (line 296) is important since not all PowerShell scripts set an explicit exit code.


345-356: LGTM! Robust completion and error handling.

The final logging banner and top-level exception handler with stack trace capture (line 354) provide excellent observability for troubleshooting setup failures.

Comment thread bootstrap.ps1
Comment on lines +158 to +167
function Test-WingetPackageInstalled {
param([string]$PackageId)

$result = winget list --id $PackageId --exact 2>&1
if ($LASTEXITCODE -ne 0) {
return $false
}

return $result -match [regex]::Escape($PackageId)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix potential false negatives in package detection.

The early return on line 162-164 when $LASTEXITCODE -ne 0 can cause false negatives. winget list may return non-zero exit codes even when the package is found (e.g., when package metadata has issues or minor warnings occur). The regex match on line 166 is the authoritative check.

Removing the exit code early-return and relying solely on the regex match will improve idempotency by preventing unnecessary reinstallation attempts.

🐛 Proposed fix to rely on output matching
 function Test-WingetPackageInstalled {
     param([string]$PackageId)
 
     $result = winget list --id $PackageId --exact 2>&1
-    if ($LASTEXITCODE -ne 0) {
-        return $false
-    }
 
     return $result -match [regex]::Escape($PackageId)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function Test-WingetPackageInstalled {
param([string]$PackageId)
$result = winget list --id $PackageId --exact 2>&1
if ($LASTEXITCODE -ne 0) {
return $false
}
return $result -match [regex]::Escape($PackageId)
}
function Test-WingetPackageInstalled {
param([string]$PackageId)
$result = winget list --id $PackageId --exact 2>&1
return $result -match [regex]::Escape($PackageId)
}
🤖 Prompt for AI Agents
In @bootstrap.ps1 around lines 158 - 167, In Test-WingetPackageInstalled, remove
the early exit that returns $false when $LASTEXITCODE -ne 0 and instead rely
solely on matching the captured winget output ($result) against the escaped
package id; keep the existing STDERR redirection (2>&1) so warnings/errors are
included in $result, and return the boolean of ($result -match
[regex]::Escape($PackageId)) as the authoritative presence check.

Comment thread README.md
Comment on lines +9 to +13
## ⚠️ Project Status: Implementation Phase

**No scripts exist yet.** This is currently planning and documentation.
**MVP scripts exist** (`bootstrap.ps1`, `build-iso.ps1`) and are in active development.

See [TODO.md](TODO.md) for implementation tasks.
See [TODO.md](TODO.md) for remaining implementation tasks.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Resolve inconsistency: Project status vs. Project Structure labels.

Lines 9-13 and the MVP Workflow section (lines 26-35) indicate that MVP scripts exist and are operational with concrete usage examples. However, the Project Structure section (lines 137-138) still labels both bootstrap.ps1 and build-iso.ps1 with (planned), suggesting they are not yet implemented.

Update lines 137-138 to remove the (planned) labels and align them with the project status:

🔧 Proposed fix
 ├── apps.json              # Your WinGet package list (create this)
 ├── Sophia-Preset.ps1      # Custom Sophia Script configuration
 ├── autounattend.xml       # Windows unattended install config
-├── bootstrap.ps1          # Main orchestration script (planned)
-├── build-iso.ps1          # ISO generation script (planned)
+├── bootstrap.ps1          # Main orchestration script
+├── build-iso.ps1          # ISO generation script

Also applies to: 26-35, 137-138

🤖 Prompt for AI Agents
In @README.md around lines 9 - 13, The README shows MVP scripts as implemented
but the Project Structure still labels bootstrap.ps1 and build-iso.ps1 as
"(planned)"; update the Project Structure entries for bootstrap.ps1 and
build-iso.ps1 to remove the "(planned)" label and ensure the MVP Workflow
section and any mentions in lines 26-35 and 137-138 reflect that these scripts
exist and include the concrete usage examples already present (i.e., remove the
planned marker and keep the existing usage text for bootstrap.ps1 and
build-iso.ps1).

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