Files
windows-builder/includes/utils/view-bootres.ps1
2026-06-02 03:37:09 -07:00

493 lines
16 KiB
PowerShell

param(
[Parameter(Mandatory=$true)]
[string]$BootResDllPath,
[Parameter(Mandatory=$false)]
[string]$OutputFolder,
[switch]$ExtractAll,
[switch]$ShowInfo
)
# Boot logo sizes for Windows 10/11
# Note: Actual Windows 11 uses square logos (height x height)
# The original Windows 8/10 used wider rectangles
$LogoSizes = @(
@{Name="winlogo1.bmp"; Width=72; Height=72; Description="Small Logo"},
@{Name="winlogo2.bmp"; Width=90; Height=90; Description="Medium Logo"},
@{Name="winlogo3.bmp"; Width=115; Height=115; Description="Standard Logo"},
@{Name="winlogo3n.bmp"; Width=87; Height=115; Description="Narrow Logo"},
@{Name="winlogo4.bmp"; Width=214; Height=214; Description="Large Logo"},
@{Name="winlogo5.bmp"; Width=284; Height=284; Description="Extra Large Logo"}
)
# Function to log messages
function Write-Log {
param(
[string]$Message,
[string]$Color = "White"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "[$timestamp] $Message" -ForegroundColor $Color
}
# Function to check if 7-Zip is available
function Test-7ZipAvailable {
$7zipPaths = @(
"C:\Program Files\7-Zip\7z.exe",
"C:\Program Files (x86)\7-Zip\7z.exe",
"$env:ProgramFiles\7-Zip\7z.exe"
)
foreach ($path in $7zipPaths) {
if (Test-Path $path) {
return $path
}
}
# Check if 7z is in PATH
try {
$null = Get-Command 7z -ErrorAction Stop
return "7z"
} catch {
return $null
}
}
# Function to get file version info
function Get-FileVersionInfo {
param([string]$FilePath)
try {
$versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FilePath)
return @{
FileVersion = $versionInfo.FileVersion
ProductVersion = $versionInfo.ProductVersion
CompanyName = $versionInfo.CompanyName
FileDescription = $versionInfo.FileDescription
InternalName = $versionInfo.InternalName
OriginalFilename = $versionInfo.OriginalFilename
ProductName = $versionInfo.ProductName
}
} catch {
return $null
}
}
# Function to check digital signature
function Get-DigitalSignature {
param([string]$FilePath)
try {
$signature = Get-AuthenticodeSignature -FilePath $FilePath
return @{
Status = $signature.Status
SignerCertificate = $signature.SignerCertificate
TimeStamperCertificate = $signature.TimeStamperCertificate
IsSigned = $signature.Status -eq 'Valid'
SignerSubject = if ($signature.SignerCertificate) { $signature.SignerCertificate.Subject } else { "N/A" }
SignerIssuer = if ($signature.SignerCertificate) { $signature.SignerCertificate.Issuer } else { "N/A" }
}
} catch {
return @{
Status = "Error"
IsSigned = $false
SignerSubject = "N/A"
SignerIssuer = "N/A"
}
}
}
# Function to get file architecture (32-bit or 64-bit)
function Get-FileArchitecture {
param([string]$FilePath)
try {
$bytes = [System.IO.File]::ReadAllBytes($FilePath)
# Check DOS signature
if ($bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) {
return "Unknown"
}
# Get PE header offset
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
# Check PE signature
if ($bytes[$peOffset] -ne 0x50 -or $bytes[$peOffset + 1] -ne 0x45) {
return "Unknown"
}
# Get machine type
$machineType = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
switch ($machineType) {
0x014C { return "32-bit (x86)" }
0x0200 { return "64-bit (IA64)" }
0x8664 { return "64-bit (x64)" }
default { return "Unknown ($machineType)" }
}
} catch {
return "Error reading file"
}
}
# Function to extract WIM from bootres.dll
function Extract-BootResWim {
param(
[string]$DllPath,
[string]$OutputPath,
[string]$SevenZipPath
)
Write-Log "Extracting WIM archive from bootres.dll..." -Color Cyan
# First, extract the PE resources
$extractArgs = @(
"e",
"`"$DllPath`"",
"-o`"$OutputPath`"",
"-r",
"-y"
)
$process = Start-Process -FilePath $SevenZipPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "$OutputPath\7z_extract.log"
if ($process.ExitCode -ne 0) {
throw "Failed to extract resources from bootres.dll"
}
# Look for the WIM file - it might be named "1" or have .wim extension
$possibleWimFiles = @(
(Get-ChildItem -Path $OutputPath -Filter "*.wim" -ErrorAction SilentlyContinue),
(Get-ChildItem -Path $OutputPath -Filter "1" -ErrorAction SilentlyContinue),
(Get-ChildItem -Path $OutputPath -Filter "RCDATA" -ErrorAction SilentlyContinue)
) | Where-Object { $_ -ne $null } | Select-Object -First 1
if (-not $possibleWimFiles) {
# Try to find any file that starts with MSWIM signature
$allFiles = Get-ChildItem -Path $OutputPath -File
foreach ($file in $allFiles) {
try {
$bytes = [System.IO.File]::ReadAllBytes($file.FullName)
if ($bytes.Length -ge 6) {
$signature = [System.Text.Encoding]::ASCII.GetString($bytes[0..4])
if ($signature -eq "MSWIM") {
$wimPath = Join-Path $OutputPath "bootres.wim"
Move-Item -Path $file.FullName -Destination $wimPath -Force
return $wimPath
}
}
} catch {
continue
}
}
throw "No WIM file found after extraction. Files in output: $(($allFiles | Select-Object -ExpandProperty Name) -join ', ')"
}
$extractedWim = $possibleWimFiles
# Rename to bootres.wim if it has a different name
$wimPath = Join-Path $OutputPath "bootres.wim"
if ($extractedWim.FullName -ne $wimPath) {
Move-Item -Path $extractedWim.FullName -Destination $wimPath -Force
}
return $wimPath
}
# Function to list contents of WIM
function Get-WimContents {
param(
[string]$WimPath,
[string]$SevenZipPath
)
Write-Log "Listing contents of WIM archive..." -Color Cyan
$listArgs = @(
"l",
"`"$WimPath`""
)
$output = & $SevenZipPath $listArgs 2>&1
# Parse output to get file list
$files = @()
$inFileList = $false
foreach ($line in $output) {
if ($line -match "^-{5,}") {
$inFileList = -not $inFileList
continue
}
if ($inFileList -and $line -match "\.bmp$") {
# Extract filename from the line
if ($line -match "\s+(\S+\.bmp)\s*$") {
$files += $matches[1]
}
}
}
return $files
}
# Function to extract bitmaps from WIM
function Extract-BitmapsFromWim {
param(
[string]$WimPath,
[string]$OutputPath,
[string]$SevenZipPath
)
Write-Log "Extracting bitmaps from WIM..." -Color Cyan
$extractArgs = @(
"e",
"`"$WimPath`"",
"-o`"$OutputPath`"",
"*.bmp",
"-y"
)
$process = Start-Process -FilePath $SevenZipPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru
if ($process.ExitCode -ne 0) {
throw "Failed to extract bitmaps from WIM"
}
}
# Function to get bitmap info
function Get-BitmapInfo {
param([string]$BitmapPath)
try {
Add-Type -AssemblyName System.Drawing
$image = [System.Drawing.Image]::FromFile($BitmapPath)
$info = @{
Width = $image.Width
Height = $image.Height
PixelFormat = $image.PixelFormat.ToString()
RawFormat = $image.RawFormat.ToString()
HorizontalResolution = $image.HorizontalResolution
VerticalResolution = $image.VerticalResolution
}
$image.Dispose()
return $info
} catch {
return $null
}
}
# Function to display bitmap info
function Show-BitmapInfo {
param(
[string]$BitmapPath,
[string]$Name
)
$info = Get-BitmapInfo -BitmapPath $BitmapPath
$fileSize = (Get-Item $BitmapPath).Length
if ($info) {
$expectedInfo = $LogoSizes | Where-Object { $_.Name -eq $Name }
Write-Host ""
Write-Host " File: $Name" -ForegroundColor Yellow
if ($expectedInfo) {
Write-Host " Description: $($expectedInfo.Description)" -ForegroundColor Gray
}
Write-Host " Dimensions: $($info.Width) x $($info.Height) pixels" -ForegroundColor White
Write-Host " Pixel Format: $($info.PixelFormat)" -ForegroundColor Gray
Write-Host " File Size: $([math]::Round($fileSize / 1KB, 2)) KB" -ForegroundColor Gray
Write-Host " Resolution: $($info.HorizontalResolution) x $($info.VerticalResolution) DPI" -ForegroundColor Gray
if ($expectedInfo) {
if ($info.Width -eq $expectedInfo.Width -and $info.Height -eq $expectedInfo.Height) {
Write-Host " Status: Correct size" -ForegroundColor Green
} else {
Write-Host " Status: Size mismatch! Expected $($expectedInfo.Width)x$($expectedInfo.Height)" -ForegroundColor Red
}
}
} else {
Write-Host " Error reading bitmap: $Name" -ForegroundColor Red
}
}
# Function to open image viewer
function Open-ImageViewer {
param([string]$ImagePath)
try {
Start-Process $ImagePath
} catch {
Write-Log "Could not open image viewer for: $ImagePath" -Color Yellow
}
}
# Main script execution
try {
Write-Host ""
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " Windows Boot Resource Viewer v1.0 " -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
Write-Host ""
# Validate input file
if (-not (Test-Path $BootResDllPath)) {
throw "bootres.dll not found at: $BootResDllPath"
}
$fileInfo = Get-Item $BootResDllPath
Write-Host "FILE INFORMATION" -ForegroundColor Green
Write-Host "================" -ForegroundColor Green
Write-Host "File Path: $($fileInfo.FullName)" -ForegroundColor White
Write-Host "File Size: $([math]::Round($fileInfo.Length / 1KB, 2)) KB" -ForegroundColor White
Write-Host "Created: $($fileInfo.CreationTime)" -ForegroundColor White
Write-Host "Modified: $($fileInfo.LastWriteTime)" -ForegroundColor White
# Get file architecture
$arch = Get-FileArchitecture -FilePath $BootResDllPath
Write-Host "Architecture: $arch" -ForegroundColor White
# Get version info
if ($ShowInfo) {
$versionInfo = Get-FileVersionInfo -FilePath $BootResDllPath
if ($versionInfo) {
Write-Host ""
Write-Host "VERSION INFORMATION" -ForegroundColor Green
Write-Host "===================" -ForegroundColor Green
Write-Host "File Version: $($versionInfo.FileVersion)" -ForegroundColor White
Write-Host "Product Version: $($versionInfo.ProductVersion)" -ForegroundColor White
Write-Host "Company: $($versionInfo.CompanyName)" -ForegroundColor White
Write-Host "Description: $($versionInfo.FileDescription)" -ForegroundColor White
Write-Host "Product Name: $($versionInfo.ProductName)" -ForegroundColor White
}
# Get digital signature
$signature = Get-DigitalSignature -FilePath $BootResDllPath
Write-Host ""
Write-Host "DIGITAL SIGNATURE" -ForegroundColor Green
Write-Host "=================" -ForegroundColor Green
Write-Host "Status: $($signature.Status)" -ForegroundColor $(if ($signature.IsSigned) { "Green" } else { "Red" })
Write-Host "Signed By: $($signature.SignerSubject)" -ForegroundColor White
Write-Host "Issuer: $($signature.SignerIssuer)" -ForegroundColor White
}
# Check for 7-Zip
$7zPath = Test-7ZipAvailable
if (-not $7zPath) {
throw "7-Zip is required but not found. Please install 7-Zip from https://www.7-zip.org/"
}
Write-Log "Found 7-Zip at: $7zPath" -Color Green
# Create temporary directory
$tempDir = Join-Path $env:TEMP "BootResViewer_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
# Extract bitmaps directly from bootres.dll
Write-Log "Extracting bitmaps from bootres.dll..." -Color Cyan
$extractArgs = @(
"e",
"`"$BootResDllPath`"",
"-o`"$tempDir`"",
"*.bmp",
"-r",
"-y"
)
$process = Start-Process -FilePath $7zPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru
if ($process.ExitCode -ne 0) {
throw "Failed to extract bitmaps from bootres.dll"
}
# Get extracted bitmaps
$extractedBitmaps = Get-ChildItem -Path $tempDir -Filter "*.bmp"
if ($extractedBitmaps.Count -eq 0) {
throw "No bitmaps found in bootres.dll"
}
Write-Log "Successfully extracted $($extractedBitmaps.Count) bitmap(s)" -Color Green
# Separate winlogo and qrcode bitmaps
$winlogoBitmaps = $extractedBitmaps | Where-Object { $_.Name -like "winlogo*" }
$qrcodeBitmaps = $extractedBitmaps | Where-Object { $_.Name -like "qrcode*" }
Write-Host ""
Write-Host "EXTRACTED BITMAPS" -ForegroundColor Green
Write-Host "=================" -ForegroundColor Green
if ($winlogoBitmaps.Count -gt 0) {
Write-Host "Boot Logos (winlogo*):" -ForegroundColor Cyan
$winlogoBitmaps | ForEach-Object { Write-Host " - $($_.Name)" -ForegroundColor White }
}
if ($qrcodeBitmaps.Count -gt 0) {
Write-Host "QR Codes (qrcode*):" -ForegroundColor Cyan
$qrcodeBitmaps | ForEach-Object { Write-Host " - $($_.Name)" -ForegroundColor White }
}
Write-Host ""
Write-Host "BITMAP DETAILS" -ForegroundColor Green
Write-Host "==============" -ForegroundColor Green
foreach ($bitmap in $extractedBitmaps) {
Show-BitmapInfo -BitmapPath $bitmap.FullName -Name $bitmap.Name
}
# Extract to output folder if specified
if ($OutputFolder) {
if (-not (Test-Path $OutputFolder)) {
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
}
Write-Host ""
Write-Log "Copying bitmaps to: $OutputFolder" -Color Cyan
foreach ($bitmap in $extractedBitmaps) {
$destPath = Join-Path $OutputFolder $bitmap.Name
Copy-Item -Path $bitmap.FullName -Destination $destPath -Force
Write-Host " Copied: $($bitmap.Name)" -ForegroundColor Green
}
}
# Summary
Write-Host ""
Write-Host "================================================" -ForegroundColor Cyan
Write-Host "SUMMARY" -ForegroundColor Green
Write-Host "================================================" -ForegroundColor Cyan
Write-Host "Total bitmaps found: $($extractedBitmaps.Count)" -ForegroundColor White
Write-Host " - Boot logos (winlogo*): $($winlogoBitmaps.Count)" -ForegroundColor White
Write-Host " - QR codes (qrcode*): $($qrcodeBitmaps.Count)" -ForegroundColor White
Write-Host "Temporary files location: $tempDir" -ForegroundColor White
if ($OutputFolder) {
Write-Host "Bitmaps saved to: $OutputFolder" -ForegroundColor Green
} else {
Write-Host ""
Write-Host "TIP: Use -OutputFolder parameter to save bitmaps to a specific location" -ForegroundColor Yellow
Write-Host "Example: .\view-bootres.ps1 -BootResDllPath 'C:\path\to\bootres.dll' -OutputFolder 'C:\extracted'" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "Expected boot logo sizes:" -ForegroundColor Cyan
foreach ($logoSize in $LogoSizes) {
Write-Host " $($logoSize.Name): $($logoSize.Width)x$($logoSize.Height) - $($logoSize.Description)" -ForegroundColor Gray
}
Write-Host ""
} catch {
Write-Host ""
Write-Host "ERROR: $_" -ForegroundColor Red
Write-Host "Stack Trace: $($_.ScriptStackTrace)" -ForegroundColor Red
exit 1
}