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>
252 lines
6.5 KiB
PowerShell
252 lines
6.5 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Built-in Script Menu for WinPE Script Launcher
|
|
.DESCRIPTION
|
|
Discovers and executes scripts from a .scripts folder. This is a simplified
|
|
version designed for WinPE environments without UAC elevation requirements.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$ScriptsPath = ".scripts"
|
|
)
|
|
|
|
$Script:SupportedExtensions = @('.ps1', '.bat', '.cmd')
|
|
$Script:ExitCode = 0
|
|
|
|
function Write-Header {
|
|
param([string]$Title)
|
|
|
|
$width = 70
|
|
Write-Host ""
|
|
Write-Host ("=" * $width) -ForegroundColor Cyan
|
|
Write-Host " $Title" -ForegroundColor Yellow
|
|
Write-Host ("=" * $width) -ForegroundColor Cyan
|
|
Write-Host ""
|
|
}
|
|
|
|
function Write-InfoBox {
|
|
param(
|
|
[string]$Message,
|
|
[string]$Type = 'Info'
|
|
)
|
|
|
|
$color = switch ($Type) {
|
|
'Success' { 'Green' }
|
|
'Warning' { 'Yellow' }
|
|
'Error' { 'Red' }
|
|
default { 'Cyan' }
|
|
}
|
|
|
|
$icon = switch ($Type) {
|
|
'Success' { '[+]' }
|
|
'Warning' { '[!]' }
|
|
'Error' { '[X]' }
|
|
default { '[i]' }
|
|
}
|
|
|
|
Write-Host "$icon " -ForegroundColor $color -NoNewline
|
|
Write-Host $Message
|
|
}
|
|
|
|
function Write-Separator {
|
|
Write-Host ("-" * 70) -ForegroundColor DarkGray
|
|
}
|
|
|
|
function Get-ScriptFiles {
|
|
param([string]$Path)
|
|
|
|
if (-not (Test-Path $Path)) {
|
|
return $null
|
|
}
|
|
|
|
$scripts = Get-ChildItem -Path $Path -File -ErrorAction SilentlyContinue |
|
|
Where-Object { $Script:SupportedExtensions -contains $_.Extension } |
|
|
Sort-Object Name
|
|
|
|
return $scripts
|
|
}
|
|
|
|
function Show-ScriptMenu {
|
|
param([array]$Scripts)
|
|
|
|
Write-Host " Available Scripts:" -ForegroundColor Green
|
|
Write-Host ""
|
|
|
|
for ($i = 0; $i -lt $Scripts.Count; $i++) {
|
|
$num = $i + 1
|
|
$script = $Scripts[$i]
|
|
$ext = $script.Extension
|
|
|
|
$extColor = switch ($ext) {
|
|
'.ps1' { 'Magenta' }
|
|
'.bat' { 'Yellow' }
|
|
'.cmd' { 'Cyan' }
|
|
default { 'White' }
|
|
}
|
|
|
|
Write-Host " " -NoNewline
|
|
Write-Host ("[{0,2}]" -f $num) -ForegroundColor White -NoNewline
|
|
Write-Host " " -NoNewline
|
|
Write-Host $script.Name -ForegroundColor $extColor
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Separator
|
|
Write-Host ""
|
|
}
|
|
|
|
function Get-UserSelection {
|
|
param([int]$MaxNumber)
|
|
|
|
Write-Host " Selection Options:" -ForegroundColor Yellow
|
|
Write-Host " - Enter number (e.g., '1')" -ForegroundColor Gray
|
|
Write-Host " - Enter 'all' to run all scripts sequentially" -ForegroundColor Gray
|
|
Write-Host " - Enter 'q' or 'quit' to exit" -ForegroundColor Gray
|
|
Write-Host ""
|
|
|
|
while ($true) {
|
|
Write-Host " Select script to run: " -ForegroundColor Cyan -NoNewline
|
|
$input = Read-Host
|
|
|
|
if ([string]::IsNullOrWhiteSpace($input)) {
|
|
Write-InfoBox "Please enter a selection" "Warning"
|
|
continue
|
|
}
|
|
|
|
$input = $input.Trim().ToLower()
|
|
|
|
if ($input -eq 'q' -or $input -eq 'quit') {
|
|
return $null
|
|
}
|
|
|
|
if ($input -eq 'all') {
|
|
return 1..$MaxNumber
|
|
}
|
|
|
|
if ($input -match '^\d+$') {
|
|
$num = [int]$input
|
|
|
|
if ($num -lt 1 -or $num -gt $MaxNumber) {
|
|
Write-InfoBox "Invalid number. Please enter 1-$MaxNumber" "Error"
|
|
continue
|
|
}
|
|
|
|
return @($num)
|
|
}
|
|
|
|
Write-InfoBox "Invalid input. Please try again" "Error"
|
|
}
|
|
}
|
|
|
|
function Invoke-Script {
|
|
param(
|
|
[string]$ScriptPath,
|
|
[string]$ScriptName
|
|
)
|
|
|
|
Write-Host ""
|
|
Write-InfoBox "Executing: $ScriptName" "Info"
|
|
Write-Host ""
|
|
|
|
$extension = [System.IO.Path]::GetExtension($ScriptPath)
|
|
|
|
try {
|
|
if ($extension -eq '.ps1') {
|
|
& $ScriptPath
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
else {
|
|
$process = Start-Process -FilePath $ScriptPath -Wait -PassThru -NoNewWindow
|
|
$exitCode = $process.ExitCode
|
|
}
|
|
|
|
Write-Host ""
|
|
if ($exitCode -eq 0 -or $null -eq $exitCode) {
|
|
Write-InfoBox "Completed: $ScriptName" "Success"
|
|
}
|
|
else {
|
|
Write-InfoBox "Completed with exit code $exitCode: $ScriptName" "Warning"
|
|
$Script:ExitCode = $exitCode
|
|
}
|
|
}
|
|
catch {
|
|
Write-InfoBox "Failed to execute: $ScriptName" "Error"
|
|
Write-InfoBox "Error: $($_.Exception.Message)" "Error"
|
|
$Script:ExitCode = 1
|
|
}
|
|
}
|
|
|
|
function Start-ScriptMenu {
|
|
try {
|
|
Clear-Host
|
|
|
|
Write-Header "WinPE SCRIPT MENU"
|
|
|
|
if (-not (Test-Path $ScriptsPath)) {
|
|
Write-InfoBox "Scripts folder not found: $ScriptsPath" "Error"
|
|
Write-Host ""
|
|
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
|
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
exit 1
|
|
}
|
|
|
|
Write-InfoBox "Scripts Folder: $ScriptsPath" "Info"
|
|
|
|
$scripts = Get-ScriptFiles -Path $ScriptsPath
|
|
|
|
if ($null -eq $scripts -or $scripts.Count -eq 0) {
|
|
Write-Host ""
|
|
Write-InfoBox "No scripts found" "Warning"
|
|
Write-InfoBox "Supported: $($Script:SupportedExtensions -join ', ')" "Info"
|
|
Write-Host ""
|
|
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
|
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
exit 1
|
|
}
|
|
|
|
Write-InfoBox "Found $($scripts.Count) script(s)" "Success"
|
|
Write-Host ""
|
|
Write-Separator
|
|
Write-Host ""
|
|
|
|
Show-ScriptMenu -Scripts $scripts
|
|
|
|
$selections = Get-UserSelection -MaxNumber $scripts.Count
|
|
|
|
if ($null -eq $selections) {
|
|
Write-Host ""
|
|
Write-InfoBox "Exiting..." "Info"
|
|
Write-Host ""
|
|
exit 0
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Header "Executing Selected Scripts"
|
|
|
|
foreach ($selection in $selections) {
|
|
$script = $scripts[$selection - 1]
|
|
Invoke-Script -ScriptPath $script.FullName -ScriptName $script.Name
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Separator
|
|
Write-InfoBox "All scripts completed" "Success"
|
|
Write-Host ""
|
|
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
|
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
|
|
exit $Script:ExitCode
|
|
}
|
|
catch {
|
|
Write-Host ""
|
|
Write-InfoBox "FATAL ERROR: $($_.Exception.Message)" "Error"
|
|
Write-Host ""
|
|
Write-Host "Press any key to exit..." -ForegroundColor Gray
|
|
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
Start-ScriptMenu
|