Fixes several offline-hive build failures: TrustedInstaller-owned keys (WindowsRuntime\ActivatableClassId, Explorer\Advanced, System\GameConfigStore, Search SystemIndex) denying writes even to admin-owned processes, a PowerShell 5.1 quirk that drops empty-string reg.exe arguments and can hang the build on a silent overwrite prompt, a registry-handle leak that left hives locked and cascaded into DISM cleanup failures, and relaxed the post-ResetBase health gate to accept 'Repairable' (only abort on 'NonRepairable') since ResetBase makes full repair impossible anyway - documented that repairing the installed OS needs the original stock ISO, not the tweaked output. Also rolls in in-progress updates to the other maker scripts and OEM setup/first-boot scripts.
157 lines
5.8 KiB
PowerShell
157 lines
5.8 KiB
PowerShell
#Requires -RunAsAdministrator
|
|
param(
|
|
[string]$IsoPath = "$PSScriptRoot\..\..\tiny10.iso",
|
|
[string]$OutputIso = ""
|
|
)
|
|
|
|
$projectRoot = (Resolve-Path "$PSScriptRoot\..\..")
|
|
|
|
# Detect Windows 10 vs 11 from install.wim/install.esd so the right autounattend variant gets injected
|
|
function Get-WindowsVersionFromMedia {
|
|
param([string]$MediaRoot)
|
|
|
|
$srcBase = $MediaRoot
|
|
if (-not (Test-Path "$srcBase\sources\install.wim") -and -not (Test-Path "$srcBase\sources\install.esd") -and (Test-Path "$srcBase\x64\sources")) {
|
|
$srcBase = "$srcBase\x64"
|
|
}
|
|
|
|
$imagePath = if (Test-Path "$srcBase\sources\install.wim") { "$srcBase\sources\install.wim" }
|
|
elseif (Test-Path "$srcBase\sources\install.esd") { "$srcBase\sources\install.esd" }
|
|
else { $null }
|
|
|
|
if (-not $imagePath) { return $null }
|
|
|
|
try {
|
|
$imgInfo = Get-WindowsImage -ImagePath $imagePath -Index 1
|
|
$parts = $imgInfo.Version.Split('.')
|
|
if ($parts.Count -ge 3) {
|
|
$build = [int]$parts[2]
|
|
if ($build -ge 22000) { return "11" }
|
|
elseif ($build -ge 10240) { return "10" }
|
|
}
|
|
}
|
|
catch {
|
|
Write-Warning "Could not read Windows version from media: $($_.Exception.Message)"
|
|
}
|
|
return $null
|
|
}
|
|
|
|
if (-not (Test-Path $IsoPath)) {
|
|
Write-Error "ISO not found: $IsoPath"
|
|
exit 1
|
|
}
|
|
|
|
$IsoPath = (Resolve-Path $IsoPath).Path
|
|
if (-not $OutputIso) { $OutputIso = $IsoPath }
|
|
|
|
# Get Windows ADK path from registry(following Visual Studio's winsdk.bat approach).
|
|
$WinSDKPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots", "KitsRoot10", $null)
|
|
if ($null -eq $WinSDKPath) {
|
|
$WinSDKPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots", "KitsRoot10", $null)
|
|
}
|
|
|
|
if ($null -ne $WinSDKPath) {
|
|
# Trim the following backslash for path concatenation.
|
|
$WinSDKPath = $WinSDKPath.TrimEnd('\')
|
|
$ADKDepTools = "$WinSDKPath\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg"
|
|
}
|
|
$localOSCDIMGPath = "$PSScriptRoot\oscdimg.exe"
|
|
|
|
if ((Test-Path variable:ADKDepTools) -and (Test-Path "$ADKDepTools\oscdimg.exe" -PathType leaf)) {
|
|
Write-Host "Will be using oscdimg.exe from system ADK."
|
|
$OSCDIMG = "$ADKDepTools\oscdimg.exe"
|
|
}
|
|
else {
|
|
Write-Host "oscdimg.exe from system ADK not found. Will be using bundled oscdimg.exe."
|
|
|
|
$url = "https://msdl.microsoft.com/download/symbols/oscdimg.exe/3D44737265000/oscdimg.exe"
|
|
|
|
if (![System.IO.File]::Exists($localOSCDIMGPath)) {
|
|
Write-Host "Downloading oscdimg.exe..."
|
|
Invoke-WebRequest -Uri $url -OutFile $localOSCDIMGPath
|
|
|
|
if ([System.IO.File]::Exists($localOSCDIMGPath)) {
|
|
Write-Host "oscdimg.exe downloaded successfully."
|
|
}
|
|
else {
|
|
Write-Error "Failed to download oscdimg.exe."
|
|
exit 1
|
|
}
|
|
}
|
|
else {
|
|
Write-Host "oscdimg.exe already exists locally."
|
|
}
|
|
|
|
$OSCDIMG = $localOSCDIMGPath
|
|
}
|
|
|
|
# Temp working folder
|
|
$tempDir = "$env:TEMP\tiny10_patch_$([System.IO.Path]::GetRandomFileName().Replace('.',''))"
|
|
New-Item -ItemType Directory -Path $tempDir | Out-Null
|
|
Write-Host "Temp dir: $tempDir"
|
|
|
|
try {
|
|
# Mount ISO
|
|
Write-Host "Mounting ISO..."
|
|
$diskImage = Mount-DiskImage -ImagePath $IsoPath -PassThru
|
|
$driveLetter = ($diskImage | Get-Volume).DriveLetter + ":"
|
|
Write-Host "Mounted at $driveLetter"
|
|
|
|
# Copy contents
|
|
Write-Host "Copying ISO contents (this may take a minute)..."
|
|
Copy-Item -Path "$driveLetter\*" -Destination $tempDir -Recurse -Force
|
|
|
|
Dismount-DiskImage -ImagePath $IsoPath | Out-Null
|
|
Write-Host "Dismounted."
|
|
|
|
# Clear read-only flags
|
|
Get-ChildItem -Path $tempDir -Recurse | ForEach-Object {
|
|
if ($_.Attributes -band [System.IO.FileAttributes]::ReadOnly) {
|
|
$_.Attributes = $_.Attributes -bxor [System.IO.FileAttributes]::ReadOnly
|
|
}
|
|
}
|
|
|
|
# Detect Windows version so we inject the matching autounattend variant
|
|
Write-Host "Detecting Windows version from media..."
|
|
$detectedVersion = Get-WindowsVersionFromMedia -MediaRoot $tempDir
|
|
if (-not $detectedVersion) {
|
|
Write-Host "Could not automatically detect Windows version from media."
|
|
do {
|
|
$detectedVersion = Read-Host "Enter Windows version (10 or 11)"
|
|
} while ($detectedVersion -notin @("10", "11"))
|
|
}
|
|
else {
|
|
Write-Host "Detected Windows $detectedVersion media."
|
|
}
|
|
|
|
# Replace autounattend.xml with the version-matched variant
|
|
$newXml = "$projectRoot\includes\autounattend-win$detectedVersion.xml"
|
|
if (-not (Test-Path $newXml)) {
|
|
Write-Error "autounattend-win$detectedVersion.xml not found at: $newXml"
|
|
exit 1
|
|
}
|
|
Write-Host "Replacing autounattend.xml with autounattend-win$detectedVersion.xml..."
|
|
Copy-Item -Path $newXml -Destination "$tempDir\autounattend.xml" -Force
|
|
|
|
# Detect label from ISO filename, tagged with the detected version
|
|
$isoName = [System.IO.Path]::GetFileNameWithoutExtension($IsoPath)
|
|
$label = if ($isoName -match 'x86') { "Tiny${detectedVersion}_x86" } else { "Tiny${detectedVersion}_x64" }
|
|
|
|
$bootEtfs = "$tempDir\boot\etfsboot.com"
|
|
$bootEfi = "$tempDir\efi\microsoft\boot\efisys.bin"
|
|
Write-Host "Repacking ISO as: $OutputIso"
|
|
& "$OSCDIMG" "-l$label" '-m' '-o' '-u2' '-udfver102' `
|
|
"-bootdata:2#p0,e,b$bootEtfs#pEF,e,b$bootEfi" `
|
|
$tempDir $OutputIso
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "Done. ISO saved to: $OutputIso"
|
|
} else {
|
|
Write-Error "oscdimg failed with exit code $LASTEXITCODE"
|
|
}
|
|
} finally {
|
|
try { Dismount-DiskImage -ImagePath $IsoPath -ErrorAction SilentlyContinue | Out-Null } catch {}
|
|
Write-Host "Cleaning up temp dir..."
|
|
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|