# TinyWindowsMaker.ps1 - Universal Windows Image Creator # Automatically detects Windows version from ISO and runs the appropriate maker script # or allows manual selection between Windows 10 and Windows 11 param ( [ValidatePattern('^[c-zC-Z]:?$|^[a-zA-Z]:\\.*$')] [string]$ScratchDisk, [string]$windowsisopath, [string]$imageindex, [ValidateSet("10", "11", "auto")] [string]$WindowsVersion = "auto", [switch]$UseSetupTemplate ) # Check if PowerShell execution is Restricted or AllSigned or Undefined $needchange = @("AllSigned", "Restricted", "Undefined") $curpolicy = Get-ExecutionPolicy if ($curpolicy -in $needchange) { Write-Host "Your current PowerShell Execution Policy is set to $curpolicy, which prevents scripts from running. Do you want to change it to RemoteSigned? (yes/no)" $response = Read-Host if ($response -eq 'yes') { Set-ExecutionPolicy RemoteSigned -Scope Process -Confirm:$false } else { Write-Host "The script cannot be run without changing the execution policy. Exiting..." exit } } # Check and run the script as admin if required $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent() $myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID) $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator if (! $myWindowsPrincipal.IsInRole($adminRole)) { Write-Host "Restarting TinyWindowsMaker as admin in a new window, you can close this one." $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"; $argString = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" # Add additional parameters if they are set if ($ScratchDisk) { $argString += " -ScratchDisk `"$ScratchDisk`"" } if ($windowsisopath) { $argString += " -windowsisopath `"$windowsisopath`"" } if ($imageindex) { $argString += " -imageindex `"$imageindex`"" } if ($WindowsVersion -ne "auto") { $argString += " -WindowsVersion `"$WindowsVersion`"" } if ($UseSetupTemplate) { $argString += " -UseSetupTemplate" } $newProcess.Arguments = $argString; $newProcess.Verb = "runas"; [System.Diagnostics.Process]::Start($newProcess); exit } $Host.UI.RawUI.WindowTitle = "TinyWindowsMaker - Universal Windows Image Creator" Clear-Host Write-Host "===================================" Write-Host " TinyWindowsMaker v1.0" Write-Host " Universal Windows Image Creator" Write-Host "===================================" Write-Host "" # Function to detect Windows version from ISO function Get-WindowsVersionFromISO { param([string]$IsoPath) try { Write-Host "Mounting ISO to analyze Windows version..." # Mount the ISO and get the drive letter $mountResult = Mount-DiskImage -ImagePath $IsoPath -PassThru $driveLetter = ($mountResult | Get-Volume).DriveLetter + ":" Write-Host "ISO mounted at drive $driveLetter" # Try to get version info from install.wim or install.esd $installWim = "$driveLetter\sources\install.wim" $installEsd = "$driveLetter\sources\install.esd" $imagePath = $null if (Test-Path $installWim) { $imagePath = $installWim Write-Host "Found install.wim, analyzing..." } elseif (Test-Path $installEsd) { $imagePath = $installEsd Write-Host "Found install.esd, analyzing..." } if ($imagePath) { $imageInfo = Get-WindowsImage -ImagePath $imagePath -Index 1 $version = $imageInfo.Version $imageName = $imageInfo.ImageName Write-Host "Image Name: $imageName" Write-Host "Version: $version" # Parse version to determine Windows 10 or 11 if ($version) { $versionParts = $version.Split('.') if ($versionParts.Count -ge 3) { $buildNumber = [int]$versionParts[2] Write-Host "Build Number: $buildNumber" # Check for unsupported Windows versions (older than Windows 10) if ($buildNumber -lt 10240) { $majorVersion = [int]$versionParts[0] $minorVersion = [int]$versionParts[1] # Determine the Windows version name $windowsVersionName = "Unknown" if ($majorVersion -eq 6) { switch ($minorVersion) { 3 { $windowsVersionName = "Windows 8.1" } 2 { $windowsVersionName = "Windows 8" } 1 { $windowsVersionName = "Windows 7" } 0 { $windowsVersionName = "Windows Vista" } } } elseif ($majorVersion -eq 5) { switch ($minorVersion) { 2 { $windowsVersionName = "Windows XP (64-bit) / Windows Server 2003" } 1 { $windowsVersionName = "Windows XP" } 0 { $windowsVersionName = "Windows 2000" } } } elseif ($majorVersion -lt 5) { $windowsVersionName = "Windows 98/ME or older" } Write-Host "" Write-Host "==========================================" Write-Host " UNSUPPORTED WINDOWS VERSION" Write-Host "==========================================" Write-Host "Detected: $windowsVersionName (Build $buildNumber)" Write-Host "" Write-Host "This tool only supports Windows 10 and Windows 11." Write-Host "Windows versions older than Windows 10 are not supported." Write-Host "" Write-Host "Supported versions:" Write-Host "- Windows 10 (Build 10240 and newer)" Write-Host "- Windows 11 (Build 22000 and newer)" Write-Host "==========================================" return @{ Version = "unsupported" DriveLetter = $driveLetter BuildNumber = $buildNumber ImageName = $imageName WindowsVersionName = $windowsVersionName } } # Windows 11 starts from build 22000 elseif ($buildNumber -ge 22000) { Write-Host "Detected Windows 11 based on build number" return @{ Version = "11" DriveLetter = $driveLetter BuildNumber = $buildNumber ImageName = $imageName } } else { Write-Host "Detected Windows 10 based on build number" return @{ Version = "10" DriveLetter = $driveLetter BuildNumber = $buildNumber ImageName = $imageName } } } } # Fallback: check image name for version hints $imageNameLower = $imageName.ToLower() if ($imageNameLower -match "11" -or $imageNameLower -match "eleven") { Write-Host "Detected Windows 11 based on image name" return @{ Version = "11" DriveLetter = $driveLetter BuildNumber = "Unknown" ImageName = $imageName } } elseif ($imageNameLower -match "10" -or $imageNameLower -match "ten") { Write-Host "Detected Windows 10 based on image name" return @{ Version = "10" DriveLetter = $driveLetter BuildNumber = "Unknown" ImageName = $imageName } } } return @{ Version = $null DriveLetter = $driveLetter BuildNumber = "Unknown" ImageName = "Unknown" } } catch { Write-Host "Warning: Could not analyze ISO file - $($_.Exception.Message)" return $null } } # Function to get source path from user (ISO, WIM, ESD, or drive letter) function Get-IsoPath { do { $srcPath = Read-Host "Enter path to Windows ISO/WIM/ESD file, or a mounted drive letter (e.g. C:\Win11.iso, D:)" if ([string]::IsNullOrEmpty($srcPath)) { Write-Host "Please enter a valid path." continue } # Drive letter shorthand if ($srcPath -match '^[c-zC-Z]:?$') { return $srcPath.TrimEnd('\') + ":" } if (-not (Test-Path $srcPath)) { Write-Host "Path not found: $srcPath" continue } $ext = [System.IO.Path]::GetExtension($srcPath).ToLower() if ($ext -notin @('.iso', '.wim', '.esd')) { Write-Host "Unsupported file type '$ext'. Accepted: .iso, .wim, .esd" continue } return $srcPath } while ($true) } # Helper: detect Windows version from a WIM or ESD file directly (no mount needed) function Get-WindowsVersionFromWimEsd { param([string]$FilePath) try { $allIndexes = Get-WindowsImage -ImagePath $FilePath # WOR-format ESDs have >=4 indexes; OS edition is the last one. # Install-only WIMs/ESDs use index 1. $targetIdx = if ($allIndexes.Count -ge 4) { $allIndexes[-1].ImageIndex } else { 1 } $imgInfo = Get-WindowsImage -ImagePath $FilePath -Index $targetIdx $ver = $imgInfo.Version $name = $imgInfo.ImageName if ($ver) { $parts = $ver.Split('.') if ($parts.Count -ge 3) { $build = [int]$parts[2] $winVer = if ($build -lt 10240) { "unsupported" } elseif ($build -ge 22000) { "11" } else { "10" } return @{ Version = $winVer; BuildNumber = $build; ImageName = $name; DriveLetter = $FilePath } } } return @{ Version = $null; BuildNumber = "Unknown"; ImageName = $name; DriveLetter = $FilePath } } catch { Write-Host "Warning: Could not read WIM/ESD: $($_.Exception.Message)" return $null } } # Determine the source and mount it if needed $isoPath = $null $isoInfo = $null # Normalize windowsisopath: accept D, D:, D:\ all as drive letter D: if ($windowsisopath -match '^[a-zA-Z]:?\\?$') { $windowsisopath = $windowsisopath[0] + ':' } # Resolve input: parameter, or ask user $sourcePath = if ($windowsisopath) { $windowsisopath } else { Get-IsoPath } $ext = [System.IO.Path]::GetExtension($sourcePath).ToLower() if ($sourcePath -match '^[c-zC-Z]:$') { # Already-mounted drive letter Write-Host "Drive letter provided: $sourcePath" $hasInstallWim = Test-Path "$sourcePath\sources\install.wim" $hasInstallEsd = Test-Path "$sourcePath\sources\install.esd" $hasBootWim = Test-Path "$sourcePath\sources\boot.wim" # Multi-arch ISO: no sources\ at root, but x64\sources\ present — use x64 for detection $versionSrcBase = $sourcePath if (-not $hasInstallWim -and -not $hasInstallEsd -and (Test-Path "$sourcePath\x64\sources")) { Write-Host "Multi-architecture ISO detected. Using x64." $versionSrcBase = "$sourcePath\x64" $hasInstallWim = Test-Path "$versionSrcBase\sources\install.wim" $hasInstallEsd = Test-Path "$versionSrcBase\sources\install.esd" $hasBootWim = Test-Path "$versionSrcBase\sources\boot.wim" } if (-not $hasInstallWim -and -not $hasInstallEsd) { Write-Host "Error: Windows installation files not found in $sourcePath\sources\" Write-Host "Expected install.wim or install.esd" Write-Host "" Write-Host "Root of ${sourcePath}:" Get-ChildItem "$sourcePath\" -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name)" } Write-Host "" Write-Host "Contents of ${sourcePath}\sources (if it exists):" Get-ChildItem "$sourcePath\sources\" -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name)" } Read-Host "Press Enter to exit" exit } if (-not $hasBootWim) { if ($hasInstallEsd -and -not $hasInstallWim) { Write-Host "Note: boot.wim not found. ESD-only media - maker script will build boot structure." } else { Write-Host "Error: boot.wim not found in $versionSrcBase\sources\" Read-Host "Press Enter to exit" exit } } $isoInfo = @{ Version = $null; DriveLetter = $sourcePath; BuildNumber = "Unknown"; ImageName = "Unknown" } if ($WindowsVersion -eq "auto") { try { $imgSrc = if (Test-Path "$versionSrcBase\sources\install.wim") { "$versionSrcBase\sources\install.wim" } else { "$versionSrcBase\sources\install.esd" } $imgDetail = Get-WindowsImage -ImagePath $imgSrc -Index 1 $parts = $imgDetail.Version.Split('.') if ($parts.Count -ge 3) { $build = [int]$parts[2] $isoInfo.Version = if ($build -lt 10240) { "unsupported" } elseif ($build -ge 22000) { "11" } else { "10" } $isoInfo.BuildNumber = $build $isoInfo.ImageName = $imgDetail.ImageName } } catch { Write-Host "Warning: Could not auto-detect version from drive." } } } elseif ($ext -in @('.wim', '.esd')) { # Direct WIM/ESD - pass the file path straight to the maker script if (-not (Test-Path $sourcePath)) { Write-Host "Error: File not found: $sourcePath" Read-Host "Press Enter to exit" exit } Write-Host "WIM/ESD source detected: $sourcePath" $isoInfo = Get-WindowsVersionFromWimEsd -FilePath (Resolve-Path $sourcePath).Path if (-not $isoInfo) { Write-Host "Error: Could not read WIM/ESD file." Read-Host "Press Enter to exit" exit } } else { # ISO file - mount it and detect version if (-not (Test-Path $sourcePath)) { Write-Host "Error: File not found: $sourcePath" Read-Host "Press Enter to exit" exit } $isoPath = $sourcePath $isoInfo = Get-WindowsVersionFromISO -IsoPath $isoPath if (-not $isoInfo) { Write-Host "Error: Could not mount or analyze the ISO." Read-Host "Press Enter to exit" exit } } # Determine which script to run $scriptToRun = $null $detectedVersion = $null if ($WindowsVersion -eq "auto") { if ($isoInfo.Version -eq "unsupported") { Write-Host "" Write-Host "==========================================" Write-Host " UNSUPPORTED WINDOWS VERSION" Write-Host "==========================================" Write-Host "Build: $($isoInfo.BuildNumber)" Write-Host "Image: $($isoInfo.ImageName)" Write-Host "" Write-Host "This tool only supports Windows 10 and Windows 11." Write-Host "Windows versions older than Windows 10 are not supported." Write-Host "" Write-Host "Supported versions:" Write-Host "- Windows 10 (Build 10240 and newer)" Write-Host "- Windows 11 (Build 22000 and newer)" Write-Host "==========================================" Write-Host "" Read-Host "Press Enter to exit" exit } elseif ($isoInfo.Version) { Write-Host "Detected Windows $($isoInfo.Version)" Write-Host "Build: $($isoInfo.BuildNumber)" Write-Host "Image: $($isoInfo.ImageName)" $detectedVersion = $isoInfo.Version $scriptToRun = "tiny$detectedVersion" + "maker.ps1" } else { Write-Host "Could not automatically detect Windows version." Write-Host "" Write-Host "Please select the Windows version:" Write-Host "1. Windows 10" Write-Host "2. Windows 11" do { $choice = Read-Host "Enter your choice (1 or 2)" switch ($choice) { "1" { $scriptToRun = "tiny10maker.ps1" $detectedVersion = "10" } "2" { $scriptToRun = "tiny11maker.ps1" $detectedVersion = "11" } default { Write-Host "Invalid choice. Please enter 1 or 2." } } } while ($choice -notin @("1", "2")) } } else { Write-Host "Manual Windows version specified: Windows $WindowsVersion" $scriptToRun = "tiny$WindowsVersion" + "maker.ps1" $detectedVersion = $WindowsVersion } # Verify the target script exists $scriptPath = Join-Path $PSScriptRoot $scriptToRun if (-not (Test-Path $scriptPath)) { Write-Host "Error: Cannot find $scriptToRun in $PSScriptRoot" Write-Host "Please make sure the script file exists." Read-Host "Press Enter to exit" exit } Write-Host "" Write-Host "===========================================" Write-Host "Starting Tiny Windows $detectedVersion creation process..." Write-Host "Using script: $scriptToRun" Write-Host "===========================================" Write-Host "" # Build the argument string for the target script $argumentList = @() $argumentList += "-NoProfile" $argumentList += "-ExecutionPolicy" $argumentList += "Bypass" $argumentList += "-File" $argumentList += "`"$scriptPath`"" if ($ScratchDisk) { $argumentList += "-ScratchDisk" $argumentList += "`"$ScratchDisk`"" } # Pass the source path - drive letter, ISO path, or WIM/ESD path. # The maker scripts resolve all three formats. $argumentList += "-windowsisopath" $argumentList += "`"$($isoInfo.DriveLetter)`"" if ($imageindex) { $argumentList += "-imageindex" $argumentList += "`"$imageindex`"" } if ($UseSetupTemplate) { $argumentList += "-UseSetupTemplate" } # Start the appropriate maker script try { $process = Start-Process -FilePath "PowerShell" -ArgumentList $argumentList -Wait -PassThru -NoNewWindow if ($process.ExitCode -eq 0) { Write-Host "" Write-Host "===========================================" Write-Host "Tiny Windows $detectedVersion creation completed successfully!" Write-Host "===========================================" } else { Write-Host "" Write-Host "===========================================" Write-Host "Tiny Windows $detectedVersion creation failed with exit code: $($process.ExitCode)" Write-Host "===========================================" } } catch { Write-Host "Error running $scriptToRun`: $($_.Exception.Message)" } finally { # Unmount the ISO if we mounted it if ($isoPath) { try { Write-Host "Unmounting ISO..." Dismount-DiskImage -ImagePath $isoPath | Out-Null Write-Host "ISO unmounted successfully." } catch { Write-Host "Warning: Could not unmount ISO - $($_.Exception.Message)" } } } Write-Host "" Read-Host "Press Enter to exit"