diff --git a/src/gsudo.Wrappers/gsudoModule.psm1 b/src/gsudo.Wrappers/gsudoModule.psm1 index e12a79e..6ec205c 100644 --- a/src/gsudo.Wrappers/gsudoModule.psm1 +++ b/src/gsudo.Wrappers/gsudoModule.psm1 @@ -134,7 +134,7 @@ if ($gsudoAutoComplete) { '--integrity' = $integrityOptions; '-i' = $integrityOptions; 'cache' = @('on', 'off', 'help'); - 'config' = @('CacheMode', 'CacheDuration', 'LogLevel', 'NewWindow.Force', 'NewWindow.CloseBehaviour', 'Prompt', 'PipedPrompt', 'ForceAttachedConsole', 'ForcePipedConsole', 'ForceVTConsole', 'CopyEnvironmentVariables', 'CopyNetworkShares', 'PowerShellLoadProfile', 'SecurityEnforceUacIsolation', 'ExceptionList'); + 'config' = @('CacheMode', 'CacheDuration', 'LogLevel', 'NewWindow.Force', 'NewWindow.CloseBehaviour', 'Prompt', 'PipedPrompt', 'PathPrecedence', 'ForceAttachedConsole', 'ForcePipedConsole', 'ForceVTConsole', 'CopyEnvironmentVariables', 'CopyNetworkShares', 'PowerShellLoadProfile', 'SecurityEnforceUacIsolation', 'ExceptionList'); 'cachemode' = @('Auto', 'Disabled', 'Explicit', '--reset'); 'loglevel' = @('All', 'Debug', 'Info', 'Warning', 'Error', 'None', '--reset'); 'NewWindow.CloseBehaviour' = @('KeepShellOpen', 'PressKeyToClose', 'OsDefault', '--reset'); diff --git a/src/gsudo/AppSettings/PathPrecedenceSetting.cs b/src/gsudo/AppSettings/PathPrecedenceSetting.cs new file mode 100644 index 0000000..d17b4f5 --- /dev/null +++ b/src/gsudo/AppSettings/PathPrecedenceSetting.cs @@ -0,0 +1,55 @@ +using gsudo.Helpers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace gsudo.AppSettings +{ + /// + /// Reorders the PATH environment variable to prioritize gsudo's path. + /// Saving the boolean value to the registry is anecdotical, the real change is done in the environment variable. + /// + internal class PathPrecedenceSetting : RegistrySetting + { + public PathPrecedenceSetting(): + base("PathPrecedence", false, bool.Parse, RegistrySettingScope.GlobalOnly) + { + + } + + public override void Save(string newValue, bool global) + { + bool bNewValue = bool.Parse(newValue); + var ourPath = Path.GetDirectoryName(ProcessFactory.FindExecutableInPath("gsudo.exe")) // shim + ?? Path.GetDirectoryName(ProcessHelper.GetOwnExeName()); + + var system32Path = Environment.GetFolderPath(Environment.SpecialFolder.System); + + var allPaths = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine).Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + // I could also do .Distinct(StringComparer.OrdinalIgnoreCase); + // ...and it works well on local, but may be out of our responsibility to fix that. + + IEnumerable newPath; + + if (bNewValue) + newPath = new[] { ourPath }.Concat(allPaths.Where(p => !p.Equals(ourPath, StringComparison.OrdinalIgnoreCase))); + else + newPath = allPaths.Where(p => !p.Equals(ourPath, StringComparison.OrdinalIgnoreCase)).Concat(new[] { ourPath }); + + var finalStringPath = string.Join(";", newPath); + + Logger.Instance.Log($"Updating PATH environment variable to: {finalStringPath}", LogLevel.Debug); + + Environment.SetEnvironmentVariable("Path", finalStringPath, EnvironmentVariableTarget.Machine); + base.Save(newValue, global); + + if (bNewValue) + Logger.Instance.Log($"\"{ourPath}\" path is now prioritized in the PATH environment variable.", LogLevel.Info); + else + Logger.Instance.Log($"\"{system32Path}\" path is now prioritized in the PATH environment variable.", LogLevel.Info); + + Logger.Instance.Log("Please restart all your consoles to ensure the change makes effect.", LogLevel.Warning); + } + } +} diff --git a/src/gsudo/AppSettings/Settings.cs b/src/gsudo/AppSettings/Settings.cs index 0c622af..b4f66c9 100644 --- a/src/gsudo/AppSettings/Settings.cs +++ b/src/gsudo/AppSettings/Settings.cs @@ -98,6 +98,8 @@ namespace gsudo deserializer: ExtensionMethods.ParseEnum, scope: RegistrySettingScope.Any); + public static RegistrySetting PathOverrideSetting = new PathPrecedenceSetting(); + public static IDictionary AllKeys => new Dictionary(StringComparer.OrdinalIgnoreCase) .Add( @@ -120,7 +122,8 @@ namespace gsudo PowerShellLoadProfile, SecurityEnforceUacIsolation, - ExceptionList + ExceptionList, + PathOverrideSetting ); internal static TimeSpan TimeSpanParseWithInfinite(string value)