diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c6059df760..c0570eda3a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,13 +20,13 @@ Provide a Copilot generated summary of the changes in this pull request. ## To-Do -- [ ] Update [documentation](https://github.com/BornToBeRoot/NETworkManager/tree/main/docs/Documentation) to reflect this changes -- [ ] Update [changelog](https://github.com/BornToBeRoot/NETworkManager/tree/main/docs/Changelog) to reflect this changes +- [ ] Update [documentation](https://github.com/BornToBeRoot/NETworkManager/tree/main/Website/docs) to reflect this changes +- [ ] Update [changelog](https://github.com/BornToBeRoot/NETworkManager/tree/main/Website/docs/changelog) to reflect this changes ## Contributing **By submitting this pull request, I confirm the following:** - [ ] I have read and understood the [contributing guidelines](https://github.com/BornToBeRoot/NETworkManager/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/BornToBeRoot/NETworkManager/blob/main/CODE_OF_CONDUCT.md). -- [ ] I have have added my name, username or email to the [contributors](https://github.com/BornToBeRoot/NETworkManager/blob/main/Contributors.md) list or don't want to. +- [ ] I have have added my name, username or email to the [contributors](https://github.com/BornToBeRoot/NETworkManager/blob/main/CONTRIBUTORS.md) list or don't want to. - [ ] The code or resource is compatible with the [GNU General Public License v3.0](https://github.com/BornToBeRoot/NETworkManager/blob/main/LICENSE). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 662a5815f8..0d26c081fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ - You found a bug or have a feature request? Feel free to create a [new issue](https://github.com/BornToBeRoot/NETworkManager/issues/new/choose). - General questions can be discussed in the [GitHub discussions](https://github.com/BornToBeRoot/NETworkManager/discussions). -- If you contribute to the code, documentation or translation, you can add your name to the [contributors](https://github.com/BornToBeRoot/NETworkManager/blob/main/Contributors.md) list with a pull request. +- If you contribute to the code, documentation or translation, you can add your name to the [contributors](https://github.com/BornToBeRoot/NETworkManager/blob/main/CONTRIBUTORS.md) list with a pull request. ## Code - If you want to fix a bug or implement a new features, let me know in the issues that you are work on it. diff --git a/Contributors.md b/CONTRIBUTORS.md similarity index 100% rename from Contributors.md rename to CONTRIBUTORS.md diff --git a/README.md b/README.md index 4e0ccebdf4..c3b5e0c03c 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ Want to contribute to NETworkManager? Here are a few information on how to get s - [Improve the documentation](CONTRIBUTING.md#documentation) - [Report a security vulnerability](https://github.com/BornToBeRoot/NETworkManager/blob/main/SECURITY.md) -A list of all contributors can be found [here](https://github.com/BornToBeRoot/NETworkManager/blob/main/Contributors.md). +A list of all contributors can be found [here](https://github.com/BornToBeRoot/NETworkManager/blob/main/CONTRIBUTORS.md). This project has adopted the [code of conduct](https://github.com/BornToBeRoot/NETworkManager/blob/main/CODE_OF_CONDUCT.md) defined by the [Contributor Covenant](https://contributor-covenant.org/). diff --git a/Source/GlobalAssemblyInfo.cs b/Source/GlobalAssemblyInfo.cs index 125413846d..b557cda1cd 100644 --- a/Source/GlobalAssemblyInfo.cs +++ b/Source/GlobalAssemblyInfo.cs @@ -6,5 +6,5 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("2024.11.18.0")] -[assembly: AssemblyFileVersion("2024.11.18.0")] +[assembly: AssemblyVersion("2025.1.18.0")] +[assembly: AssemblyFileVersion("2025.1.18.0")] diff --git a/Source/NETworkManager.Models/ApplicationManager.cs b/Source/NETworkManager.Models/ApplicationManager.cs index 036ba1228e..072dacd875 100644 --- a/Source/NETworkManager.Models/ApplicationManager.cs +++ b/Source/NETworkManager.Models/ApplicationManager.cs @@ -78,7 +78,7 @@ public static Canvas GetIcon(ApplicationName name) canvas.Children.Add(new PackIconFontAwesome { Kind = PackIconFontAwesomeKind.TerminalSolid }); break; case ApplicationName.AWSSessionManager: - canvas.Children.Add(new PackIconMaterial { Kind = PackIconMaterialKind.Aws }); + canvas.Children.Add(new PackIconFontAwesome { Kind = PackIconFontAwesomeKind.AwsBrands }); break; case ApplicationName.TigerVNC: canvas.Children.Add(new PackIconMaterial { Kind = PackIconMaterialKind.EyeOutline }); diff --git a/Source/NETworkManager.Models/PowerShell/PowerShell.cs b/Source/NETworkManager.Models/PowerShell/PowerShell.cs index b93099c8f7..4761621137 100644 --- a/Source/NETworkManager.Models/PowerShell/PowerShell.cs +++ b/Source/NETworkManager.Models/PowerShell/PowerShell.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; +using log4net; using Microsoft.Win32; namespace NETworkManager.Models.PowerShell; @@ -11,44 +11,43 @@ namespace NETworkManager.Models.PowerShell; /// public static class PowerShell { + private static readonly ILog Log = LogManager.GetLogger(typeof(PowerShell)); + /// - /// Default installation paths for PowerShell. + /// Windows PowerShell file name. /// - public static readonly List GetDefaultInstallationPaths = new() - { - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "PowerShell", "7", "pwsh.exe"), - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "PowerShell", "7", - "pwsh.exe"), - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), - @"System32\WindowsPowerShell\v1.0\powershell.exe") - }; - + public const string WindowsPowerShellFileName = "powershell.exe"; + + /// + /// PowerShell Core file name. + /// + public const string PwshFileName = "pwsh.exe"; + /// /// Default SZ registry keys for the global PowerShell profile. /// - private static readonly List> DefaultProfileRegkeysSzBase = new() - { - new Tuple("FaceName", "Consolas") - }; + private static readonly List> DefaultProfileRegkeysSzBase = + [ + new("FaceName", "Consolas") + ]; /// /// Default DWORD registry keys for the global PowerShell profile. /// - private static readonly List> DefaultProfileRegkeysDwordBase = new() - { - new Tuple("CursorType", 1), - new Tuple("FontFamily", 54), // 36 - new Tuple("FontSize", 1179648), // 120000 - new Tuple("FontWeight", 400) // 190 - }; + private static readonly List> DefaultProfileRegkeysDwordBase = + [ + new("CursorType", 1), + new("FontFamily", 54), // 36 + new("FontSize", 1179648), // 120000 + new("FontWeight", 400) // 190 + ]; /// /// Default DWORD registry keys for the global PowerShell profile to delete. /// - private static readonly List DefaultProfileRegkeysDwordDelete = new() - { + private static readonly List DefaultProfileRegkeysDwordDelete = [ "ScreenColors" - }; + ]; /// /// Default DWORD registry keys for the global PowerShell profile with dark theme. @@ -57,12 +56,11 @@ public static class PowerShell private static List> GetProfileRegkeysDwordDark() { return DefaultProfileRegkeysDwordBase.Concat( - new[] - { - new Tuple("DefaultBackground", 2434341), // HEX: 252525 - new Tuple("ColorTable00", 2434341), // HEX: 252525 - new Tuple("ColorTable07", 13421772) // HEX: cccccc - }).ToList(); + [ + new Tuple("DefaultBackground", 2434341), // HEX: 252525 + new Tuple("ColorTable00", 2434341), // HEX: 252525 + new Tuple("ColorTable07", 13421772) // HEX: cccccc + ]).ToList(); } /// @@ -72,12 +70,11 @@ private static List> GetProfileRegkeysDwordDark() private static List> GetProfileRegkeysDwordWhite() { return DefaultProfileRegkeysDwordBase.Concat( - new[] - { - new Tuple("DefaultBackground", 16777215), // HEX: FFFFFF + [ + new Tuple("DefaultBackground", 16777215), // HEX: FFFFFF new Tuple("ColorTable00", 16777215), // HEX: FFFFFF new Tuple("ColorTable07", 2434341) // HEX: 252525 - }).ToList(); + ]).ToList(); } /// @@ -93,12 +90,13 @@ public static void WriteDefaultProfileToRegistry(string theme, string powerShell // Windows PowerShell --> HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe if (powerShellPath.StartsWith(systemRoot)) - registryPath += "%SystemRoot%" + powerShellPath - .Substring(systemRoot.Length, powerShellPath.Length - systemRoot.Length).Replace(@"\", "_"); + registryPath += "%SystemRoot%" + powerShellPath.Substring(systemRoot.Length, powerShellPath.Length - systemRoot.Length).Replace(@"\", "_"); // PWSH --> HKCU:\Console\C:_Program Files_PowerShell_7_pwsh.exe else registryPath += powerShellPath.Replace(@"\", "_"); + Log.Info($"Registry path for PowerShell profile: \"{registryPath}\""); + var registryKey = Registry.CurrentUser.OpenSubKey(registryPath, true); registryKey ??= Registry.CurrentUser.CreateSubKey(registryPath); diff --git a/Source/NETworkManager.Models/PuTTY/PuTTY.cs b/Source/NETworkManager.Models/PuTTY/PuTTY.cs index 2b4fee5ce8..645a5dc2bb 100644 --- a/Source/NETworkManager.Models/PuTTY/PuTTY.cs +++ b/Source/NETworkManager.Models/PuTTY/PuTTY.cs @@ -10,95 +10,79 @@ namespace NETworkManager.Models.PuTTY; /// /// Class control PuTTY. /// -public class PuTTY +public static class PuTTY { /// - /// Default PuTTY installation paths. + /// PuTTY file name. /// - public static readonly List GetDefaultInstallationPaths = new() - { - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), _puttyFolder, _puttyFile), - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), _puttyFolder, _puttyFile) - }; + public const string FileName = "putty.exe"; /// /// Default SZ registry keys for PuTTY profile NETworkManager. /// - private static readonly List> DefaultProfileRegkeysSZBase = new() - { - new Tuple("Colour1", "255,255,255"), - new Tuple("Colour3", "85,85,85"), - new Tuple("Colour4", "0,0,0"), - new Tuple("Colour5", "0,255,0"), - new Tuple("Colour6", "0,0,0"), - new Tuple("Colour7", "85,85,85"), - new Tuple("Colour8", "187,0,0"), - new Tuple("Colour9", "255,85,85"), - new Tuple("Colour10", "0,187,0"), - new Tuple("Colour11", "85,255,85"), - new Tuple("Colour12", "187,187,0"), - new Tuple("Colour13", "255,255,85"), - new Tuple("Colour14", "0,0,187"), - new Tuple("Colour15", "85,85,255"), - new Tuple("Colour16", "187,0,187"), - new Tuple("Colour17", "255,85,255"), - new Tuple("Colour18", "0,187,187"), - new Tuple("Colour19", "85,255,255"), - new Tuple("Colour20", "187,187,187"), - new Tuple("Colour21", "255,255,255"), - new Tuple("LineCodePage", "UTF-8"), - new Tuple("Font", "Consolas") - }; + private static readonly List> DefaultProfileRegkeysSzBase = + [ + new("Colour1", "255,255,255"), + new("Colour3", "85,85,85"), + new("Colour4", "0,0,0"), + new("Colour5", "0,255,0"), + new("Colour6", "0,0,0"), + new("Colour7", "85,85,85"), + new("Colour8", "187,0,0"), + new("Colour9", "255,85,85"), + new("Colour10", "0,187,0"), + new("Colour11", "85,255,85"), + new("Colour12", "187,187,0"), + new("Colour13", "255,255,85"), + new("Colour14", "0,0,187"), + new("Colour15", "85,85,255"), + new("Colour16", "187,0,187"), + new("Colour17", "255,85,255"), + new("Colour18", "0,187,187"), + new("Colour19", "85,255,255"), + new("Colour20", "187,187,187"), + new("Colour21", "255,255,255"), + new("LineCodePage", "UTF-8"), + new("Font", "Consolas") + ]; /// /// Default DWORD registry keys for PuTTY profile NETworkManager. /// - private static readonly List> DefaultProfileRegkeysDwordBase = new() - { - new Tuple("CurType", 2), - new Tuple("FontHeight", 12), - new Tuple("BlinkCur", 1), - new Tuple("ScrollBar", 0) - }; - - /// - /// Name of the PuTTY folder. - /// - private static string _puttyFolder => "PuTTY"; - - /// - /// Name of the PuTTY executable. - /// - private static string _puttyFile => "putty.exe"; + private static readonly List> DefaultProfileRegkeysDwordBase = + [ + new("CurType", 2), + new("FontHeight", 12), + new("BlinkCur", 1), + new("ScrollBar", 0) + ]; /// /// SZ registry keys for PuTTY profile NETworkManager if app theme is dark. /// /// List with SZ registry keys. - private static List> GetProfileRegkeysSZDark() + private static List> GetProfileRegkeysSzDark() { - return DefaultProfileRegkeysSZBase.Concat( - new[] - { - // new Tuple("Colour0", "255,255,255"), + return DefaultProfileRegkeysSzBase.Concat( + [ + // new Tuple("Colour0", "255,255,255"), new Tuple("Colour0", "187,187,187"), // Foreground new Tuple("Colour2", "37,37,37") // Background - }).ToList(); + ]).ToList(); } /// /// SZ registry keys for PuTTY profile NETworkManager if app theme is white. /// /// List with DWORD registry keys. - private static List> GetProfileRegkeysSZWhite() + private static List> GetProfileRegkeysSzWhite() { - return DefaultProfileRegkeysSZBase.Concat( - new[] - { - // new Tuple("Colour0", "68,68,68"), + return DefaultProfileRegkeysSzBase.Concat( + [ + // new Tuple("Colour0", "68,68,68"), new Tuple("Colour0", "0,0,0"), // Foreground new Tuple("Colour2", "255,255,255") // Background - }).ToList(); + ]).ToList(); } /// @@ -116,7 +100,7 @@ public static void WriteDefaultProfileToRegistry(string theme) if (registryKey != null) { - foreach (var item in theme == "Dark" ? GetProfileRegkeysSZDark() : GetProfileRegkeysSZWhite()) + foreach (var item in theme == "Dark" ? GetProfileRegkeysSzDark() : GetProfileRegkeysSzWhite()) registryKey.SetValue(item.Item1, item.Item2); foreach (var item in DefaultProfileRegkeysDwordBase) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index bd77a3b107..83056b5df5 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -173,10 +173,6 @@ public static void Upgrade(Version fromVersion, Version toVersion) { Log.Info($"Start settings upgrade from {fromVersion} to {toVersion}..."); - // 2022.12.20.0 - if (fromVersion < new Version(2022, 12, 20, 0)) - UpgradeTo_2022_12_20_0(); - // 2023.3.7.0 if (fromVersion < new Version(2023, 3, 7, 0)) UpgradeTo_2023_3_7_0(); @@ -193,6 +189,11 @@ public static void Upgrade(Version fromVersion, Version toVersion) if (fromVersion < new Version(2023, 11, 28, 0)) UpgradeTo_2023_11_28_0(); + + // 2024.11.11.0 + if (fromVersion < new Version(2024, 11, 11, 0)) + UpgradeTo_2024_11_11_0(); + // Latest if (fromVersion < toVersion) UpgradeToLatest(toVersion); @@ -204,35 +205,7 @@ public static void Upgrade(Version fromVersion, Version toVersion) Log.Info("Settings upgrade finished!"); } - /// - /// Method to apply changes for version 2022.12.20.0. - /// - private static void UpgradeTo_2022_12_20_0() - { - Log.Info("Apply update to 2022.12.20.0..."); - - // Add AWS Session Manager application - Log.Info("Add new app \"AWSSessionManager\"..."); - Current.General_ApplicationList.Add(ApplicationManager.GetDefaultList() - .First(x => x.Name == ApplicationName.AWSSessionManager)); - - var powerShellPath = ""; - foreach (var file in PowerShell.GetDefaultInstallationPaths.Where(File.Exists)) - { - powerShellPath = file; - break; - } - - Log.Info($"Set \"AWSSessionManager_ApplicationFilePath\" to \"{powerShellPath}\"..."); - Current.AWSSessionManager_ApplicationFilePath = powerShellPath; - - // Add Bit Calculator application - Log.Info("Add new app \"BitCalculator\"..."); - Current.General_ApplicationList.Add(ApplicationManager.GetDefaultList() - .First(x => x.Name == ApplicationName.BitCalculator)); - } - - /// + /// /// Method to apply changes for version 2023.3.7.0. /// private static void UpgradeTo_2023_3_7_0() @@ -326,6 +299,18 @@ private static void UpgradeTo_2023_11_28_0() Current.DNSLookup_DNSServers = new ObservableCollection(DNSServer.GetDefaultList()); } + + /// + /// Method to apply changes for version 2024.11.11.0. + /// + private static void UpgradeTo_2024_11_11_0() + { + Log.Info("Apply upgrade to 2024.11.11.0..."); + + Log.Info("Reset ApplicationList to default..."); + Current.General_ApplicationList = + new ObservableSetCollection(ApplicationManager.GetDefaultList()); + } /// /// Method to apply changes for the latest version. @@ -334,10 +319,6 @@ private static void UpgradeTo_2023_11_28_0() private static void UpgradeToLatest(Version version) { Log.Info($"Apply upgrade to {version}..."); - - Log.Info("Reset ApplicationList to default..."); - Current.General_ApplicationList = - new ObservableSetCollection(ApplicationManager.GetDefaultList()); } #endregion diff --git a/Source/NETworkManager.Utilities/ApplicationHelper.cs b/Source/NETworkManager.Utilities/ApplicationHelper.cs new file mode 100644 index 0000000000..9f2767059f --- /dev/null +++ b/Source/NETworkManager.Utilities/ApplicationHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.Linq; + +namespace NETworkManager.Utilities; + +/// +/// Helper class to interact with the applications on the system. +/// +public static class ApplicationHelper +{ + /// + /// Find an application in the system PATH. + /// This is similar to the `where` command in Windows. + /// + /// The name of the application to find (like `notepad` or `notepad.exe`). + /// The full path to the application if found, otherwise `null`. + public static string Find(string fileName) + { + var path = Environment.GetEnvironmentVariable("PATH"); + + if (path == null) + return null; + + var directories = path.Split(';'); + + if (!fileName.EndsWith(".exe")) + fileName += ".exe"; + + return directories + .Select(dir => Path.Combine(dir, fileName)) + .FirstOrDefault(File.Exists); + } +} \ No newline at end of file diff --git a/Source/NETworkManager.Utilities/ExternalProcessStarter.cs b/Source/NETworkManager.Utilities/ExternalProcessStarter.cs index 8c340bafba..d18a4620c3 100644 --- a/Source/NETworkManager.Utilities/ExternalProcessStarter.cs +++ b/Source/NETworkManager.Utilities/ExternalProcessStarter.cs @@ -10,23 +10,18 @@ public static class ExternalProcessStarter /// Url like: https://github.com/BornToBeRoot public static void OpenUrl(string url) { - // Escape the $ in the command promp + // Escape the $ in the command prompt url = url.Replace("&", "^&"); Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); } - public static void RunProcess(string filename) + public static void RunProcess(string filename, bool asAdmin = false) { - RunProcess(filename, false); + RunProcess(filename, null, asAdmin); } - public static void RunProcess(string filename, bool asAdmin) - { - RunProcess(filename, "", asAdmin); - } - - public static void RunProcess(string filename, string arguments = "", bool asAdmin = false) + public static void RunProcess(string filename, string arguments, bool asAdmin = false) { ProcessStartInfo info = new() { diff --git a/Source/NETworkManager/MainWindow.xaml.cs b/Source/NETworkManager/MainWindow.xaml.cs index d5e596d283..26a318e624 100644 --- a/Source/NETworkManager/MainWindow.xaml.cs +++ b/Source/NETworkManager/MainWindow.xaml.cs @@ -74,19 +74,6 @@ private void SettingsManager_PropertyChanged(object sender, PropertyChangedEvent case nameof(SettingsInfo.Network_CustomDNSServer): ConfigureDNSServer(); - break; - - // Update PowerShell profile if changed in the settings - case nameof(SettingsInfo.Appearance_PowerShellModifyGlobalProfile): - case nameof(SettingsInfo.Appearance_Theme): - case nameof(SettingsInfo.PowerShell_ApplicationFilePath): - case nameof(SettingsInfo.AWSSessionManager_ApplicationFilePath): - // Skip on welcome dialog - if (SettingsManager.Current.WelcomeDialog_Show) - return; - - WriteDefaultPowerShellProfileToRegistry(); - break; } } @@ -505,13 +492,13 @@ await this.ShowMessageAsync(Strings.SettingsHaveBeenReset, if (SettingsManager.Current.WelcomeDialog_Show) { - var x = new WelcomeChildWindow(); + var welcomeChildWindow = new WelcomeChildWindow(); var welcomeViewModel = new WelcomeViewModel(async instance => { IsWelcomeWindowOpen = false; - x.IsOpen = false; + welcomeChildWindow.IsOpen = false; // Set settings based on user choice SettingsManager.Current.Update_CheckForUpdatesAtStartup = instance.CheckForUpdatesAtStartup; @@ -539,22 +526,6 @@ await this.ShowMessageAsync(Strings.SettingsHaveBeenReset, SettingsManager.Current.SNTPLookup_SNTPServers = new ObservableCollection(SNTPServer.GetDefaultList()); - // Check if PowerShell is installed - foreach (var file in PowerShell.GetDefaultInstallationPaths.Where(File.Exists)) - { - SettingsManager.Current.PowerShell_ApplicationFilePath = file; - SettingsManager.Current.AWSSessionManager_ApplicationFilePath = file; - - break; - } - - // Check if PuTTY is installed - foreach (var file in PuTTY.GetDefaultInstallationPaths.Where(File.Exists)) - { - SettingsManager.Current.PuTTY_ApplicationFilePath = file; - break; - } - SettingsManager.Current.WelcomeDialog_Show = false; // Save it to create a settings file @@ -563,11 +534,11 @@ await this.ShowMessageAsync(Strings.SettingsHaveBeenReset, Load(); }); - x.DataContext = welcomeViewModel; + welcomeChildWindow.DataContext = welcomeViewModel; IsWelcomeWindowOpen = true; - await this.ShowChildWindowAsync(x); + await this.ShowChildWindowAsync(welcomeChildWindow); } else { @@ -601,9 +572,6 @@ private void Load() NetworkChange.NetworkAvailabilityChanged += (_, _) => OnNetworkHasChanged(); NetworkChange.NetworkAddressChanged += (_, _) => OnNetworkHasChanged(); - // Set PowerShell global profile - WriteDefaultPowerShellProfileToRegistry(); - // Search for updates... if (SettingsManager.Current.Update_CheckForUpdatesAtStartup) CheckForUpdates(); @@ -1952,28 +1920,7 @@ private void ConfigureDNSServer() DNSClient.GetInstance().Configure(dnsSettings); } - - private void WriteDefaultPowerShellProfileToRegistry() - { - if (!SettingsManager.Current.Appearance_PowerShellModifyGlobalProfile) - return; - - HashSet paths = []; - - // PowerShell - if (!string.IsNullOrEmpty(SettingsManager.Current.PowerShell_ApplicationFilePath) && - File.Exists(SettingsManager.Current.PowerShell_ApplicationFilePath)) - paths.Add(SettingsManager.Current.PowerShell_ApplicationFilePath); - - // AWS Session Manager - if (!string.IsNullOrEmpty(SettingsManager.Current.AWSSessionManager_ApplicationFilePath) && - File.Exists(SettingsManager.Current.AWSSessionManager_ApplicationFilePath)) - paths.Add(SettingsManager.Current.AWSSessionManager_ApplicationFilePath); - - foreach (var path in paths) - PowerShell.WriteDefaultProfileToRegistry(SettingsManager.Current.Appearance_Theme, path); - } - + #endregion #region Status window @@ -2060,4 +2007,4 @@ private async void FocusEmbeddedWindow() } #endregion -} \ No newline at end of file +} diff --git a/Source/NETworkManager/ViewModels/AWSSessionManagerHostViewModel.cs b/Source/NETworkManager/ViewModels/AWSSessionManagerHostViewModel.cs index e8a4bc95b3..7b77c82db8 100644 --- a/Source/NETworkManager/ViewModels/AWSSessionManagerHostViewModel.cs +++ b/Source/NETworkManager/ViewModels/AWSSessionManagerHostViewModel.cs @@ -1,18 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Threading; -using Amazon; +using Amazon; using Amazon.EC2; using Amazon.EC2.Model; using Amazon.Runtime.CredentialManagement; @@ -26,11 +12,26 @@ using NETworkManager.Models; using NETworkManager.Models.AWS; using NETworkManager.Models.EventSystem; +using NETworkManager.Models.PowerShell; using NETworkManager.Profiles; using NETworkManager.Settings; using NETworkManager.Utilities; using NETworkManager.Views; -using AWSSessionManager = NETworkManager.Profiles.Application.AWSSessionManager; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Threading; +using AWSSessionManagerProfile = NETworkManager.Profiles.Application.AWSSessionManager; namespace NETworkManager.ViewModels; @@ -39,6 +40,7 @@ public class AWSSessionManagerHostViewModel : ViewModelBase, IProfileManager #region Variables private static readonly ILog Log = LogManager.GetLogger(typeof(AWSSessionManagerHostViewModel)); + private readonly IDialogCoordinator _dialogCoordinator; private readonly DispatcherTimer _searchDispatcherTimer = new(); @@ -63,7 +65,6 @@ public string InterTabPartition private readonly bool _isLoading; private bool _isViewActive = true; - private bool _disableFocusEmbeddedWindow; private bool _isAWSCLIInstalled; @@ -95,17 +96,17 @@ public bool IsAWSSessionManagerPluginInstalled } } - private bool _isPowerShellConfigured; + private bool _isExecutableConfigured; - public bool IsPowerShellConfigured + public bool IsExecutableConfigured { - get => _isPowerShellConfigured; + get => _isExecutableConfigured; set { - if (value == _isPowerShellConfigured) + if (value == _isExecutableConfigured) return; - _isPowerShellConfigured = value; + _isExecutableConfigured = value; OnPropertyChanged(); } } @@ -155,26 +156,6 @@ public int SelectedTabIndex } } - private DragablzTabItem _selectedTabItem; - - public DragablzTabItem SelectedTabItem - { - get => _selectedTabItem; - set - { - if (value == _selectedTabItem) - return; - - _selectedTabItem = value; - - // Focus embedded window on switching tab - if (!_disableFocusEmbeddedWindow) - FocusEmbeddedWindow(); - - OnPropertyChanged(); - } - } - private bool _headerContextMenuIsOpen; public bool HeaderContextMenuIsOpen @@ -334,8 +315,17 @@ public AWSSessionManagerHostViewModel(IDialogCoordinator instance) _dialogCoordinator = instance; - CheckInstallationStatus(); - CheckSettings(); + // Check if AWS tools are installed + CheckRequirements(); + + // Check if PowerShell executable is configured + CheckExecutable(); + + // Try to find PowerShell executable + if (!IsExecutableConfigured) + TryFindExecutable(); + + WriteDefaultProfileToRegistry(); InterTabClient = new DragablzInterTabClient(ApplicationName.AWSSessionManager); InterTabPartition = ApplicationName.AWSSessionManager.ToString(); @@ -378,11 +368,11 @@ private void LoadSettings() #region ICommand & Actions - public ICommand CheckInstallationStatusCommand => new RelayCommand(_ => CheckInstallationStatusAction()); + public ICommand CheckRequirementsCommand => new RelayCommand(_ => CheckRequirementsAction()); - private void CheckInstallationStatusAction() + private void CheckRequirementsAction() { - CheckInstallationStatus(); + CheckRequirements(); } public ItemActionCallback CloseItemCommand => CloseItemAction; @@ -394,7 +384,7 @@ private void CloseItemAction(ItemActionCallbackArgs args) private bool Connect_CanExecute(object obj) { - return IsPowerShellConfigured; + return IsExecutableConfigured; } public ICommand ConnectCommand => new RelayCommand(_ => ConnectAction(), Connect_CanExecute); @@ -552,7 +542,7 @@ private static void OpenSettingsAction() #region Methods - private void CheckInstallationStatus() + private void CheckRequirements() { using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"); @@ -580,13 +570,41 @@ private void CheckInstallationStatus() } } - private void CheckSettings() + /// + /// Check if the executable is configured and exists. + /// + private void CheckExecutable() { - IsPowerShellConfigured = !string.IsNullOrEmpty(SettingsManager.Current.AWSSessionManager_ApplicationFilePath) && + IsExecutableConfigured = !string.IsNullOrEmpty(SettingsManager.Current.AWSSessionManager_ApplicationFilePath) && File.Exists(SettingsManager.Current.AWSSessionManager_ApplicationFilePath); + + if (IsExecutableConfigured) + Log.Info($"PowerShell executable found: \"{SettingsManager.Current.AWSSessionManager_ApplicationFilePath}\""); + else + Log.Warn("PowerShell executable not found!"); } - private bool IsConfigured => IsAWSCLIInstalled && IsAWSSessionManagerPluginInstalled && IsPowerShellConfigured; + /// + /// Try to find executable. + /// + private void TryFindExecutable() + { + Log.Info("Try to find PowerShell executable..."); + + var applicationFilePath = ApplicationHelper.Find(PowerShell.PwshFileName); + + if (string.IsNullOrEmpty(applicationFilePath)) + applicationFilePath = ApplicationHelper.Find(PowerShell.WindowsPowerShellFileName); + + SettingsManager.Current.AWSSessionManager_ApplicationFilePath = applicationFilePath; + + CheckExecutable(); + + if (!IsExecutableConfigured) + Log.Warn("Install PowerShell or configure the path in the settings."); + } + + private bool IsConfigured => IsAWSCLIInstalled && IsAWSSessionManagerPluginInstalled && IsExecutableConfigured; private async Task SyncAllInstanceIDsFromAWS() { @@ -601,7 +619,7 @@ private async Task SyncAllInstanceIDsFromAWS() if (!IsConfigured) { Log.Warn( - $"Preconditions not met! AWS CLI installed {IsAWSCLIInstalled}. AWS Session Manager plugin installed {IsAWSSessionManagerPluginInstalled}. PowerShell configured {IsPowerShellConfigured}."); + $"Preconditions not met! AWS CLI installed {IsAWSCLIInstalled}. AWS Session Manager plugin installed {IsAWSSessionManagerPluginInstalled}. PowerShell configured {IsExecutableConfigured}."); return; } @@ -706,33 +724,33 @@ private async Task SyncInstanceIDsFromAWS(string profile, string region) }; foreach (var reservation in response.Reservations) - foreach (var instance in reservation.Instances) - { - if (SettingsManager.Current.AWSSessionManager_SyncOnlyRunningInstancesFromAWS && - instance.State.Name.Value != "running") - continue; - - var tagName = instance.Tags.FirstOrDefault(x => x.Key == "Name"); - - var name = tagName == null || tagName.Value == null - ? instance.InstanceId - : $"{tagName.Value} ({instance.InstanceId})"; - - groupInfo.Profiles.Add(new ProfileInfo + foreach (var instance in reservation.Instances) { - Name = name, - Host = instance.InstanceId, - Group = $"~ [{profile}\\{region}]", - IsDynamic = true, - - AWSSessionManager_Enabled = true, - AWSSessionManager_InstanceID = instance.InstanceId, - AWSSessionManager_OverrideProfile = true, - AWSSessionManager_Profile = profile, - AWSSessionManager_OverrideRegion = true, - AWSSessionManager_Region = region - }); - } + if (SettingsManager.Current.AWSSessionManager_SyncOnlyRunningInstancesFromAWS && + instance.State.Name.Value != "running") + continue; + + var tagName = instance.Tags.FirstOrDefault(x => x.Key == "Name"); + + var name = tagName == null || tagName.Value == null + ? instance.InstanceId + : $"{tagName.Value} ({instance.InstanceId})"; + + groupInfo.Profiles.Add(new ProfileInfo + { + Name = name, + Host = instance.InstanceId, + Group = $"~ [{profile}\\{region}]", + IsDynamic = true, + + AWSSessionManager_Enabled = true, + AWSSessionManager_InstanceID = instance.InstanceId, + AWSSessionManager_OverrideProfile = true, + AWSSessionManager_Profile = profile, + AWSSessionManager_OverrideRegion = true, + AWSSessionManager_Region = region + }); + } // Remove, replace or add group var profilesChangedCurrentState = ProfileManager.ProfilesChanged; @@ -828,14 +846,14 @@ private async Task Connect() private void ConnectProfile() { - var sessionInfo = AWSSessionManager.CreateSessionInfo(SelectedProfile); + var sessionInfo = AWSSessionManagerProfile.CreateSessionInfo(SelectedProfile); Connect(sessionInfo, SelectedProfile.Name); } private void ConnectProfileExternal() { - var sessionInfo = AWSSessionManager.CreateSessionInfo(SelectedProfile); + var sessionInfo = AWSSessionManagerProfile.CreateSessionInfo(SelectedProfile); Process.Start(new ProcessStartInfo { @@ -854,9 +872,7 @@ private void Connect(AWSSessionManagerSessionInfo sessionInfo, string header = n new AWSSessionManagerControl(tabId, sessionInfo), tabId)); // Select the added tab - _disableFocusEmbeddedWindow = true; SelectedTabIndex = TabItems.Count - 1; - _disableFocusEmbeddedWindow = false; } // Modify history list @@ -943,7 +959,7 @@ public void FocusEmbeddedWindow() // Focus embedded window in the selected tab (((DragablzTabItem)tabablzControl.SelectedItem)?.View as IEmbeddedWindow)?.FocusEmbeddedWindow(); - + break; } } @@ -1029,6 +1045,21 @@ public void OnProfileManagerDialogClose() ConfigurationManager.OnDialogClose(); } + private void WriteDefaultProfileToRegistry() + { + if (!SettingsManager.Current.Appearance_PowerShellModifyGlobalProfile) + return; + + if (!IsExecutableConfigured) + return; + + Log.Info("Write PowerShell profile to registry..."); + + PowerShell.WriteDefaultProfileToRegistry( + SettingsManager.Current.Appearance_Theme, + SettingsManager.Current.AWSSessionManager_ApplicationFilePath); + } + #endregion #region Event @@ -1038,20 +1069,25 @@ private void SettingsManager_PropertyChanged(object sender, PropertyChangedEvent switch (e.PropertyName) { case nameof(SettingsInfo.AWSSessionManager_EnableSyncInstanceIDsFromAWS): - { - IsSyncEnabled = SettingsManager.Current.AWSSessionManager_EnableSyncInstanceIDsFromAWS; + { + IsSyncEnabled = SettingsManager.Current.AWSSessionManager_EnableSyncInstanceIDsFromAWS; - if (IsSyncEnabled) - SyncAllInstanceIDsFromAWS().ConfigureAwait(false); - else - RemoveDynamicGroups(); - break; - } + if (IsSyncEnabled) + SyncAllInstanceIDsFromAWS().ConfigureAwait(false); + else + RemoveDynamicGroups(); + break; + } case nameof(SettingsInfo.AWSSessionManager_SyncOnlyRunningInstancesFromAWS): SyncAllInstanceIDsFromAWS().ConfigureAwait(false); break; case nameof(SettingsInfo.AWSSessionManager_ApplicationFilePath): - CheckSettings(); + CheckExecutable(); + WriteDefaultProfileToRegistry(); + break; + case nameof(SettingsInfo.Appearance_PowerShellModifyGlobalProfile): + case nameof(SettingsInfo.Appearance_Theme): + WriteDefaultProfileToRegistry(); break; } } @@ -1088,4 +1124,4 @@ private void SearchDispatcherTimer_Tick(object sender, EventArgs e) } #endregion -} \ No newline at end of file +} diff --git a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs index d0147e2bde..f88a0a0b56 100644 --- a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs +++ b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs @@ -11,6 +11,7 @@ using System.Windows.Input; using System.Windows.Threading; using Dragablz; +using log4net; using MahApps.Metro.Controls.Dialogs; using NETworkManager.Controls; using NETworkManager.Localization.Resources; @@ -21,14 +22,15 @@ using NETworkManager.Settings; using NETworkManager.Utilities; using NETworkManager.Views; -using PowerShell = NETworkManager.Profiles.Application.PowerShell; +using PowerShellProfile = NETworkManager.Profiles.Application.PowerShell; namespace NETworkManager.ViewModels; public class PowerShellHostViewModel : ViewModelBase, IProfileManager { #region Variables - + private static readonly ILog Log = LogManager.GetLogger(typeof(PowerShellHostViewModel)); + private readonly IDialogCoordinator _dialogCoordinator; private readonly DispatcherTimer _searchDispatcherTimer = new(); @@ -53,19 +55,18 @@ public string InterTabPartition private readonly bool _isLoading; private bool _isViewActive = true; - private bool _disableFocusEmbeddedWindow; - private bool _isConfigured; + private bool _isExecutableConfigured; - public bool IsConfigured + public bool IsExecutableConfigured { - get => _isConfigured; + get => _isExecutableConfigured; set { - if (value == _isConfigured) + if (value == _isExecutableConfigured) return; - _isConfigured = value; + _isExecutableConfigured = value; OnPropertyChanged(); } } @@ -85,28 +86,6 @@ public int SelectedTabIndex } } - /* - private DragablzTabItem _selectedTabItem; - - public DragablzTabItem SelectedTabItem - { - get => _selectedTabItem; - set - { - if (value == _selectedTabItem) - return; - - _selectedTabItem = value; - - // Focus embedded window on switching tab - if (!_disableFocusEmbeddedWindow) - FocusEmbeddedWindow(); - - OnPropertyChanged(); - } - } - */ - private bool _headerContextMenuIsOpen; public bool HeaderContextMenuIsOpen @@ -266,7 +245,14 @@ public PowerShellHostViewModel(IDialogCoordinator instance) _dialogCoordinator = instance; - CheckSettings(); + // Check if PowerShell executable is configured + CheckExecutable(); + + // Try to find PowerShell executable + if(!IsExecutableConfigured) + TryFindExecutable(); + + WriteDefaultProfileToRegistry(); InterTabClient = new DragablzInterTabClient(ApplicationName.PowerShell); InterTabPartition = ApplicationName.PowerShell.ToString(); @@ -312,7 +298,7 @@ private void CloseItemAction(ItemActionCallbackArgs args) private bool Connect_CanExecute(object obj) { - return IsConfigured; + return IsExecutableConfigured; } public ICommand ConnectCommand => new RelayCommand(_ => ConnectAction(), Connect_CanExecute); @@ -441,10 +427,38 @@ private static void OpenSettingsAction() #region Methods - private void CheckSettings() + /// + /// Check if the executable is configured and exists. + /// + private void CheckExecutable() + { + IsExecutableConfigured = !string.IsNullOrEmpty(SettingsManager.Current.PowerShell_ApplicationFilePath) && + File.Exists(SettingsManager.Current.PowerShell_ApplicationFilePath); + + if(IsExecutableConfigured) + Log.Info($"PowerShell executable found: \"{SettingsManager.Current.PowerShell_ApplicationFilePath}\""); + else + Log.Warn("PowerShell executable not found!"); + } + + /// + /// Try to find executable. + /// + private void TryFindExecutable() { - IsConfigured = !string.IsNullOrEmpty(SettingsManager.Current.PowerShell_ApplicationFilePath) && - File.Exists(SettingsManager.Current.PowerShell_ApplicationFilePath); + Log.Info("Try to find PowerShell executable..."); + + var applicationFilePath = ApplicationHelper.Find(PowerShell.PwshFileName); + + if(string.IsNullOrEmpty(applicationFilePath)) + applicationFilePath = ApplicationHelper.Find(PowerShell.WindowsPowerShellFileName); + + SettingsManager.Current.PowerShell_ApplicationFilePath = applicationFilePath; + + CheckExecutable(); + + if(!IsExecutableConfigured) + Log.Warn("Install PowerShell or configure the path in the settings."); } private async Task Connect(string host = null) @@ -493,19 +507,19 @@ private async Task Connect(string host = null) private void ConnectProfile() { - Connect(PowerShell.CreateSessionInfo(SelectedProfile), + Connect(PowerShellProfile.CreateSessionInfo(SelectedProfile), SelectedProfile.Name); } private void ConnectProfileExternal() { var sessionInfo = - PowerShell.CreateSessionInfo(SelectedProfile); + PowerShellProfile.CreateSessionInfo(SelectedProfile); Process.Start(new ProcessStartInfo { FileName = SettingsManager.Current.PowerShell_ApplicationFilePath, - Arguments = Models.PowerShell.PowerShell.BuildCommandLine(sessionInfo) + Arguments = PowerShell.BuildCommandLine(sessionInfo) }); } @@ -520,9 +534,7 @@ private void Connect(PowerShellSessionInfo sessionInfo, string header = null) new PowerShellControl(tabId, sessionInfo), tabId)); // Select the added tab - _disableFocusEmbeddedWindow = true; SelectedTabIndex = TabItems.Count - 1; - _disableFocusEmbeddedWindow = false; } public void AddTab(string host) @@ -671,6 +683,21 @@ public void OnProfileManagerDialogClose() { ConfigurationManager.OnDialogClose(); } + + private void WriteDefaultProfileToRegistry() + { + if (!SettingsManager.Current.Appearance_PowerShellModifyGlobalProfile) + return; + + if(!IsExecutableConfigured) + return; + + Log.Info("Write PowerShell profile to registry..."); + + PowerShell.WriteDefaultProfileToRegistry( + SettingsManager.Current.Appearance_Theme, + SettingsManager.Current.AWSSessionManager_ApplicationFilePath); + } #endregion @@ -692,8 +719,17 @@ private void SearchDispatcherTimer_Tick(object sender, EventArgs e) private void SettingsManager_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(SettingsInfo.PowerShell_ApplicationFilePath)) - CheckSettings(); + switch (e.PropertyName) + { + case nameof(SettingsInfo.PowerShell_ApplicationFilePath): + CheckExecutable(); + WriteDefaultProfileToRegistry(); + break; + case nameof(SettingsInfo.Appearance_PowerShellModifyGlobalProfile): + case nameof(SettingsInfo.Appearance_Theme): + WriteDefaultProfileToRegistry(); + break; + } } #endregion diff --git a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs index 29b92c1bf8..c40c225d7a 100644 --- a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs +++ b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs @@ -1,4 +1,16 @@ -using System; +using Dragablz; +using log4net; +using MahApps.Metro.Controls.Dialogs; +using NETworkManager.Controls; +using NETworkManager.Localization.Resources; +using NETworkManager.Models; +using NETworkManager.Models.EventSystem; +using NETworkManager.Models.PuTTY; +using NETworkManager.Profiles; +using NETworkManager.Settings; +using NETworkManager.Utilities; +using NETworkManager.Views; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; @@ -10,24 +22,14 @@ using System.Windows.Data; using System.Windows.Input; using System.Windows.Threading; -using Dragablz; -using MahApps.Metro.Controls.Dialogs; -using NETworkManager.Controls; -using NETworkManager.Localization.Resources; -using NETworkManager.Models; -using NETworkManager.Models.EventSystem; -using NETworkManager.Models.PuTTY; -using NETworkManager.Profiles; -using NETworkManager.Settings; -using NETworkManager.Utilities; -using NETworkManager.Views; -using PuTTY = NETworkManager.Settings.Application.PuTTY; +using PuTTYProfile = NETworkManager.Settings.Application.PuTTY; namespace NETworkManager.ViewModels; public class PuTTYHostViewModel : ViewModelBase, IProfileManager { #region Variables + private static readonly ILog Log = LogManager.GetLogger(typeof(PuTTYHostViewModel)); private readonly IDialogCoordinator _dialogCoordinator; private readonly DispatcherTimer _searchDispatcherTimer = new(); @@ -53,19 +55,18 @@ public string InterTabPartition private readonly bool _isLoading; private bool _isViewActive = true; - private bool _disableFocusEmbeddedWindow; - private bool _isConfigured; + private bool _isExecutableConfigured; - public bool IsConfigured + public bool IsExecutableConfigured { - get => _isConfigured; + get => _isExecutableConfigured; set { - if (value == _isConfigured) + if (value == _isExecutableConfigured) return; - _isConfigured = value; + _isExecutableConfigured = value; OnPropertyChanged(); } } @@ -85,26 +86,6 @@ public int SelectedTabIndex } } - private DragablzTabItem _selectedTabItem; - - public DragablzTabItem SelectedTabItem - { - get => _selectedTabItem; - set - { - if (value == _selectedTabItem) - return; - - _selectedTabItem = value; - - // Focus embedded window on switching tab - if (!_disableFocusEmbeddedWindow) - FocusEmbeddedWindow(); - - OnPropertyChanged(); - } - } - private bool _headerContextMenuIsOpen; public bool HeaderContextMenuIsOpen @@ -264,7 +245,14 @@ public PuTTYHostViewModel(IDialogCoordinator instance) _dialogCoordinator = instance; - CheckSettings(); + // Check if PuTTY executable is configured + CheckExecutable(); + + // Try to find PuTTY executable + if (!IsExecutableConfigured) + TryFindExecutable(); + + WriteDefaultProfileToRegistry(); InterTabClient = new DragablzInterTabClient(ApplicationName.PuTTY); InterTabPartition = ApplicationName.PuTTY.ToString(); @@ -310,7 +298,7 @@ private void CloseItemAction(ItemActionCallbackArgs args) private bool Connect_CanExecute(object obj) { - return IsConfigured; + return IsExecutableConfigured; } public ICommand ConnectCommand => new RelayCommand(_ => ConnectAction(), Connect_CanExecute); @@ -445,14 +433,33 @@ private static void OpenSettingsAction() #endregion #region Methods - - private void CheckSettings() + /// + /// Check if executable is configured and exists. + /// + private void CheckExecutable() { - IsConfigured = !string.IsNullOrEmpty(SettingsManager.Current.PuTTY_ApplicationFilePath) && + IsExecutableConfigured = !string.IsNullOrEmpty(SettingsManager.Current.PuTTY_ApplicationFilePath) && File.Exists(SettingsManager.Current.PuTTY_ApplicationFilePath); - // Create default PuTTY profile for NETworkManager - WriteDefaultProfileToRegistry(); + if (IsExecutableConfigured) + Log.Info($"PuTTY executable configured: \"{SettingsManager.Current.PuTTY_ApplicationFilePath}\""); + else + Log.Warn("PuTTY executable not found!"); + } + + /// + /// Try to find executable. + /// + private void TryFindExecutable() + { + Log.Info("Try to find PuTTY executable..."); + + SettingsManager.Current.PuTTY_ApplicationFilePath = ApplicationHelper.Find(Models.PuTTY.PuTTY.FileName); + + CheckExecutable(); + + if (!IsExecutableConfigured) + Log.Warn("Install PuTTY or configure the path in the settings."); } private async Task Connect(string host = null) @@ -481,7 +488,7 @@ private async Task Connect(string host = null) EnableLog = SettingsManager.Current.PuTTY_EnableSessionLog, LogMode = SettingsManager.Current.PuTTY_LogMode, LogFileName = SettingsManager.Current.PuTTY_LogFileName, - LogPath = PuTTY.LogPath, + LogPath = PuTTYProfile.LogPath, AdditionalCommandLine = instance.AdditionalCommandLine }; @@ -520,7 +527,7 @@ private void ConnectProfile() private void ConnectProfileExternal() { // Create log path - DirectoryHelper.CreateWithEnvironmentVariables(PuTTY.LogPath); + DirectoryHelper.CreateWithEnvironmentVariables(PuTTYProfile.LogPath); var sessionInfo = NETworkManager.Profiles.Application.PuTTY.CreateSessionInfo(SelectedProfile); @@ -544,9 +551,7 @@ private void Connect(PuTTYSessionInfo sessionInfo, string header = null) tabId)); // Select the added tab - _disableFocusEmbeddedWindow = true; SelectedTabIndex = TabItems.Count - 1; - _disableFocusEmbeddedWindow = false; } public void AddTab(string host) @@ -678,7 +683,7 @@ public void FocusEmbeddedWindow() // Focus embedded window in the selected tab (((DragablzTabItem)tabablzControl.SelectedItem)?.View as IEmbeddedWindow)?.FocusEmbeddedWindow(); - + break; } } @@ -758,8 +763,12 @@ public void OnProfileManagerDialogClose() private void WriteDefaultProfileToRegistry() { - if (IsConfigured) - Models.PuTTY.PuTTY.WriteDefaultProfileToRegistry(SettingsManager.Current.Appearance_Theme); + if (!IsExecutableConfigured) + return; + + Log.Info("Write PuTTY profile to registry..."); + + Models.PuTTY.PuTTY.WriteDefaultProfileToRegistry(SettingsManager.Current.Appearance_Theme); } #endregion @@ -768,12 +777,15 @@ private void WriteDefaultProfileToRegistry() private void SettingsManager_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(SettingsInfo.PuTTY_ApplicationFilePath)) - CheckSettings(); - - // Update PuTTY profile "NETworkManager" if application theme has changed - if (e.PropertyName == nameof(SettingsInfo.Appearance_Theme)) - WriteDefaultProfileToRegistry(); + switch (e.PropertyName) + { + case nameof(SettingsInfo.PuTTY_ApplicationFilePath): + CheckExecutable(); + break; + case nameof(SettingsInfo.Appearance_Theme): + WriteDefaultProfileToRegistry(); + break; + } } private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e) diff --git a/Source/NETworkManager/Views/AWSSessionManagerHostView.xaml b/Source/NETworkManager/Views/AWSSessionManagerHostView.xaml index 40f9b19ada..2e4127dab1 100644 --- a/Source/NETworkManager/Views/AWSSessionManagerHostView.xaml +++ b/Source/NETworkManager/Views/AWSSessionManagerHostView.xaml @@ -41,7 +41,7 @@ - + @@ -794,7 +794,7 @@ - + @@ -849,7 +849,7 @@ -