Production-grade Windows PE builder with PowerShell 7 integration. Features: - PowerShell 7 integrated into WinPE environment - Automatic script launcher for external media - Configurable startup and fallback scripts - Custom console colors - Maximized console window on boot - PowerShell module integration - Windows ADK auto-installation - Defender optimization for faster builds Project Structure: - Build-PE.ps1: Main build orchestrator - config.json: Configuration file - lib/: Build modules (Dependencies, WinPEBuilder, PowerShell7, ModuleManager, DefenderOptimization) - resources/: Runtime scripts (Invoke-ScriptLauncher, Invoke-ScriptMenu, Driver-Manager) - CLAUDE.md: Complete project documentation - README.md: Quick start guide Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
416 lines
14 KiB
Markdown
416 lines
14 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## 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 <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:
|
|
|
|
```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)
|
|
│ └── <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.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
|