build-pe-script-launcher/resources/Invoke-ScriptLauncher.ps1
Claude b06374a562 Initial commit: Build PE Script Launcher
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>
2026-01-12 16:39:43 -05:00

239 lines
7.8 KiB
PowerShell

<#
.SYNOPSIS
WinPE Script Launcher - Automatically detects and runs scripts from external media.
.DESCRIPTION
This script runs automatically when WinPE boots. It scans all available drives
for a .scripts folder on the root, then executes the configured target script.
#>
$ErrorActionPreference = "Continue"
# Load configuration from WinPE image
$ConfigPath = "X:\Windows\System32\winpe-config.json"
$Config = $null
if (Test-Path $ConfigPath) {
try {
$Config = Get-Content $ConfigPath -Raw | ConvertFrom-Json
$ScriptsFolder = $Config.scriptsFolder
$TargetScript = $Config.targetScript
$FallbackScript = $Config.fallbackScript
}
catch {
Write-Warning "Failed to load config, using defaults"
$ScriptsFolder = ".scripts"
$TargetScript = "Invoke-ScriptMenu.ps1"
$FallbackScript = "Invoke-ScriptMenu.ps1"
}
}
else {
# Fallback to defaults if config not found
$ScriptsFolder = ".scripts"
$TargetScript = "Invoke-ScriptMenu.ps1"
$FallbackScript = "Invoke-ScriptMenu.ps1"
}
# Apply console customizations
try {
$host.UI.RawUI.WindowTitle = 'WinPE Script Launcher - PowerShell 7'
# Set console colors if configured
if ($Config -and $Config.consoleColors) {
if ($Config.consoleColors.backgroundColor) {
$host.UI.RawUI.BackgroundColor = $Config.consoleColors.backgroundColor
}
if ($Config.consoleColors.foregroundColor) {
$host.UI.RawUI.ForegroundColor = $Config.consoleColors.foregroundColor
}
Clear-Host # Apply color changes
}
# Get console window handle and maximize it
Add-Type -MemberDefinition @'
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
'@ -Name Console -Namespace Win32 -PassThru -ErrorAction SilentlyContinue | Out-Null
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public class User32 {
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
'@ -ErrorAction SilentlyContinue
$consoleWindow = [Win32.Console]::GetConsoleWindow()
$SW_MAXIMIZE = 3
[User32]::ShowWindow($consoleWindow, $SW_MAXIMIZE) | Out-Null
}
catch {
# Silently continue if window manipulation fails
}
function Write-Banner {
Write-Host ""
Write-Host "=============================================" -ForegroundColor Cyan
Write-Host " WinPE Script Launcher v1.0" -ForegroundColor White
Write-Host "=============================================" -ForegroundColor Cyan
Write-Host ""
}
function Find-ScriptsFolder {
param(
[string]$FolderName
)
Write-Host "Scanning drives for [$FolderName] folder..." -ForegroundColor Yellow
Write-Host ""
Start-Sleep -Seconds 2
try {
$drives = Get-PSDrive -PSProvider FileSystem -ErrorAction SilentlyContinue |
Where-Object { $_.Used -gt 0 -and $_.Root -ne "X:\" }
if (-not $drives) {
Write-Warning "No drives found with content"
return $null
}
foreach ($drive in $drives) {
$testPath = Join-Path $drive.Root $FolderName
Write-Host " Checking $($drive.Root)..." -ForegroundColor Cyan
if (Test-Path $testPath) {
Write-Host " [FOUND] $testPath" -ForegroundColor Green
Write-Host ""
return $testPath
}
}
Write-Host ""
Write-Warning "No [$FolderName] folder found on any drive"
return $null
}
catch {
Write-Error "Error scanning drives: $_"
return $null
}
}
function Invoke-TargetScript {
param(
[string]$ScriptsPath,
[string]$ScriptName
)
$scriptPath = Join-Path $ScriptsPath $ScriptName
if (-not (Test-Path $scriptPath)) {
Write-Error "Target script not found: $scriptPath"
Write-Host ""
Write-Host "Expected script: $ScriptName" -ForegroundColor Yellow
Write-Host "Scripts folder: $ScriptsPath" -ForegroundColor Yellow
Write-Host ""
Write-Host "Available files in scripts folder:" -ForegroundColor Cyan
try {
Get-ChildItem -Path $ScriptsPath -File | ForEach-Object {
Write-Host " - $($_.Name)" -ForegroundColor White
}
}
catch {
Write-Warning "Could not list files in scripts folder"
}
return $false
}
Write-Host "Executing: $scriptPath" -ForegroundColor Green
Write-Host ""
Write-Host "-------------------------------------------" -ForegroundColor DarkGray
Write-Host ""
try {
Push-Location $ScriptsPath
& $scriptPath
Pop-Location
Write-Host ""
Write-Host "-------------------------------------------" -ForegroundColor DarkGray
Write-Host "Script execution completed" -ForegroundColor Green
return $true
}
catch {
Pop-Location
Write-Error "Script execution failed: $_"
return $false
}
}
Write-Banner
$scriptsPath = Find-ScriptsFolder -FolderName $ScriptsFolder
if ($scriptsPath) {
Write-Host "Scripts folder located at: $scriptsPath" -ForegroundColor Green
Write-Host ""
$success = Invoke-TargetScript -ScriptsPath $scriptsPath -ScriptName $TargetScript
if (-not $success) {
Write-Host ""
Write-Host "Press any key to continue to command prompt..." -ForegroundColor Yellow
$null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}
else {
Write-Host ""
Write-Host "=============================================" -ForegroundColor Yellow
Write-Host " No external scripts found" -ForegroundColor Yellow
Write-Host "=============================================" -ForegroundColor Yellow
Write-Host ""
$localScriptsPath = "X:\$ScriptsFolder"
if (Test-Path $localScriptsPath) {
Write-Host "Found local scripts folder on WinPE image" -ForegroundColor Green
Write-Host "Launching built-in fallback script..." -ForegroundColor Cyan
Write-Host ""
Start-Sleep -Seconds 1
$fallbackScriptPath = "X:\Windows\System32\$FallbackScript"
if (Test-Path $fallbackScriptPath) {
try {
& $fallbackScriptPath -ScriptsPath $localScriptsPath
}
catch {
Write-Error "Failed to launch fallback script: $_"
Write-Host ""
Write-Host "Press any key to continue to command prompt..." -ForegroundColor Yellow
$null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}
else {
Write-Warning "Fallback script not found in WinPE image: $FallbackScript"
Write-Host ""
Write-Host "Press any key to continue to command prompt..." -ForegroundColor Yellow
$null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}
else {
Write-Host "To use this WinPE environment:" -ForegroundColor White
Write-Host " 1. Insert USB drive or external media" -ForegroundColor Cyan
Write-Host " 2. Create folder: [$ScriptsFolder] in root" -ForegroundColor Cyan
Write-Host " 3. Add script: [$TargetScript]" -ForegroundColor Cyan
Write-Host " 4. Reboot or run this launcher again" -ForegroundColor Cyan
Write-Host ""
Write-Host "OR" -ForegroundColor Yellow
Write-Host ""
Write-Host " Create folder: X:\$ScriptsFolder on this WinPE image" -ForegroundColor Cyan
Write-Host " Add your scripts and run this launcher again" -ForegroundColor Cyan
Write-Host ""
Write-Host "Press any key to continue to command prompt..." -ForegroundColor Yellow
$null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}