14 KiB
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
# 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
# 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-installationWinPEBuilder.psm1- DISM operations (mount, unmount, add packages)PowerShell7.psm1- PS7 extraction and integrationModuleManager.psm1- Module copying to WinPE image
resources/ - Runtime scripts
Invoke-ScriptLauncher.ps1- Runs on PE boot, scans for external mediaInvoke-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
- Dependency Check - Validates admin rights, ADK installation, PS7 availability
- Workspace Init - Creates work directory using ADK's copype.cmd
- Mount Image - Mounts boot.wim for modification
- Add Components - Installs WinPE optional components (WMI, NetFX, PowerShell, etc.)
- Install PS7 - Extracts PowerShell 7 to
Program Files\PowerShell\7 - Copy Modules - Copies modules from repository to image
- Inject Scripts - Copies launcher and menu scripts to System32
- Configure Startup - Modifies startnet.cmd to run launcher
- Unmount - Commits changes and unmounts image
- Create ISO - Generates bootable ISO using MakeWinPEMedia
Configuration
config.json Structure
{
"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
.\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 <Mode>- 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:
# 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 optionDisableRealTime- 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
# 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)
│ └── <ModuleName>/
├── 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.cmdto create initial WinPE workspace - Uses
MakeWinPEMedia.cmdto 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/usingSave-Modulestructure - Copied to
X:\Program Files\WindowsPowerShell\Modules\in image - Dependencies automatically resolved by
Update-Modules.ps1
Troubleshooting
Build fails with "Image is already mounted"
dism /Cleanup-Mountpoints
ADK installation fails
- Check internet connection
- Ensure sufficient disk space (~10GB)
- Run as Administrator
Module not found during build
# 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
- Add module name to
config.jsonpowershellModules array - Run
.\Update-Modules.ps1 -ModuleName "NewModule" - Rebuild:
.\Build-PE.ps1
Changing Scripts
External Media Script (runs from USB/external drive):
- Modify
targetScriptinconfig.json - Ensure your script exists in external media's .scripts folder
- Rebuild:
.\Build-PE.ps1
Startup Script (first script that runs on boot):
- Create your custom script in
resources/folder - Update
startupScriptinconfig.jsonwith your script name - Rebuild:
.\Build-PE.ps1 - Script must handle external media detection or call other scripts
Fallback Script (embedded for offline use):
- Create your custom script in
resources/folder - Update
fallbackScriptinconfig.jsonwith your script name - Rebuild:
.\Build-PE.ps1 - Script will be available at X:\Windows\System32\ when no external media found
Customizing Console Colors
- Edit
consoleColorsinconfig.json - Choose from: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White
- Rebuild:
.\Build-PE.ps1
Example - Dark blue theme:
"consoleColors": {
"backgroundColor": "DarkBlue",
"foregroundColor": "White"
}
Upgrading PowerShell 7
- Update
powershell7Versionandpowershell7ZipUrlin config.json - Delete old PowerShell zip file
- 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
- Format USB drive
- Create
.scriptsfolder in root - Add target script (e.g.,
Invoke-ScriptMenu.ps1) - Add additional scripts
- 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
DisableRealTimefor fastest builds - CI/CD pipelines: Use
AddExclusionsfor good performance with minimal risk - Production/Shared systems: Use
None(default) for safety - Enterprise: Use
AddExclusionswith approval from security team
How it works:
DisableRealTime- Temporarily disables Windows Defender real-time protection during build, restores original state when doneAddExclusions- Adds work/, downloads/, output/, and ADK paths to Defender exclusions during build, removes them when doneNone- 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