# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Repository Information **Git Repository:** https://git.farmtowntech.com/setonc/build-pe-script-launcher **Branch:** master **Status:** Active development ```powershell # Clone the repository git clone https://git.farmtowntech.com/setonc/build-pe-script-launcher.git ``` ## Project Overview Build PE Script Launcher - A production-grade Windows PE builder that creates bootable images with PowerShell 7, custom modules, and automatic script launching from external media. The PE image remains static; rebuilds are only needed for PowerShell 7 or module updates. ## Quick Start ```powershell # Clone and build .\Build-PE.ps1 # Update PowerShell modules (optional) .\Update-Modules.ps1 # Test the ISO in a VM # Boot WinPE.iso with external media containing .scripts folder ``` ## Architecture ### Core Components **Build-PE.ps1** - Main orchestrator - Validates dependencies (auto-installs Windows ADK if missing) - Downloads PowerShell 7 if needed - Mounts WinPE image via DISM - Integrates PowerShell 7 and modules - Injects launcher scripts - Creates bootable ISO **config.json** - Configuration - PowerShell modules list - Target script name - Scripts folder name - PowerShell 7 version and download URL **lib/** - Build modules - `Dependencies.psm1` - ADK validation and auto-installation - `WinPEBuilder.psm1` - DISM operations (mount, unmount, add packages) - `PowerShell7.psm1` - PS7 extraction and integration - `ModuleManager.psm1` - Module copying to WinPE image **resources/** - Runtime scripts - `Invoke-ScriptLauncher.ps1` - Runs on PE boot, scans for external media - `Invoke-ScriptMenu.ps1` - Fallback menu for local .scripts folder **modules/** - PowerShell modules - Pre-downloaded modules from PSGallery - Committed to repository for offline builds - Updated via `Update-Modules.ps1` ### Boot Flow ``` WinPE Boot ↓ startnet.cmd (modified) ↓ Console window maximizes automatically ↓ Invoke-ScriptLauncher.ps1 (PowerShell 7) ↓ Scans all drives for .scripts folder ↓ ├─ Found on external media? │ ↓ │ Execute configured target script │ (e.g., user's custom Invoke-ScriptMenu.ps1) │ └─ Not found? ↓ Check for local X:\.scripts ↓ ├─ Found? → Launch Invoke-ScriptMenu.ps1 └─ Not found? → Show instructions, drop to PowerShell 7 prompt ``` **Console Features:** - **PowerShell 7 by default** - All scripts and the command prompt use PS7 - **Maximized window** - Console automatically maximizes on boot for full-screen experience - **Elevated privileges** - Everything runs as SYSTEM (no UAC in WinPE) - **Classic UI** - WinPE uses legacy console rendering (no modern W10/W11 decorations available) ### Build Process Workflow 1. **Dependency Check** - Validates admin rights, ADK installation, PS7 availability 2. **Workspace Init** - Creates work directory using ADK's copype.cmd 3. **Mount Image** - Mounts boot.wim for modification 4. **Add Components** - Installs WinPE optional components (WMI, NetFX, PowerShell, etc.) 5. **Install PS7** - Extracts PowerShell 7 to `Program Files\PowerShell\7` 6. **Copy Modules** - Copies modules from repository to image 7. **Inject Scripts** - Copies launcher and menu scripts to System32 8. **Configure Startup** - Modifies startnet.cmd to run launcher 9. **Unmount** - Commits changes and unmounts image 10. **Create ISO** - Generates bootable ISO using MakeWinPEMedia ## Configuration ### config.json Structure ```json { "powershellModules": ["ModuleName1", "ModuleName2"], "targetScript": "Invoke-ScriptMenu.ps1", "scriptsFolder": ".scripts", "startupScript": "Invoke-ScriptLauncher.ps1", "fallbackScript": "Invoke-ScriptMenu.ps1", "consoleColors": { "backgroundColor": "Black", "foregroundColor": "Gray" }, "powershell7Version": "7.4.13", "powershell7ZipUrl": "https://github.com/PowerShell/PowerShell/releases/..." } ``` **Configuration Options:** **powershellModules** - Array of module names to include in WinPE (from PSGallery) **targetScript** - Script name to execute from external media .scripts folder **scriptsFolder** - Name of folder to search for on external media (default: ".scripts") **startupScript** - Script that runs first on boot (default: "Invoke-ScriptLauncher.ps1") - Must exist in resources/ folder - This is the entry point for your WinPE environment **fallbackScript** - Script embedded in image for offline/local use (default: "Invoke-ScriptMenu.ps1") - Must exist in resources/ folder - Runs when no external media is found but X:\.scripts exists **consoleColors** - Customize PowerShell console appearance - backgroundColor: Console background color (Black, DarkBlue, DarkGreen, etc.) - foregroundColor: Console text color (Gray, White, Cyan, etc.) **powershell7Version** - Version of PowerShell 7 to integrate **powershell7ZipUrl** - Direct download URL for PS7 zip archive ## Commands ### Build WinPE Image ```powershell .\Build-PE.ps1 ``` First run downloads Windows ADK (~4GB, 20-30 min), subsequent builds are faster (~10 min). Options: - `-CleanBuild` - Remove existing work directory - `-SkipADKCheck` - Skip ADK validation (not recommended) - `-DefenderOptimization ` - Optimize Windows Defender for faster builds (see Performance Optimization below) ### Build with Performance Optimization Windows Defender real-time scanning significantly impacts DISM performance. Use `-DefenderOptimization` for faster builds: ```powershell # Fastest: Temporarily disable real-time protection (50-70% improvement) .\Build-PE.ps1 -DefenderOptimization DisableRealTime # Balanced: Add build directories to exclusions (20-30% improvement) .\Build-PE.ps1 -DefenderOptimization AddExclusions # Default: No Defender changes (safest) .\Build-PE.ps1 -DefenderOptimization None ``` **Defender optimization modes:** - `None` (default) - No changes to Defender, safest option - `DisableRealTime` - Temporarily disable real-time protection for build duration, restored automatically (fastest) - `AddExclusions` - Add build directories and ADK paths to Defender exclusions, removed after build (balanced) **Note:** Defender settings are automatically restored when the build completes, even if it fails. ### Update Modules ```powershell # Update all modules in config.json .\Update-Modules.ps1 # Update specific module .\Update-Modules.ps1 -ModuleName "PSWindowsUpdate" # Force re-download .\Update-Modules.ps1 -ModuleName "PSWindowsUpdate" -Force ``` ## Directory Structure ``` Build PE Script Launcher/ ├── Build-PE.ps1 # Main build script ├── Update-Modules.ps1 # Module updater utility ├── config.json # Build configuration ├── lib/ # Build-time modules │ ├── Dependencies.psm1 │ ├── WinPEBuilder.psm1 │ ├── PowerShell7.psm1 │ ├── ModuleManager.psm1 │ └── DefenderOptimization.psm1 ├── resources/ # Runtime scripts │ ├── Invoke-ScriptLauncher.ps1 │ └── Invoke-ScriptMenu.ps1 ├── modules/ # PowerShell modules (committed) │ └── / ├── work/ # Build workspace (gitignored) │ ├── mount/ # Mounted WinPE image │ └── media/ # WinPE media files └── output/ # Build outputs (gitignored) ├── WinPE.iso └── build.log ``` ## Key Technical Details ### Windows ADK Integration - Auto-installs via silent parameters: `/quiet /norestart /features OptionId.DeploymentTools` - Installs both ADK core and WinPE add-on - Uses `copype.cmd` to create initial WinPE workspace - Uses `MakeWinPEMedia.cmd` to create bootable ISO ### PowerShell 7 Integration - Based on community method (not officially supported by Microsoft) - Extracts PS7 portable zip to `X:\Program Files\PowerShell\7` - Modifies startnet.cmd to add PS7 to PATH - Uses PowerShell 7 LTS (v7.4.13) for 3-year support ### DISM Operations All image modifications use DISM commands: - Mount: `dism /Mount-Image /ImageFile:boot.wim /Index:1 /MountDir:mount` - Add package: `dism /Add-Package /Image:mount /PackagePath:package.cab` - Unmount: `dism /Unmount-Image /MountDir:mount /Commit` ### Module Management - Modules stored in `modules/` using `Save-Module` structure - Copied to `X:\Program Files\WindowsPowerShell\Modules\` in image - Dependencies automatically resolved by `Update-Modules.ps1` ## Troubleshooting ### Build fails with "Image is already mounted" ```powershell dism /Cleanup-Mountpoints ``` ### ADK installation fails - Check internet connection - Ensure sufficient disk space (~10GB) - Run as Administrator ### Module not found during build ```powershell # Download missing module .\Update-Modules.ps1 -ModuleName "ModuleName" # Or verify config.json module names match PSGallery exactly ``` ### PowerShell 7 not in PATH when PE boots - Check startnet.cmd modification in mounted image - Verify PS7 extracted to correct path - Review build.log for errors ## Modifying the Project ### Adding a New Module 1. Add module name to `config.json` powershellModules array 2. Run `.\Update-Modules.ps1 -ModuleName "NewModule"` 3. Rebuild: `.\Build-PE.ps1` ### Changing Scripts **External Media Script (runs from USB/external drive):** 1. Modify `targetScript` in `config.json` 2. Ensure your script exists in external media's .scripts folder 3. Rebuild: `.\Build-PE.ps1` **Startup Script (first script that runs on boot):** 1. Create your custom script in `resources/` folder 2. Update `startupScript` in `config.json` with your script name 3. Rebuild: `.\Build-PE.ps1` 4. Script must handle external media detection or call other scripts **Fallback Script (embedded for offline use):** 1. Create your custom script in `resources/` folder 2. Update `fallbackScript` in `config.json` with your script name 3. Rebuild: `.\Build-PE.ps1` 4. Script will be available at X:\Windows\System32\ when no external media found ### Customizing Console Colors 1. Edit `consoleColors` in `config.json` 2. Choose from: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White 3. Rebuild: `.\Build-PE.ps1` Example - Dark blue theme: ```json "consoleColors": { "backgroundColor": "DarkBlue", "foregroundColor": "White" } ``` ### Upgrading PowerShell 7 1. Update `powershell7Version` and `powershell7ZipUrl` in config.json 2. Delete old PowerShell zip file 3. Rebuild: `.\Build-PE.ps1` ### Customizing Launcher Behavior Edit `resources/Invoke-ScriptLauncher.ps1`: - Change drive scanning logic - Modify error messages - Add additional checks - Customize banner display ## Use Cases ### Driver Extraction from Offline Windows User boots WinPE → Launcher finds .scripts on USB → Runs driver export script ### System Recovery Scripts Multiple recovery scripts on external media → Menu lets user choose → Script runs with PS7 and modules available ### Automated Deployment Pre-configured script on known media → Launcher auto-executes → Unattended deployment ## External Media Setup ### For End Users 1. Format USB drive 2. Create `.scripts` folder in root 3. Add target script (e.g., `Invoke-ScriptMenu.ps1`) 4. Add additional scripts 5. Boot WinPE image ### Example .scripts Structure ``` USB:\ └── .scripts\ ├── Invoke-ScriptMenu.ps1 # Entry point ├── Export-Drivers.ps1 ├── Backup-System.ps1 └── utilities\ └── helpers.psm1 ``` ## Performance Notes ### Build Times (without optimization) - First build: 30-45 minutes (ADK download + install) - Subsequent builds: 5-10 minutes - ISO size: ~500MB - Module impact: ~10-50MB per module typically ### Windows Defender Optimization Windows Defender real-time scanning significantly impacts DISM and ADK performance. Use `-DefenderOptimization` for dramatic speed improvements: **Performance Impact by Mode:** | Mode | First Build | Subsequent | Improvement | Risk Level | |------|-------------|------------|-------------|------------| | None (default) | 30-45 min | 5-10 min | Baseline | Safest | | AddExclusions | 24-32 min | 4-7 min | 20-30% faster | Low | | DisableRealTime | 15-20 min | 2-4 min | 50-70% faster | Low* | *DisableRealTime temporarily disables protection but automatically restores it when build completes (even on failure). **Which mode to use:** - **Development:** Use `DisableRealTime` for fastest builds - **CI/CD pipelines:** Use `AddExclusions` for good performance with minimal risk - **Production/Shared systems:** Use `None` (default) for safety - **Enterprise:** Use `AddExclusions` with approval from security team **How it works:** - `DisableRealTime` - Temporarily disables Windows Defender real-time protection during build, restores original state when done - `AddExclusions` - Adds work/, downloads/, output/, and ADK paths to Defender exclusions during build, removes them when done - `None` - No changes to Defender (default behavior) All Defender changes are automatically reverted when the build completes, even if the build fails. ## Security Considerations - Scripts run with SYSTEM privileges in WinPE - No execution policy restrictions - Only use trusted scripts - Validate all external media scripts before use - Consider signing scripts for enterprise deployment - **Defender Optimization:** When using `-DefenderOptimization`, Defender settings are automatically restored after build. Even if build fails, the finally block ensures restoration. Safe for development use. ## Known Limitations - PowerShell 7 in WinPE is unofficial (works but unsupported) - Some cmdlets (Get-PhysicalDisk) may not work under PS7 in WinPE - UAC not present in WinPE (all scripts run elevated) - Network drivers may need manual addition for some hardware - **UI Limitations:** - Console uses legacy Windows console rendering (no modern W10/W11 window decorations) - WinPE lacks DWM (Desktop Window Manager) and modern shell components - True borderless fullscreen not available; window maximization is the best alternative - No Aero, Fluent Design, or modern theming support