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 }