diff --git a/README.md b/README.md
index e3f13795..597aa288 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,35 @@ Windows. Test your ISO in a VM before installing it.**

+## Booting from Ventoy
+
+ISOs built here boot from Ventoy in its default (non-wimboot) mode โ no Rufus,
+no extracted USB stick, no manual patching. If an older build stops at
+**"A media driver your computer needs is missing"**, the wording is misleading:
+it is not a missing disk driver, it means Setup never saw its installation
+media. Rebuild the ISO; nothing about the Ventoy stick needs to change.
+
+Ventoy does not extract a Windows ISO. It boots the ISO's own `boot.wim` and
+injects `vtoyjump.exe` so the ISO can be mounted as a virtual drive before
+`setup.exe` runs. Two builder behaviours broke that:
+
+| Change | Why it broke Ventoy |
+| --- | --- |
+| The WinPE launch chain forced to a fixed `X:\sources\setup.exe` (`Setup\CmdLine` in the scripts, `winpeshl.ini` in the app) | Setup takes the boot RAM disk as its media root, finds no `install.wim` beside it and stops. Core only. |
+| `oscdimg -udfver102` | UDF 1.02 cannot describe a file larger than 4 GB, so a trimmed `install.wim` is written with metadata that lean readers mis-parse. |
+
+Both are fixed: the stock WinPE launch chain is left alone, so the boot image's
+own `setup.exe` bootstrap locates the media before running that media's
+`sources\setup.exe`, and ISOs are built with `-udfver150`. A build also refuses
+to emit an ISO whose `sources\` has no usable `install.wim`/`install.esd`,
+because that failure looks identical to this one.
+
+If a rebuilt ISO still fails, press `Shift+F10` at the error and run `diskpart`,
+then `list volume`. No virtual DVD drive means `vtoyjump` never ran;
+`X:\Windows\System32\ventoy\vtoype.log` records why a mount failed. `Ctrl+W` at
+the Ventoy menu switches to wimboot mode, a different boot path. Also check that
+Ventoy is 1.1.07 or newer and that its data partition is NTFS rather than exFAT.
+
## More information
[Usage, compatibility and build instructions](docs/usage.md) ยท
diff --git a/docs/usage.md b/docs/usage.md
index 7676c46a..62d1d63a 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -63,9 +63,14 @@ The six-step wizard provides:
acknowledgement before a build.
- Core and Custom WinSxS/component-payload removals always use the legacy
Windows installer, including on 24H2 and newer media. The private Setup
- boot image starts `wpeinit.exe`, then its matching `sources\setup.exe`
- (`setup_old.exe` when present), instead of the newer SetupHost workflow.
- This is automatic, not a hardware-bypass option; no installer from a
+ boot image starts `wpeinit.exe`, then the boot image's own `setup.exe`
+ bootstrap, which locates the installation media and runs that media's
+ matching `sources\setup.exe` (`setup_old.exe` when present) instead of the
+ newer SetupHost workflow. Starting a fixed `X:\sources\setup.exe` instead
+ would make Setup treat the boot RAM disk as the media root and stop with
+ "A media driver your computer needs is missing" โ including under Ventoy,
+ which mounts the ISO as a virtual drive only after its own WinPE hook has
+ run. This is automatic, not a hardware-bypass option; no installer from a
different Windows release is downloaded. Media without the classic
executable fails explicitly. A resumed Core job also receives this change
even if its final installation image was already compressed.
@@ -94,6 +99,44 @@ The six-step wizard provides:
state, verified saved progress for **Resume build**, an output SHA-256, a JSON
report, and separate interrupted-workspace discard/recovery.
+## Booting from Ventoy
+
+Output ISOs boot from Ventoy in its default (non-wimboot) mode, for both Tiny11
+and Tiny11 Core. Ventoy does not extract a Windows ISO: it boots the ISO's own
+`boot.wim` and injects `vtoyjump.exe`, which mounts the ISO as a virtual drive
+before `setup.exe` runs. Setup only reads `sources\install.wim` after that
+mount, so anything that stops the hook from running, or that hides the media
+from Setup, surfaces as the same misleading message:
+
+> A media driver your computer needs is missing. This could be a DVD, USB, or Hard disk driver.
+
+That message is not about a driver. It means Setup never saw its installation
+media. Three build-time causes are handled:
+
+| Cause | Handling |
+| --- | --- |
+| The WinPE launch chain forced to a fixed `X:\sources\setup.exe` (`Setup\CmdLine` in the scripts, `winpeshl.ini` in the app) | The stock launch chain is left alone. The boot image's own `setup.exe` bootstrap locates the media and runs that media's `sources\setup.exe`. |
+| `oscdimg -udfver102` | ISOs are built with `-udfver150`. UDF 1.02 cannot describe a file larger than 4 GB, which a trimmed `install.wim` exceeds. |
+| A failed image export that still deleted the old image | The build refuses to create an ISO whose `sources\` has no usable `install.wim`/`install.esd`, and removes leftover `install2.wim`/`install2.esd`. |
+
+If a current ISO still stops at that message, press `Shift+F10` and run:
+
+```
+diskpart
+list volume
+type X:\Windows\System32\ventoy\vtoype.log
+```
+
+- **No virtual DVD drive in `list volume`** โ `vtoyjump` never ran, so the
+ problem is the boot image patch rather than the ISO contents.
+- **`vtoype.log`** records what `vtoyjump` did and why a mount failed.
+- **`Ctrl+W`** at the Ventoy menu switches to wimboot mode, a different boot
+ path worth trying as a workaround.
+
+Also check that Ventoy is **1.1.07 or newer**, that its data partition is
+**NTFS** rather than exFAT, and that the ISO sits on the first, large Ventoy
+partition rather than the 32 MB `VTOYEFI` one.
+
## Turbo mode and smaller images
The settings page has independent **Turbo mode**, **Remove redundant image
diff --git a/src/Tiny11Builder.Core/BuildEngine.Tail.cs b/src/Tiny11Builder.Core/BuildEngine.Tail.cs
index 8c6c800a..3a6f2ffd 100644
--- a/src/Tiny11Builder.Core/BuildEngine.Tail.cs
+++ b/src/Tiny11Builder.Core/BuildEngine.Tail.cs
@@ -304,6 +304,7 @@ await s.Tracking.RunAsync("checkpoint:compressed", "Compress", "Save verified co
private async Task CreateIsoAsync(BuildSession s, CancellationToken token)
{
s.Stage("Create ISO", "Creating a UEFI-bootable ISO using Microsoft's oscdimg.", token);
+ RequireInstallableMedia(s);
if (File.Exists(s.TemporaryIso))
{
PathSafety.RejectReparsePoints(s.TemporaryIso);
@@ -313,12 +314,52 @@ private async Task CreateIsoAsync(BuildSession s, CancellationToken token)
var efi = Path.Combine(s.Staging, s.EfiRelative);
var boot = s.Image.Architecture == "x64" && File.Exists(bios) ?
$"-bootdata:2#p0,e,b{bios}#pEF,e,b{efi}" : $"-bootdata:1#pEF,e,b{efi}";
+ // -u2 is the ISO9660 + Joliet + UDF layout Microsoft's own retail media uses; ISO9660 alone cannot hold a
+ // file larger than 4 GB, so the UDF layer is what carries install.wim. -udfver150 rather than the default
+ // UDF 1.02: 1.02 cannot describe a single file larger than 4 GB, and a trimmed install.wim routinely exceeds
+ // that. oscdimg still writes such a file, but the on-disc metadata ends up in a form lenient readers accept
+ // and lean ones mis-parse. This is a large-file robustness fix; it is not what stopped Ventoy booting.
var isoResult = await runner.RunAsync(s.Recipe.OscdimgPath,
- ["-m", "-o", "-u2", "-udfver102", boot, s.Staging, s.TemporaryIso], s.Log, token, finishOnCancellation: false).ConfigureAwait(false);
+ ["-m", "-o", "-u2", "-udfver150", boot, s.Staging, s.TemporaryIso], s.Log, token, finishOnCancellation: false).ConfigureAwait(false);
if (isoResult.ExitCode != 0 || !File.Exists(s.TemporaryIso) || new FileInfo(s.TemporaryIso).Length < 34816)
throw new IOException($"oscdimg did not produce an ISO (exit {isoResult.ExitCode}). {isoResult.Output}");
}
+ ///
+ /// Refuses to publish media that Windows Setup cannot install from. Every failure below looks identical to the
+ /// user - "A media driver your computer needs is missing" - while the real cause is an ISO with no installation
+ /// image, so the build has to stop here and name it instead of shipping a disc that cannot install.
+ ///
+ private static void RequireInstallableMedia(BuildSession s)
+ {
+ var sources = Path.Combine(s.Staging, "sources");
+ // An export interrupted between writing and renaming can leave a second image behind. Setup picks the first
+ // image it finds in sources\, so a stale partial one would silently win over the finished one.
+ foreach (var stray in new[] { "install2.wim", "install2.esd" })
+ {
+ var file = Path.Combine(sources, stray);
+ if (!File.Exists(file)) continue;
+ PathSafety.RejectReparsePoints(file);
+ File.Delete(file);
+ s.Warn($"Removed a leftover {stray} from the sources folder; Setup would have detected it as the installation image.");
+ }
+ var images = new[] { "install.wim", "install.esd" }.Select(name => Path.Combine(sources, name))
+ .Where(File.Exists).ToArray();
+ if (images.Length == 0)
+ throw new IOException("The media has no sources\\install.wim or install.esd, so Windows Setup would stop " +
+ "with \"A media driver your computer needs is missing\" even though no driver is involved. The image " +
+ "export step failed; no ISO was created.");
+ // The export stage already proved each image is complete (DISM lists its single edition and its WIM header and
+ // footer parse), so only the size is worth reporting here.
+ foreach (var image in images)
+ s.Log($"Install image {Path.GetFileName(image)}: {new FileInfo(image).Length / (1024d * 1024d):0} MB");
+ // Ventoy only applies its Windows boot patch to an ISO it recognises as standard installation media; without
+ // these it is treated as a generic image and never mounts itself as the drive Setup reads from.
+ foreach (var required in new[] { @"setup.exe", @"sources\boot.wim", @"boot\bcd", @"boot\boot.sdi" })
+ if (!File.Exists(Path.Combine(s.Staging, required)))
+ s.Log($"Ventoy compatibility: the staged media has no {required}, so Ventoy will not recognise this ISO as Windows media.");
+ }
+
private static async Task VerifyAndPublishAsync(BuildSession s, CancellationToken token)
{
s.Stage("Verify output", "Hashing the completed ISO and publishing it without overwriting existing files.", token);
diff --git a/src/Tiny11Builder.Core/SetupInstaller.cs b/src/Tiny11Builder.Core/SetupInstaller.cs
index f5dc24a5..ab5a91a6 100644
--- a/src/Tiny11Builder.Core/SetupInstaller.cs
+++ b/src/Tiny11Builder.Core/SetupInstaller.cs
@@ -24,6 +24,27 @@ internal static void ApplyLegacy(string mount, Action log)
ImageFileAccess.ValidateFile(program);
if (new FileInfo(program).Length == 0)
throw new InvalidDataException("The legacy installer in the Windows Setup image is empty.");
+
+ // Start the boot image's own setup bootstrap, and let it find the media, instead of starting a fixed path
+ // inside the boot RAM disk.
+ //
+ // boot.wim is loaded to X:, but the installation media is not there. From a USB stick it is another drive;
+ // under Ventoy it is not a drive at all until vtoyjump.exe has mounted the ISO as a virtual one, and Ventoy
+ // runs that hook from the same WinPE launch chain this file configures. Setup started as
+ // X:\sources\setup.exe takes the directory it was loaded from as the media root, finds no install.wim beside
+ // it, and stops with "A media driver your computer needs is missing" - which reads like a missing storage
+ // driver but only means Setup never saw its media. setup.exe at the root of the boot image is the stock
+ // bootstrap: it locates the media and then runs that media's matching sources\setup.exe, which is the classic
+ // installer this method exists to select. Only when the image ships no bootstrap does the fixed path remain.
+ var launch = "%SYSTEMDRIVE%\\" + executable;
+ var bootstrap = Path.Combine(mount, "setup.exe");
+ if (File.Exists(bootstrap))
+ {
+ ImageFileAccess.ValidateFile(bootstrap);
+ if (new FileInfo(bootstrap).Length == 0)
+ throw new InvalidDataException("The Setup bootstrap in the Windows Setup image is empty.");
+ launch = @"%SYSTEMDRIVE%\setup.exe";
+ }
var path = Path.Combine(mount, @"Windows\System32\winpeshl.ini");
PathSafety.RejectReparsePoints(Path.GetDirectoryName(path)!);
if (File.Exists(path))
@@ -31,9 +52,9 @@ internal static void ApplyLegacy(string mount, Action log)
using var privileges = new ImageOperations.PrivilegeScope();
ImageFileAccess.DeleteEntry(path);
}
- var content = "[LaunchApps]\r\n%SYSTEMROOT%\\System32\\wpeinit.exe\r\n%SYSTEMDRIVE%\\" + executable + "\r\n";
+ var content = "[LaunchApps]\r\n%SYSTEMROOT%\\System32\\wpeinit.exe\r\n" + launch + "\r\n";
File.WriteAllText(path, content, Encoding.ASCII);
if (File.ReadAllText(path) != content) throw new IOException("The legacy Windows Setup startup configuration could not be verified.");
- log($"Legacy installer enabled: %SYSTEMDRIVE%\\{executable}. Required by Core/component-store removals.");
+ log($"Legacy installer enabled: {launch}. Required by Core/component-store removals.");
}
}
diff --git a/tests/Tiny11Builder.Core.Tests/SetupInstallerTests.cs b/tests/Tiny11Builder.Core.Tests/SetupInstallerTests.cs
index f1936f75..b1bc2f1e 100644
--- a/tests/Tiny11Builder.Core.Tests/SetupInstallerTests.cs
+++ b/tests/Tiny11Builder.Core.Tests/SetupInstallerTests.cs
@@ -47,6 +47,23 @@ public void Legacy_startup_initializes_PE_then_runs_the_matching_classic_install
Assert.Throws(() => SetupInstaller.ApplyLegacy(fixture.Root, messages.Add));
}
+ [Fact]
+ public void Legacy_startup_uses_the_media_bootstrap_so_Setup_finds_its_media_outside_the_ram_disk()
+ {
+ using var fixture = new BuildFixture();
+ var mount = NativeTests.CreateOwnedMount(fixture.Root);
+ Directory.CreateDirectory(Path.Combine(mount, "sources"));
+ File.WriteAllText(Path.Combine(mount, @"sources\setup.exe"), "same-build classic binary");
+ File.WriteAllText(Path.Combine(mount, "setup.exe"), "stock media bootstrap");
+ var messages = new List();
+ SetupInstaller.ApplyLegacy(mount, messages.Add);
+ var ini = File.ReadAllText(Path.Combine(mount, @"Windows\System32\winpeshl.ini"));
+ // A fixed X:\sources\setup.exe makes Setup treat the RAM disk as the media root, which is empty under
+ // Ventoy until vtoyjump mounts the ISO. The bootstrap locates the real media first.
+ Assert.Equal("[LaunchApps]\r\n%SYSTEMROOT%\\System32\\wpeinit.exe\r\n%SYSTEMDRIVE%\\setup.exe\r\n", ini);
+ Assert.Single(messages);
+ }
+
[Fact]
public void Missing_classic_installer_is_a_loud_failure_not_a_new_installer_fallback()
{
diff --git a/tiny11Coremaker.ps1 b/tiny11Coremaker.ps1
index 439768ab..aa816b0b 100644
--- a/tiny11Coremaker.ps1
+++ b/tiny11Coremaker.ps1
@@ -332,11 +332,11 @@ Rename-Item -Path $mainOSDrive\scratchdir\Windows\WinSxS_edit -NewName $mainOSDr
Write-Host "Complete!"
Write-Host "Loading registry..."
-reg load HKLM\zCOMPONENTS $ScratchDisk\scratchdir\Windows\System32\config\COMPONENTS | Out-Null
-reg load HKLM\zDEFAULT $ScratchDisk\scratchdir\Windows\System32\config\default | Out-Null
-reg load HKLM\zNTUSER $ScratchDisk\scratchdir\Users\Default\ntuser.dat | Out-Null
-reg load HKLM\zSOFTWARE $ScratchDisk\scratchdir\Windows\System32\config\SOFTWARE | Out-Null
-reg load HKLM\zSYSTEM $ScratchDisk\scratchdir\Windows\System32\config\SYSTEM | Out-Null
+reg load HKLM\zCOMPONENTS $mainOSDrive\scratchdir\Windows\System32\config\COMPONENTS | Out-Null
+reg load HKLM\zDEFAULT $mainOSDrive\scratchdir\Windows\System32\config\default | Out-Null
+reg load HKLM\zNTUSER $mainOSDrive\scratchdir\Users\Default\ntuser.dat | Out-Null
+reg load HKLM\zSOFTWARE $mainOSDrive\scratchdir\Windows\System32\config\SOFTWARE | Out-Null
+reg load HKLM\zSYSTEM $mainOSDrive\scratchdir\Windows\System32\config\SYSTEM | Out-Null
Write-Host "Bypassing system requirements(on the system image):"
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
@@ -380,7 +380,7 @@ Write-Host "Disabling Sponsored Apps:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent' '/v' 'DisableCloudOptimizedContent' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Enabling Local Accounts on OOBE:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' '/v' 'BypassNRO' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
-Copy-Item -Path "$PSScriptRoot\autounattend.xml" -Destination "$ScratchDisk\scratchdir\Windows\System32\Sysprep\autounattend.xml" -Force | Out-Null
+Copy-Item -Path "$PSScriptRoot\autounattend.xml" -Destination "$mainOSDrive\scratchdir\Windows\System32\Sysprep\autounattend.xml" -Force | Out-Null
Write-Host "Disabling Reserved Storage:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager' '/v' 'ShippedWithReserves' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Disabling BitLocker Device Encryption"
@@ -483,6 +483,14 @@ Write-Host "Unmounting image..."
& 'dism' '/English' '/unmount-image' "/mountdir:$mainOSDrive\scratchdir" '/commit'
Write-Host "Exporting image..."
& 'dism' '/English' '/Export-Image' "/SourceImageFile:$mainOSDrive\tiny11\sources\install.wim" "/SourceIndex:$index" "/DestinationImageFile:$mainOSDrive\tiny11\sources\install2.wim" '/compress:max'
+
+# Never delete the source image unless the export actually produced one. A failed export that still deletes
+# install.wim leaves the ISO with no installation image at all, and Windows Setup reports that as
+# "A media driver your computer needs is missing" - which looks like a USB or driver fault and hides the cause.
+if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath "$mainOSDrive\tiny11\sources\install2.wim")) {
+ throw "DISM /Export-Image failed (exit code $LASTEXITCODE). Refusing to delete install.wim."
+}
+
Remove-Item -Path "$mainOSDrive\tiny11\sources\install.wim" -Force >null
Rename-Item -Path "$mainOSDrive\tiny11\sources\install2.wim" -NewName "install.wim" >null
Write-Host "Windows image completed. Continuing with boot.wim."
@@ -511,7 +519,20 @@ Write-Host "Bypassing system requirements(on the setup image):"
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassStorageCheck' '/t' 'REG_DWORD' '/d' '1' '/f' >null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassTPMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' >null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\MoSetup' '/v' 'AllowUpgradesWithUnsupportedTPMOrCPU' '/t' 'REG_DWORD' '/d' '1' '/f' >null
-& 'reg' 'add' 'HKEY_LOCAL_MACHINE\zSYSTEM\Setup' '/v' 'CmdLine' '/t' 'REG_SZ' '/d' 'X:\sources\setup.exe' '/f' >null
+
+# NOTE: this build deliberately does NOT rewrite HKLM\SYSTEM\Setup\CmdLine.
+#
+# It used to be forced to a bare 'X:\sources\setup.exe'. That value is the WinPE setup launch chain a third-party
+# boot manager has to hook in order to work:
+#
+# Ventoy does not extract an ISO. It boots the ISO's own boot.wim and injects vtoyjump.exe so that vtoyjump can
+# mount the ISO as a virtual drive before setup.exe runs. Setup started as X:\sources\setup.exe takes the
+# directory it was loaded from - the boot RAM disk - as the media root, finds no install.wim beside it, and stops
+# with "A media driver your computer needs is missing". That reads like a missing storage driver but only means
+# Setup never saw its media.
+#
+# The stock value launches the boot image's own setup bootstrap, which locates the real media (the USB stick, or
+# the drive Ventoy mounted) and then runs that media's matching sources\setup.exe. Leave it alone.
Write-Host "Tweaking complete!"
Write-Host "Unmounting Registry..."
reg unload HKLM\zCOMPONENTS >null
@@ -524,9 +545,40 @@ Write-Host "Unmounting image..."
Clear-Host
Write-Host "Exporting ESD. This may take a while..."
& dism /Export-Image /SourceImageFile:"$mainOSDrive\tiny11\sources\install.wim" /SourceIndex:1 /DestinationImageFile:"$mainOSDrive\tiny11\sources\install.esd" /Compress:recovery
+
+# Same guard as the WIM export: never delete the source WIM unless the ESD export actually succeeded.
+if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath "$mainOSDrive\tiny11\sources\install.esd")) {
+ throw "DISM /Export-Image to install.esd failed (exit code $LASTEXITCODE). Refusing to delete install.wim."
+}
+
Remove-Item "$mainOSDrive\tiny11\sources\install.wim" > $null 2>&1
Write-Host "The tiny11 image is now completed. Proceeding with the making of the ISO..."
Write-Host "Creating ISO image..."
+
+# Guard: an ISO with no usable installation image produces exactly the symptom "A media driver your computer needs
+# is missing" when Setup looks for its media, which is easy to misread as a USB or driver fault. Fail here instead.
+$installImages = @("$mainOSDrive\tiny11\sources\install.wim", "$mainOSDrive\tiny11\sources\install.esd") |
+ Where-Object { Test-Path -LiteralPath $_ }
+if (-not $installImages) {
+ throw "No install.wim or install.esd in $mainOSDrive\tiny11\sources - the image export step failed. Refusing to build an ISO that Setup cannot install from."
+}
+foreach ($img in $installImages) {
+ $imgMB = [math]::Round((Get-Item -LiteralPath $img).Length / 1MB, 1)
+ Write-Host "Install image $([System.IO.Path]::GetFileName($img)): ${imgMB}MB"
+ if ($imgMB -lt 500) {
+ throw "Install image $img is only ${imgMB}MB - it looks truncated. Refusing to build the ISO."
+ }
+}
+
+# A leftover export would confuse Setup's media detection.
+foreach ($stray in @('install2.wim', 'install2.esd')) {
+ $strayPath = Join-Path "$mainOSDrive\tiny11\sources" $stray
+ if (Test-Path -LiteralPath $strayPath) {
+ Write-Host "Removing leftover $stray from sources\"
+ Remove-Item -Path $strayPath -Force -ErrorAction SilentlyContinue
+ }
+}
+
$ADKDepTools = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg"
$localOSCDIMGPath = "$PSScriptRoot\oscdimg.exe"
@@ -556,7 +608,12 @@ if ([System.IO.Directory]::Exists($ADKDepTools)) {
$OSCDIMG = $localOSCDIMGPath
}
-& "$OSCDIMG" '-m' '-o' '-u2' '-udfver102' "-bootdata:2#p0,e,b$ScratchDisk\tiny11\boot\etfsboot.com#pEF,e,b$ScratchDisk\tiny11\efi\microsoft\boot\efisys.bin" "$ScratchDisk\tiny11" "$PSScriptRoot\tiny11.iso"
+# ---- ISO container --------------------------------------------------------
+# -u2 ISO9660 + Joliet + UDF, the layout Microsoft's own retail media uses. ISO9660 alone cannot hold a
+# >4 GB file, so the UDF layer is what carries install.esd.
+# -udfver150 UDF 1.50 rather than 1.02. UDF 1.02 cannot describe a single file larger than 4 GB and a trimmed
+# install.esd can exceed that. This is a large-file robustness fix; it is not what stopped Ventoy booting.
+& "$OSCDIMG" '-m' '-o' '-u2' '-udfver150' "-bootdata:2#p0,e,b$mainOSDrive\tiny11\boot\etfsboot.com#pEF,e,b$mainOSDrive\tiny11\efi\microsoft\boot\efisys.bin" "$mainOSDrive\tiny11" "$PSScriptRoot\tiny11.iso"
# Finishing up
Write-Host "Creation completed! Press any key to exit the script..."
diff --git a/tiny11maker.ps1 b/tiny11maker.ps1
index c24757f2..cb5cd456 100644
--- a/tiny11maker.ps1
+++ b/tiny11maker.ps1
@@ -394,6 +394,14 @@ Write-Output "Unmounting image..."
Dismount-WindowsImage -Path $ScratchDisk\scratchdir -Save
Write-Host "Exporting image..."
Dism.exe /Export-Image /SourceImageFile:"$ScratchDisk\tiny11\sources\install.wim" /SourceIndex:$index /DestinationImageFile:"$ScratchDisk\tiny11\sources\install2.wim" /Compress:recovery
+
+# Never delete the source image unless the export actually produced one. A failed export that still deletes
+# install.wim leaves the ISO with no installation image at all, and Windows Setup reports that as
+# "A media driver your computer needs is missing" - which looks like a USB or driver fault and hides the cause.
+if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath "$ScratchDisk\tiny11\sources\install2.wim")) {
+ throw "DISM /Export-Image failed (exit code $LASTEXITCODE). Refusing to delete install.wim."
+}
+
Remove-Item -Path "$ScratchDisk\tiny11\sources\install.wim" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny11\sources\install2.wim" -NewName "install.wim" | Out-Null
Write-Output "Windows image completed. Continuing with boot.wim."
@@ -439,6 +447,31 @@ Write-Output "The tiny11 image is now completed. Proceeding with the making of t
Write-Output "Copying unattended file for bypassing MS account on OOBE..."
Copy-Item -Path "$PSScriptRoot\autounattend.xml" -Destination "$ScratchDisk\tiny11\autounattend.xml" -Force | Out-Null
Write-Output "Creating ISO image..."
+
+# Guard: an ISO with no usable installation image produces exactly the symptom "A media driver your computer needs
+# is missing" when Setup looks for its media, which is easy to misread as a USB or driver fault. Fail here instead.
+$installImages = @("$ScratchDisk\tiny11\sources\install.wim", "$ScratchDisk\tiny11\sources\install.esd") |
+ Where-Object { Test-Path -LiteralPath $_ }
+if (-not $installImages) {
+ throw "No install.wim or install.esd in $ScratchDisk\tiny11\sources - the image export step failed. Refusing to build an ISO that Setup cannot install from."
+}
+foreach ($img in $installImages) {
+ $imgMB = [math]::Round((Get-Item -LiteralPath $img).Length / 1MB, 1)
+ Write-Output "Install image $([System.IO.Path]::GetFileName($img)): ${imgMB}MB"
+ if ($imgMB -lt 500) {
+ throw "Install image $img is only ${imgMB}MB - it looks truncated. Refusing to build the ISO."
+ }
+}
+
+# A leftover export would confuse Setup's media detection.
+foreach ($stray in @('install2.wim', 'install2.esd')) {
+ $strayPath = Join-Path "$ScratchDisk\tiny11\sources" $stray
+ if (Test-Path -LiteralPath $strayPath) {
+ Write-Output "Removing leftover $stray from sources\"
+ Remove-Item -Path $strayPath -Force -ErrorAction SilentlyContinue
+ }
+}
+
$ADKDepTools = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg"
$localOSCDIMGPath = "$PSScriptRoot\oscdimg.exe"
@@ -466,7 +499,12 @@ if ([System.IO.Directory]::Exists($ADKDepTools)) {
$OSCDIMG = $localOSCDIMGPath
}
-& "$OSCDIMG" '-m' '-o' '-u2' '-udfver102' "-bootdata:2#p0,e,b$ScratchDisk\tiny11\boot\etfsboot.com#pEF,e,b$ScratchDisk\tiny11\efi\microsoft\boot\efisys.bin" "$ScratchDisk\tiny11" "$PSScriptRoot\tiny11.iso"
+# ---- ISO container --------------------------------------------------------
+# -u2 ISO9660 + Joliet + UDF, the layout Microsoft's own retail media uses. ISO9660 alone cannot hold a
+# >4 GB file, so the UDF layer is what carries install.wim.
+# -udfver150 UDF 1.50 rather than 1.02. UDF 1.02 cannot describe a single file larger than 4 GB and a trimmed
+# install.wim can exceed that. This is a large-file robustness fix; it is not what stopped Ventoy booting.
+& "$OSCDIMG" '-m' '-o' '-u2' '-udfver150' "-bootdata:2#p0,e,b$ScratchDisk\tiny11\boot\etfsboot.com#pEF,e,b$ScratchDisk\tiny11\efi\microsoft\boot\efisys.bin" "$ScratchDisk\tiny11" "$PSScriptRoot\tiny11.iso"
# Finishing up
Write-Output "Creation completed! Press any key to exit the script..."