|
|
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Security;
- using System.Windows.Forms;
- using Ameliorated.ConsoleUtils;
- using Microsoft.Dism;
-
- // Asks user to select Windows installation media, and mounts it if applicable
- // Returns path to where it's mounted
-
- namespace amecs.Misc
- {
- public static class SelectWindowsImage
- {
- private static string _fileViolationTest;
- private static bool CheckFileViolation(string inputFile)
- {
- try
- {
- _fileViolationTest = inputFile;
- }
- catch (SecurityException e)
- {
- Console.WriteLine();
- ConsoleTUI.OpenFrame.Close("Security exception: " + e.Message, ConsoleColor.Red, Console.BackgroundColor, new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return true;
- }
-
- return false;
- }
-
- public static string GetWindowsVersion(float majorMinor, int isoBuild)
- {
- return (majorMinor, isoBuild) switch
- {
- (6, _) => "Windows Vista",
- (6.1f, _) => "Windows 7",
- (6.2f, _) => "Windows 8",
- (6.3f, _) => "Windows 8.1",
- (10, var a) when a < 19041 => "Windows 10 (Old)",
- (10, var a) when a >= 22000 => "Windows 11",
- (10, _) => "Windows 10",
- _ => "Unknown"
- };
- }
-
- public static bool DismountIso(string imagePath)
- {
- var startInfo = new ProcessStartInfo
- {
- CreateNoWindow = false,
- UseShellExecute = false,
- FileName = "PowerShell.exe",
- WindowStyle = ProcessWindowStyle.Hidden,
- Arguments = $"-NoP -C \"Dismount-DiskImage '{imagePath}'\"",
- RedirectStandardOutput = true
- };
-
- var proc = Process.Start(startInfo);
- if (proc == null) return false;
- proc.WaitForExit();
- return true;
- }
-
- private static string _mountedPath;
- private static string _isoPath;
- private static string _isoWinVer;
- private static int _isoBuild;
-
- /// <summary>
- /// Asks user to select Windows installation media, mounts it if applicable, and checks its version
- /// </summary>
- /// <param name="winVersionsMustMatch">If true when ISO and host versions mismatch, prompts user that things can break if they continue</param>
- /// <param name="isoBuildMustBeReturned">If true and the ISO build can't be retrieved, prompts a user with an error</param>
- public static (
- string MountedPath, string IsoPath, string Winver, int? Build, bool? VersionsMatch
- ) GetMediaPath(bool winVersionsMustMatch = false, bool isoBuildMustBeReturned = false)
- {
- var error = ((string)null, "none", (string)null, (int?)null, (bool?)null);
- var choice =
- new ChoicePrompt { Text = "To continue, Windows installation media is needed.\r\nDo you have a Windows USB instead of an ISO file? (Y/N): " }.Start();
- if (!choice.HasValue) return error;
-
- // Folder/drive chosen
- var usingFolder = choice == 0;
- if (usingFolder)
- {
- var dlg = new FolderPicker
- {
- InputPath = Globals.UserFolder
- };
-
- if (dlg.ShowDialog(IntPtr.Zero).GetValueOrDefault())
- {
- if (CheckFileViolation(dlg.ResultPath))
- return error;
-
- _mountedPath = dlg.ResultPath;
- }
- else
- {
- Console.WriteLine();
- ConsoleTUI.OpenFrame.Close("\r\nYou must select a folder or drive containing Windows installation media.",
- new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return error;
- }
- }
- else
- {
- // Mounting the ISO
- var dialog = new OpenFileDialog();
- dialog.Filter = "ISO Files (*.ISO)| *.ISO";
- dialog.Multiselect = false;
- dialog.InitialDirectory = Globals.UserFolder;
-
- var window = new NativeWindow();
- window.AssignHandle(Process.GetCurrentProcess().MainWindowHandle);
- if (dialog.ShowDialog(window) == DialogResult.OK)
- {
- _isoPath = dialog.FileName;
- if (CheckFileViolation(_isoPath)) return error;
- Console.WriteLine();
- ConsoleTUI.OpenFrame.WriteCentered("\r\nMounting ISO");
- }
- else
- {
- Console.WriteLine();
- ConsoleTUI.OpenFrame.Close("\r\nYou must select an ISO.",
- new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return error;
- }
-
- using (new ConsoleUtils.LoadingIndicator(true))
- {
- var startInfo = new ProcessStartInfo
- {
- CreateNoWindow = false,
- UseShellExecute = false,
- FileName = "PowerShell.exe",
- WindowStyle = ProcessWindowStyle.Hidden,
- Arguments = $"-NoP -C \"(Mount-DiskImage '{_isoPath}' -PassThru | Get-Volume).DriveLetter + ':\'\"",
- RedirectStandardOutput = true
- };
-
- var proc = Process.Start(startInfo);
- if (proc == null) return error;
- proc.WaitForExit();
-
- _mountedPath = proc.StandardOutput.ReadLine();
- }
- }
-
- // Check WIM version
- var wimOrEsdPath = new[] { $@"{_mountedPath}\sources\install.esd", $@"{_mountedPath}\sources\install.wim" }.FirstOrDefault(File.Exists);
- if (!string.IsNullOrEmpty(wimOrEsdPath))
- {
- try
- {
- DismApi.Initialize(DismLogLevel.LogErrors);
-
- string previousIndexVersion = null;
- string isoFullVersion = null;
- var multiVersion = false;
-
- var imageInfos = DismApi.GetImageInfo(wimOrEsdPath);
- foreach (var imageInfo in imageInfos)
- {
- isoFullVersion = imageInfo.ProductVersion.ToString();
- if (isoFullVersion != previousIndexVersion && previousIndexVersion != null)
- {
- // If it's multi-version, WinVer will be "Unknown" as well
- multiVersion = true;
- isoFullVersion = "0.0.0.0";
- break;
- }
- previousIndexVersion = isoFullVersion;
- }
-
- switch (multiVersion)
- {
- case true when isoBuildMustBeReturned:
- ConsoleTUI.OpenFrame.Close(
- "Multiple Windows versions were found in the Windows image, can't determine which Windows build it is. Please use an unmodified Windows ISO.",
- ConsoleColor.Red, Console.BackgroundColor,
- new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return error;
- case true when winVersionsMustMatch:
- ConsoleTUI.OpenFrame.Close(
- "Multiple Windows versions were found in the Windows image, can't determine which Windows build it is. If your Windows version doesn't match the ISO, there will be problems.",
- ConsoleColor.Red, Console.BackgroundColor,
- new ChoicePrompt { AnyKey = true, Text = "Press any key to continue anyways: " });
-
- Program.Frame.Clear();
- ConsoleTUI.OpenFrame.WriteCentered("\r\nContinuing without version check...\r\n");
- break;
- }
-
- var buildSplit = isoFullVersion.Split('.');
- _isoBuild = int.Parse(buildSplit[2]);
- _isoWinVer = GetWindowsVersion(float.Parse($"{buildSplit[0]}.{buildSplit[1]}"), _isoBuild);
- }
- catch (Exception e)
- {
- Console.WriteLine();
- ConsoleTUI.OpenFrame.Close(
- "Error checking ISO version: " + e.Message.TrimEnd('\n').TrimEnd('\r'),
- ConsoleColor.Red, Console.BackgroundColor,
- new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return error;
- }
- finally
- {
- try
- {
- DismApi.Shutdown();
- }
- catch
- {
- // do nothing
- }
- }
-
- // Check the current OS version
- var hostVersion = Environment.OSVersion.Version;
- var hostWinver = GetWindowsVersion(float.Parse($"{hostVersion.Major}.{hostVersion.Minor}"), hostVersion.Build);
-
- // If it all matches & winVersionsMustMatch
- if (hostWinver == _isoWinVer) return (_mountedPath, _isoPath, _isoWinVer, _isoBuild, true);
- // If ISO version doesn't match host version & winVersionsMustMatch
- if (hostWinver != _isoWinVer && winVersionsMustMatch)
- {
- if (!string.IsNullOrEmpty(_isoPath)) DismountIso(_isoPath);
- ConsoleTUI.OpenFrame.Close(
- $"You're on {hostWinver}, but the selected image is {_isoWinVer}. You can only use an ISO that matches your Windows version.",
- ConsoleColor.Red, Console.BackgroundColor,
- new ChoicePrompt { AnyKey = true, Text = "Press any key to return to the Menu: " });
- return error;
- }
-
- // If ISO version doesn't match host version, and winVersionsMustMatch is true
- if (hostWinver != _isoWinVer) return (_mountedPath, _isoPath, _isoWinVer, _isoBuild, false);
- }
-
- var noWimText = isoBuildMustBeReturned
- ? "Press any key to return to the Menu"
- : "Press any key to continue anyways";
-
- ConsoleTUI.OpenFrame.Close(
- "No Windows installation image was found inside the selected Windows media. No version check can be done, things might break.",
- ConsoleColor.Red, Console.BackgroundColor,
- new ChoicePrompt { AnyKey = true, Text = $"{noWimText}: " });
-
- Program.Frame.Clear();
- ConsoleTUI.OpenFrame.WriteCentered("\r\nContinuing without version check\r\n");
-
- return isoBuildMustBeReturned ? error : (_mountedPath, _isoPath, null, null, null);
- }
- }
- }
|