diff --git a/src/Actions/.NET.cs b/src/Actions/.NET.cs index e3c76a5..8d34840 100644 --- a/src/Actions/.NET.cs +++ b/src/Actions/.NET.cs @@ -7,8 +7,7 @@ using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading; -using System.Windows.Forms; -using Misc.FolderPicker; +using amecs.Misc; using Ameliorated.ConsoleUtils; using Microsoft.Dism; @@ -16,103 +15,28 @@ namespace amecs.Actions { public class _NET { - private static string file; - private static bool CheckFileViolation(string inputFile) - { - try - { - file = inputFile; - } - catch (SecurityException e) - { - Console.WriteLine(); - ConsoleTUI.OpenFrame.Close("Security error: " + e.Message, ConsoleColor.Red, Console.BackgroundColor, new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " }); - return true; - } + private static string _mountedPath; + private static string _isoPath; - return false; - } - - private static bool DismountImage() + private static void Unmount() { - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.CreateNoWindow = false; - startInfo.UseShellExecute = false; - startInfo.FileName = "PowerShell.exe"; - startInfo.WindowStyle = ProcessWindowStyle.Hidden; - startInfo.Arguments = $"-NoP -C \"Dismount-DiskImage '{file}'\""; - startInfo.RedirectStandardOutput = true; - - var proc = Process.Start(startInfo); - proc.WaitForExit(); - return true; + if (_isoPath == "none") + return; + + SelectWindowsImage.DismountIso(_isoPath); } public static bool Install() { - string letter; - - var choice = new ChoicePrompt() { Text = "To install .NET 3.5, Windows installation media is needed.\r\nDo you have a Windows USB instead of an ISO? (Y/N): " }.Start(); - if (choice == null) return false; - var usingFolder = choice == 0; - if (usingFolder) - { - var dlg = new FolderPicker(); - dlg.InputPath = Globals.UserFolder; - if (!dlg.ShowDialog(IntPtr.Zero, false).GetValueOrDefault()) - { - Console.WriteLine(); - ConsoleTUI.OpenFrame.Close("\r\nYou must select a folder or drive.", new ChoicePrompt() {AnyKey = true, Text = "Press any key to return to the Menu: "}); - return true; - } - if (CheckFileViolation(dlg.ResultPath)) return false; - letter = dlg.ResultPath; - } - else - { - var dialog = new System.Windows.Forms.OpenFileDialog(); - dialog.Filter = "ISO Files (*.ISO)| *.ISO"; // Filter files by extension - dialog.Multiselect = false; - dialog.InitialDirectory = Globals.UserFolder; + (_mountedPath, _isoPath, _, _, _) = SelectWindowsImage.GetMediaPath(true); + if (_mountedPath == null) return false; - NativeWindow window = new NativeWindow(); - window.AssignHandle(Process.GetCurrentProcess().MainWindowHandle); - if (dialog.ShowDialog(window) == DialogResult.OK) - { - if (CheckFileViolation(dialog.FileName)) return false; - 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 true; - } - - using (new ConsoleUtils.LoadingIndicator(true)) - { - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.CreateNoWindow = false; - startInfo.UseShellExecute = false; - startInfo.FileName = "PowerShell.exe"; - startInfo.WindowStyle = ProcessWindowStyle.Hidden; - startInfo.Arguments = - $"-NoP -C \"(Mount-DiskImage '{file}' -PassThru | Get-Volume).DriveLetter + ':\'\""; - startInfo.RedirectStandardOutput = true; - - var proc = Process.Start(startInfo); - proc.WaitForExit(); - - letter = proc.StandardOutput.ReadLine(); - } - } - - if (!Directory.Exists(letter + @"\sources\sxs") || !Directory.GetFiles(letter + @"\sources\sxs", "*netfx3*").Any()) + if (!Directory.Exists(_mountedPath + @"\sources\sxs") || !Directory.GetFiles(_mountedPath + @"\sources\sxs", "*netfx3*").Any()) { - DismountImage(); + Unmount(); Console.WriteLine(); - ConsoleTUI.OpenFrame.Close("ISO/USB/folder does not contain the required files.", ConsoleColor.Red, Console.BackgroundColor, new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " }); + ConsoleTUI.OpenFrame.Close("ISO/USB/folder does not contain the required files.", + ConsoleColor.Red, Console.BackgroundColor, new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " }); return false; } @@ -120,63 +44,51 @@ namespace amecs.Actions var topCache = Console.CursorTop; var leftCache = Console.CursorLeft; Console.WriteLine(); - bool inProgress = false; + var inProgress = false; try { - using (var indicator = new ConsoleUtils.LoadingIndicator()) + using var indicator = new ConsoleUtils.LoadingIndicator(); + DismApi.Initialize(DismLogLevel.LogErrors); + using (var session = DismApi.OpenOnlineSession()) { - DismApi.Initialize(DismLogLevel.LogErrors); - using (var session = DismApi.OpenOnlineSession()) + var stdout = GetStdHandle(-11); + var indicatorStopped = false; + var maxHashTags = (ConsoleTUI.OpenFrame.DisplayWidth - 5); + DismApi.EnableFeatureByPackagePath(session, "NetFX3", null, true, true, new List() { _mountedPath + @"\sources\sxs" }, delegate(DismProgress progress) { - var stdout = GetStdHandle(-11); - bool indicatorStopped = false; - var maxHashTags = (ConsoleTUI.OpenFrame.DisplayWidth - 5); - DismApi.EnableFeatureByPackagePath(session, "NetFX3", null, true, true, new List() { letter + @"\sources\sxs" }, delegate(DismProgress progress) + inProgress = true; + if (!indicatorStopped) { - inProgress = true; - if (!indicatorStopped) - { - indicator.Stop(); - Console.SetCursorPosition(leftCache, topCache); - Console.WriteLine(" "); - } - - indicatorStopped = true; - var progressPerc = progress.Current / 10; - var currentHashTags = (int)Math.Ceiling(Math.Min(((double)progressPerc / 100) * maxHashTags, maxHashTags)); - var spaces = maxHashTags - currentHashTags + (4 - progressPerc.ToString().Length); - var sb = new StringBuilder(new string('#', currentHashTags) + new string(' ', spaces) + progressPerc + "%"); - uint throwaway; - WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out throwaway); - inProgress = false; - }); - session.Close(); - Thread.Sleep(100); - var sb = new StringBuilder(new string('#', maxHashTags) + " 100%"); - uint throwaway; - WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out throwaway); - } + indicator.Stop(); + Console.SetCursorPosition(leftCache, topCache); + Console.WriteLine(" "); + } - DismApi.Shutdown(); - if (!usingFolder) DismountImage(); + indicatorStopped = true; + var progressPercentage = progress.Current / 10; + var currentHashTags = (int)Math.Ceiling(Math.Min(((double)progressPercentage / 100) * maxHashTags, maxHashTags)); + var spaces = maxHashTags - currentHashTags + (4 - progressPercentage.ToString().Length); + var sb = new StringBuilder(new string('#', currentHashTags) + new string(' ', spaces) + progressPercentage + "%"); + WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out _); + inProgress = false; + }); + session.Close(); + Thread.Sleep(100); + var sb = new StringBuilder(new string('#', maxHashTags) + " 100%"); + uint throwaway; + WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out throwaway); } + + DismApi.Shutdown(); + Unmount(); } catch (Exception e) { while (inProgress) { Thread.Sleep(50); } - - if (!usingFolder) - { - try - { - DismountImage(); - } - catch (Exception ex) - { - } - } + + Unmount(); Console.WriteLine(); Console.WriteLine(); @@ -190,7 +102,6 @@ namespace amecs.Actions Console.WriteLine(); Console.WriteLine(); - if (!usingFolder) ConsoleTUI.OpenFrame.Close(".NET 3.5 installed successfully", ConsoleColor.Green, Console.BackgroundColor, new ChoicePrompt() { AnyKey = true, diff --git a/src/Actions/Deameliorate.cs b/src/Actions/Deameliorate.cs new file mode 100644 index 0000000..eb24c3c --- /dev/null +++ b/src/Actions/Deameliorate.cs @@ -0,0 +1,239 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Security.Principal; +using System.Threading; +using amecs.Misc; +using Ameliorated.ConsoleUtils; +using Microsoft.Win32; + +namespace amecs.Actions +{ + public class Deameliorate + { + private static string _mountedPath; + private static string _winVer; + private static string _win11Setup = ""; + private static bool _win11 = Environment.OSVersion.Version.Build >= 22000; + private const string ExplorerPatcherId = "D17F1E1A-5919-4427-8F89-A1A8503CA3EB"; + + public static bool DeAme() + { + if (new ChoicePrompt() + { + Text = @" +This will de-ameliorate by reinstalling Windows. + +Although user data should be kept, we strongly recommend +making backups of any important user data. + +Continue? (Y/N): " + }.Start().Value == 1) return true; + + Program.Frame.Clear(); + (_mountedPath, _, _winVer, _, _) = SelectWindowsImage.GetMediaPath(); + if (_mountedPath == null) return false; + + if (new ChoicePrompt {Text = $"\r\nYour Windows image is {_winVer}. Continue? (Y/N): "}.Start().Value == 1) + return true; + + var fc = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + + string userSid = null; + try + { + NSudo.GetSystemPrivilege(); + NSudo.RunAsUser(() => + { + userSid = WindowsIdentity.GetCurrent().User.ToString(); + }); + } + catch + { + // do nothing + } + + try + { + ConsoleTUI.OpenFrame.WriteCentered("\r\nUninstalling AME-installed UI software..."); + + string openShellId = null; + + var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"); + foreach (var item in key.GetSubKeyNames()) + { + try + { + if (((string)key.OpenSubKey(item).GetValue("DisplayName")).Equals("Open-Shell")) + openShellId = item; + } + catch + { + // do nothing + } + } + + if (openShellId != null) + { + ConsoleTUI.OpenFrame.WriteCentered("\r\nUninstalling Open-Shell..."); + + Process.Start("MsiExec.exe", $"/X{openShellId} /quiet")?.WaitForExit(); + + if (userSid != null) + { + var appData = (string)Registry.Users.OpenSubKey(userSid + @"\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders").GetValue("AppData"); + + if (Directory.Exists(Path.Combine(appData, "OpenShell"))) + Directory.Delete(Path.Combine(appData, "OpenShell"), true); + } + } + + var epSetupPath = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)}\ExplorerPatcher\ep_setup.exe"; + if (File.Exists(epSetupPath)) + { + ConsoleTUI.OpenFrame.WriteCentered("\r\nUninstalling ExplorerPatcher..."); + + var winlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true); + winlogon?.SetValue("AutoRestartShell", 0); + + // kill processes that the files use + foreach (var processName in new[] {"explorer.exe", "rundll32.exe", "dllhost.exe", "ShellExperienceHost.exe", "StartMenuExperienceHost.exe"}) + { + foreach (var process in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processName))) + { + process.Kill(); + process.WaitForExit(); + } + } + + // delete DWM service that removes rounded corners + Process.Start("sc", $"stop \"ep_dwm_{ExplorerPatcherId}\"")?.WaitForExit(); + Process.Start("sc", $"delete \"ep_dwm_{ExplorerPatcherId}\"")?.WaitForExit(); + + // remove registered DLL + var explorerPatcherDllPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "ExplorerPatcher", "ExplorerPatcher.amd64.dll"); + Process.Start("regsvr32.exe", $"/s /u \"{explorerPatcherDllPath}\"")?.WaitForExit(); + + // delete files + foreach (var file in new[] + { + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\ShellExperienceHost_cw5n1h2txyewy\dxgi.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\ShellExperienceHost_cw5n1h2txyewy\wincorlib.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\ShellExperienceHost_cw5n1h2txyewy\wincorlib_orig.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\dxgi.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\wincorlib.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + @"SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\wincorlib_orig.dll"), + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), + "dxgi.dll") + }) + { + if (File.Exists(file)) File.Delete(file); + } + foreach (var folder in new[] + { + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "ExplorerPatcher"), + Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + @"Microsoft\Windows\Start Menu\Programs\ExplorerPatcher") + }) + { + if (Directory.Exists(folder)) Directory.Delete(folder, true); + } + + winlogon?.SetValue("AutoRestartShell", 1); + } + + Program.Frame.Clear(); + } catch (Exception e) + { + ConsoleTUI.OpenFrame.Close( + "Error when uninstalling software: " + e.Message, + ConsoleColor.Red, Console.BackgroundColor, + new ChoicePrompt { AnyKey = true, Text = "Press any key to continue anyways: " }); + + Program.Frame.Clear(); + ConsoleTUI.OpenFrame.WriteCentered("\r\nContinuing without uninstalling software...\r\n"); + } + + // restart Explorer + if (Process.GetProcessesByName("explorer").Length == 0) + NSudo.RunProcessAsUser(NSudo.GetUserToken(), "explorer.exe", "", 0); + + // all policies are cleared as a user that's de-ameliorating is unlikely to have their own policies in the first place + // also clear ExplorerPatcher Registry entries + ConsoleTUI.OpenFrame.WriteCentered("\r\nClearing policies..."); + foreach (var keyPath in new[] { + $@"HKU\{userSid}\Software\Microsoft\Windows\CurrentVersion\Policies", + $@"HKU\{userSid}\Software\Policies", + $@"HKU\{userSid}\Software\ExplorerPatcher", + $@"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{{ExplorerPatcherId}}}_ExplorerPatcher", + @"HKLM\Software\Microsoft\Windows\CurrentVersion\Policies", + @"HKLM\Software\Policies", + @"HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Policies" + }) + { + var hive = RegistryHive.LocalMachine; + if (keyPath.StartsWith("HKU")) + hive = RegistryHive.Users; + + var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default); + var subKeyPath = keyPath.Substring(keyPath.IndexOf('\\') + 1); + var key = baseKey.OpenSubKey(subKeyPath, true); + if (key == null) continue; + + try + { + baseKey.DeleteSubKeyTree(subKeyPath); + } + catch + { + // do nothing - some values might fail, but almost all are deleted + } + + key.Close(); + } + + Thread.Sleep(3000); + Program.Frame.Clear(); + ConsoleTUI.OpenFrame.WriteCentered("\r\nCompleted initial setup!", ConsoleColor.Green); + if (_win11) + { + ConsoleTUI.OpenFrame.WriteCentered("\r\nWindows Setup will display as 'Windows Server,' but it's not actually installing Windows Server and is only set as such to bypass hardware requirements."); + Console.WriteLine(); + } + ConsoleTUI.OpenFrame.WriteCentered("\r\nWaiting 10 seconds and starting Windows Setup..."); + + Console.ForegroundColor = fc; + Thread.Sleep(10000); + Console.WriteLine(); + try + { + if (_win11) _win11Setup = "/Product Server"; + Process.Start(Path.Combine(_mountedPath, "setup.exe"), $"/Auto Upgrade /DynamicUpdate Disable {_win11Setup}"); + } catch (Exception e) + { + ConsoleTUI.OpenFrame.Close( + $"There was an error when trying to run the Windows Setup: {e}\r\nTry running the Windows Setup manually from File Explorer.", + ConsoleColor.Red, Console.BackgroundColor, + new ChoicePrompt { AnyKey = true, Text = $"Press any key to exit: " }); + + return false; + } + + ConsoleTUI.OpenFrame.Close( + "Completed, Windows Setup should have started.", + ConsoleColor.Cyan, Console.BackgroundColor, + new ChoicePrompt { AnyKey = true, Text = $"Press any key to go back: " }); + + return true; + } + } +} \ No newline at end of file diff --git a/src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs b/src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs index c39429f..7831bdc 100644 --- a/src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs +++ b/src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs @@ -323,6 +323,7 @@ namespace Ameliorated.ConsoleUtils ConsoleUtils.ResetColor(); } + // TODO: Fix this splitting lines when a piece of text can fit on one line private List CenterLines(string text, LineCenterOptions options, int maxWidth = 0) { var _maxWidth = DisplayWidth; diff --git a/src/Ameliorated.ConsoleUtils/ConsoleTUI/Menu.cs b/src/Ameliorated.ConsoleUtils/ConsoleTUI/Menu.cs index cc62416..143ff42 100644 --- a/src/Ameliorated.ConsoleUtils/ConsoleTUI/Menu.cs +++ b/src/Ameliorated.ConsoleUtils/ConsoleTUI/Menu.cs @@ -164,7 +164,7 @@ namespace Ameliorated.ConsoleUtils while (true) { keyPressed = Console.ReadKey(true).Key; - if (keyPressed == ConsoleKey.DownArrow) + if (keyPressed == ConsoleKey.DownArrow || keyPressed == ConsoleKey.S) { if (validIndex >= currentValidChoices.Count - 1) continue; Console.SetCursorPosition(Math.Max(TotalOffset - 2, 0), Console.CursorTop); @@ -182,7 +182,7 @@ namespace Ameliorated.ConsoleUtils validIndex += 1; } - if (keyPressed == ConsoleKey.UpArrow) + if (keyPressed == ConsoleKey.UpArrow || keyPressed == ConsoleKey.W) { if (!(validIndex > 0)) continue; @@ -201,7 +201,7 @@ namespace Ameliorated.ConsoleUtils validIndex -= 1; } - if (keyPressed == ConsoleKey.RightArrow || keyPressed == ConsoleKey.PageUp || + if (keyPressed == ConsoleKey.RightArrow || keyPressed == ConsoleKey.A || keyPressed == ConsoleKey.PageUp || (keyPressed == ConsoleKey.Enter && currentValidChoices[validIndex].IsNextButton)) { if (pageIndex == pages) @@ -245,7 +245,7 @@ namespace Ameliorated.ConsoleUtils continue; } - if (keyPressed == ConsoleKey.LeftArrow || keyPressed == ConsoleKey.PageDown || + if (keyPressed == ConsoleKey.LeftArrow || keyPressed == ConsoleKey.D || keyPressed == ConsoleKey.PageDown || (keyPressed == ConsoleKey.Enter && currentValidChoices[validIndex].IsPreviousButton)) { if (pageIndex == 1) diff --git a/src/App.config b/src/App.config new file mode 100644 index 0000000..9816074 --- /dev/null +++ b/src/App.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Globals.cs b/src/Globals.cs index 7bad17d..62fa23c 100644 --- a/src/Globals.cs +++ b/src/Globals.cs @@ -36,6 +36,6 @@ namespace amecs return true; } - public static readonly int WinVer = Int32.Parse(Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuildNumber").ToString()); + public static readonly int WinVer = int.Parse(Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuildNumber").ToString()); } } \ No newline at end of file diff --git a/src/Misc.FolderPicker/FolderPicker.cs b/src/Misc/FolderPicker.cs similarity index 99% rename from src/Misc.FolderPicker/FolderPicker.cs rename to src/Misc/FolderPicker.cs index 12d04e6..c56d598 100644 --- a/src/Misc.FolderPicker/FolderPicker.cs +++ b/src/Misc/FolderPicker.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; -namespace Misc.FolderPicker +namespace amecs.Misc { public class FolderPicker { diff --git a/src/Misc/SelectWindowsImage.cs b/src/Misc/SelectWindowsImage.cs new file mode 100644 index 0000000..a12c339 --- /dev/null +++ b/src/Misc/SelectWindowsImage.cs @@ -0,0 +1,261 @@ +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; + + /// + /// Asks user to select Windows installation media, mounts it if applicable, and checks its version + /// + /// If true when ISO and host versions mismatch, prompts user that things can break if they continue + /// If true and the ISO build can't be retrieved, prompts a user with an error + 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); + } + } +} \ No newline at end of file diff --git a/src/NSudo.cs b/src/NSudo.cs index 1d052de..81456c7 100644 --- a/src/NSudo.cs +++ b/src/NSudo.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; using System.Threading; +using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; namespace amecs @@ -505,8 +506,20 @@ namespace amecs RtlAdjustPrivilege((int)luid, true, true, out throwaway); } - public class Win32 { - + public static void RunAsUser(Action action) + { + var token = NSudo.GetUserToken(); + Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }), + action)).Wait(); + Marshal.FreeHGlobal(token); + } + + private static async Task RunAsUserAsync(Action action) + { + var token = NSudo.GetUserToken(); + await Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }), + action)); + Marshal.FreeHGlobal(token); } } } \ No newline at end of file diff --git a/src/Program.cs b/src/Program.cs index d722486..2bede50 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,19 +1,9 @@ using System; -using System.Diagnostics; -using System.DirectoryServices; using System.DirectoryServices.AccountManagement; -using System.Globalization; using System.Linq; -using System.Management; -using System.Runtime.InteropServices; -using System.Security; using System.Security.Principal; -using System.Threading; -using System.Threading.Tasks; using Ameliorated.ConsoleUtils; using Microsoft.Win32; -using System.Windows.Forms; -using System.Windows.Forms.VisualStyles; using amecs.Actions; using Menu = Ameliorated.ConsoleUtils.Menu; @@ -21,23 +11,6 @@ namespace amecs { internal class Program { - private static void RunAsUser(Action action) - { - var token = NSudo.GetUserToken(); - Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }), - action)).Wait(); - Marshal.FreeHGlobal(token); - } - - private static async Task RunAsUserAsync(Action action) - { - var token = NSudo.GetUserToken(); - await Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }), - action)); - Marshal.FreeHGlobal(token); - } - - private const string Ver = "2.1"; public static ConsoleTUI.Frame Frame; [STAThread] @@ -51,7 +24,7 @@ namespace amecs NSudo.GetSystemPrivilege(); if (!WindowsIdentity.GetCurrent().IsSystem) throw new Exception("Identity did not change."); - RunAsUser(() => + NSudo.RunAsUser(() => { Globals.Username = WindowsIdentity.GetCurrent().Name.Split('\\').Last(); Globals.UserDomain = WindowsIdentity.GetCurrent().Name.Split('\\').FirstOrDefault(); @@ -82,9 +55,8 @@ namespace amecs } Frame = new ConsoleTUI.Frame($"| Central AME Script v{Ver} |", false); - Frame.Open(); - + while (true) { Globals.UserElevated = Globals.User.IsMemberOf(Globals.Administrators); @@ -137,6 +109,7 @@ namespace amecs new Menu.MenuItem("Install .NET 3.5", new Func(_NET.Install)) : new Menu.MenuItem("Install .NET 3.5", new Func(_NET.Install)) {SecondaryText = "[Installed]", SecondaryTextForeground = ConsoleColor.Yellow, PrimaryTextForeground = ConsoleColor.DarkGray}, Menu.MenuItem.Blank, + new Menu.MenuItem("Uninstall AME", new Func(Deameliorate.DeAme)), new Menu.MenuItem("Extra", new Func(Extra.Extra.ShowMenu)), new Menu.MenuItem("Exit", new Func(Globals.Exit)) }, diff --git a/src/amecs.csproj b/src/amecs.csproj index cfac80e..28a4d5f 100644 --- a/src/amecs.csproj +++ b/src/amecs.csproj @@ -46,12 +46,11 @@ packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll - packages\JetBrains.Annotations.2022.3.1\lib\net20\JetBrains.Annotations.dll - False + packages\JetBrains.Annotations.2023.3.0\lib\net20\JetBrains.Annotations.dll - packages\Microsoft.Dism.2.5.2\lib\net40\Microsoft.Dism.dll + packages\Microsoft.Dism.3.1.0\lib\net40\Microsoft.Dism.dll packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll @@ -61,20 +60,22 @@ packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll - - packages\System.CodeDom.7.0.0\lib\net462\System.CodeDom.dll + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.CodeDom.8.0.0\lib\net462\System.CodeDom.dll - - packages\System.Console.4.3.0\lib\net46\System.Console.dll + + packages\System.Console.4.3.1\lib\net46\System.Console.dll - - packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll - False + + packages\System.Diagnostics.DiagnosticSource.8.0.0\lib\net462\System.Diagnostics.DiagnosticSource.dll packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll @@ -115,22 +116,31 @@ packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + - - packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll + + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll - - packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll + + packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll - - packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll + + packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll @@ -144,7 +154,7 @@ False - packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll + packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net463\System.Security.Cryptography.Algorithms.dll packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll @@ -152,12 +162,11 @@ packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + + packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll - - packages\System.Security.Permissions.7.0.0\lib\net462\System.Security.Permissions.dll - False + + packages\System.Security.Permissions.8.0.0\lib\net462\System.Security.Permissions.dll packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll @@ -165,20 +174,21 @@ - packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll + packages\System.Text.RegularExpressions.4.3.1\lib\net463\System.Text.RegularExpressions.dll - packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll + @@ -197,11 +207,12 @@ - + + @@ -210,6 +221,7 @@ + @@ -231,16 +243,18 @@ - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. - + + + + + + + \ No newline at end of file diff --git a/src/packages.config b/src/packages.config index ebeffdd..f74a35b 100644 --- a/src/packages.config +++ b/src/packages.config @@ -1,23 +1,35 @@  - - - - + + + + - + - + + + + + + + + + + + + + + + + + - - - - @@ -29,34 +41,26 @@ - - - + - - + - - - - - \ No newline at end of file