-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Make sure that SettingFile arg is parsed before we load the settings #7449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
dbd1878
10943a5
3391e14
1e673d3
5979c49
4086976
7d04ee2
e708a43
05eed04
1e9d32d
2226218
b2d36a8
96e0b52
5c48dbc
777f5eb
e9fd826
4f1f4f0
8ca2220
ed941fa
371ed6f
92a8b9b
b8dcdfe
6799d24
d2a33ca
00c2a10
108ae7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -200,6 +200,7 @@ internal CommandLineParameterParser(PSHostUserInterface hostUI, string bannerTex | |
| _helpText = helpText; | ||
| } | ||
|
|
||
| #region Internal properties | ||
| internal bool AbortStartup | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
| { | ||
| get | ||
|
|
@@ -392,6 +393,218 @@ internal string WorkingDirectory | |
| { | ||
| get { return _workingDirectory; } | ||
| } | ||
| #endregion Internal properties | ||
|
|
||
| #region static methods | ||
| /// <summary> | ||
| /// Processes the -SettingFile Argument. | ||
| /// </summary> | ||
| /// <param name="args"> | ||
| /// The command line parameters to be processed. | ||
| /// </param> | ||
| /// <param name="argIndex"> | ||
| /// The index in args to the argument following '-SettingFile'. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The parameter name is generic but comment says that it is used only for '-SettingFile' - should the parameter name reflects the fact? |
||
| /// </param> | ||
| /// <param name="parser"> | ||
| /// Used to allow the helper to write errors to the console. If not supplied, no errors will be written. | ||
| /// </param> | ||
| /// <returns> | ||
| /// Returns true if the argument was parsed successfully and false if not. | ||
| /// </returns> | ||
| private static bool ParseSettingFileHelper(string[] args, int argIndex, CommandLineParameterParser parser) | ||
| { | ||
| if (argIndex >= args.Length) | ||
| { | ||
| if (parser != null) | ||
| { | ||
| parser.WriteCommandLineError( | ||
| CommandLineParameterParserStrings.MissingSettingsFileArgument); | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| string configFile = null; | ||
| try | ||
| { | ||
| configFile = NormalizeFilePath(args[argIndex]); | ||
| } | ||
| catch (Exception ex) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we could remove the |
||
| { | ||
| if (parser != null) | ||
| { | ||
| string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[argIndex], ex.Message); | ||
| parser.WriteCommandLineError(error); | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| if (!System.IO.File.Exists(configFile)) | ||
| { | ||
| if (parser != null) | ||
| { | ||
| string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.SettingsFileNotExists, configFile); | ||
| parser.WriteCommandLineError(error); | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| PowerShellConfig.Instance.SetSystemConfigFilePath(configFile); | ||
| return true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Processes the command line parameters to ConsoleHost which must be parsed before the Host is created. | ||
| /// Success to indicate that the program should continue running. | ||
| /// </summary> | ||
| /// <param name="args"> | ||
| /// The command line parameters to be processed. | ||
| /// </param> | ||
| internal static void EarlyParse(string[] args) | ||
| { | ||
| Dbg.Assert(!_dirtyEarlyParse, "This instance has already been used. Create a new instance."); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assert message is misleading. The method can only be called once since _dirtyEarlyParse is a static field.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed, I verified this can be run multiple times |
||
|
|
||
| // indicates that we've called this method on this instance, and that when it's done, the state variables | ||
| // will reflect the parse. | ||
| _dirtyEarlyParse = true; | ||
|
|
||
| EarlyParseHelper(args); | ||
| } | ||
|
|
||
| private static string GetConfigurationNameFromGroupPolicy() | ||
| { | ||
| // Current user policy takes precedence. | ||
| var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig); | ||
| if (consoleSessionSetting != null) | ||
| { | ||
| if (consoleSessionSetting.EnableConsoleSessionConfiguration == true) | ||
| { | ||
| if (!string.IsNullOrEmpty(consoleSessionSetting.ConsoleSessionConfigurationName)) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could combine three |
||
| { | ||
| return consoleSessionSetting.ConsoleSessionConfigurationName; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return string.Empty; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Processes the command line parameters to ConsoleHost which must be parsed before the Host is created. | ||
| /// Success to indicate that the program should continue running. | ||
| /// </summary> | ||
| /// <param name="args"> | ||
| /// The command line parameters to be processed. | ||
| /// </param> | ||
| private static void EarlyParseHelper(string[] args) | ||
| { | ||
| Dbg.Assert(args != null, "Argument 'args' to ParseHelper should never be null"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Back this up with a check in release mode. At a minimum, silently ignore and return.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved |
||
| bool noexitSeen = false; | ||
| for (int i = 0; i < args.Length; ++i) | ||
| { | ||
| var switchKeyResults = GetSwitchKey(args, ref i, null, ref noexitSeen); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not clear that we get from the method. I'd replace (string switchKey, bool shouldBreak) = GetSwitchKey(args, ref i, null, ref noexitSeen); Named argument for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved |
||
| if (switchKeyResults.ShouldBreak) | ||
| { | ||
| break; | ||
| } | ||
|
|
||
| string switchKey = switchKeyResults.SwitchKey; | ||
|
|
||
| if (MatchSwitch(switchKey, "settingsfile", "settings")) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Named arguments will be good for constants. Below I see some such patterns.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved |
||
| { | ||
| // parse setting file arg and don't write error as there is no host yet. | ||
| if (!ParseSettingFileHelper(args, ++i, null)) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
| { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the word in a switch from the current argument or parses a file. | ||
| /// For example -foo, /foo, or --foo would return 'foo'. | ||
| /// </summary> | ||
| /// <param name="args"> | ||
| /// The command line parameters to be processed. | ||
| /// </param> | ||
| /// <param name="argIndex"> | ||
| /// The index in args to the argument to process. | ||
| /// </param> | ||
| /// <param name="parser"> | ||
| /// Used to allow the helper to write errors to the console. If not supplied, Files will not be parsed. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment about writing errors doesn't appear to apply.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated comment (I have not pushed at this point.) |
||
| /// </param> | ||
| /// <param name="noexitSeen"> | ||
| /// Used during parsing files. | ||
| /// </param> | ||
| /// <returns> | ||
| /// Returns a Tuple: | ||
| /// The first value is a String called SwitchKey with the word in a switch from the current argument or null. | ||
| /// The second value is a bool called ShouldBreak, indicating if the parsing look should break. | ||
| /// </returns> | ||
| private static (string SwitchKey, bool ShouldBreak) GetSwitchKey(string[] args, ref int argIndex, CommandLineParameterParser parser, ref bool noexitSeen) | ||
| { | ||
| string switchKey = args[argIndex].Trim().ToLowerInvariant(); | ||
| if (string.IsNullOrEmpty(switchKey)) | ||
| { | ||
| return (SwitchKey: null, ShouldBreak: false); | ||
| } | ||
|
|
||
| if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/') | ||
| { | ||
| // then its a file | ||
| if (parser != null) | ||
| { | ||
| --argIndex; | ||
| parser.ParseFile(args, ref argIndex, noexitSeen); | ||
| } | ||
|
|
||
| return (SwitchKey: null, ShouldBreak: true); | ||
| } | ||
|
|
||
| // chop off the first character so that we're agnostic wrt specifying / or - | ||
| // in front of the switch name. | ||
| switchKey = switchKey.Substring(1); | ||
|
|
||
| // chop off the second dash so we're agnostic wrt specifying - or -- | ||
| if (!string.IsNullOrEmpty(switchKey) && SpecialCharacters.IsDash(switchKey[0])) | ||
| { | ||
| switchKey = switchKey.Substring(1); | ||
| } | ||
|
|
||
| return (SwitchKey: switchKey, ShouldBreak: false); | ||
| } | ||
|
|
||
| private static string NormalizeFilePath(string path) | ||
| { | ||
| // Normalize slashes | ||
| path = path.Replace(StringLiterals.AlternatePathSeparator, | ||
| StringLiterals.DefaultPathSeparator); | ||
|
|
||
| return Path.GetFullPath(path); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method is used once and then we call File.Exist() where Path.GetFullPath() is called again.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. existing code, please file an issue, the method was just changed from an instance to static
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done #7469. |
||
| } | ||
|
|
||
| private static bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch) | ||
| { | ||
| Dbg.Assert(switchKey != null, "need a value"); | ||
| Dbg.Assert(!String.IsNullOrEmpty(match), "need a value"); | ||
| Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace"); | ||
| Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace"); | ||
| Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match"); | ||
|
|
||
| if (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0) | ||
| { | ||
| if (switchKey.Length >= smallestUnambiguousMatch.Length) | ||
| { | ||
| return true; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could exclude if-s and use single
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, I don't follow what you are saying. Well, looking at the code, I made a guess.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant |
||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| private void ShowHelp() | ||
| { | ||
|
|
@@ -463,57 +676,20 @@ internal void Parse(string[] args) | |
| } | ||
| } | ||
|
|
||
| private static string GetConfigurationNameFromGroupPolicy() | ||
| { | ||
| // Current user policy takes precedence. | ||
| var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig); | ||
| if (consoleSessionSetting != null) | ||
| { | ||
| if (consoleSessionSetting.EnableConsoleSessionConfiguration == true) | ||
| { | ||
| if (!string.IsNullOrEmpty(consoleSessionSetting.ConsoleSessionConfigurationName)) | ||
| { | ||
| return consoleSessionSetting.ConsoleSessionConfigurationName; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return string.Empty; | ||
| } | ||
|
|
||
| private void ParseHelper(string[] args) | ||
| { | ||
| Dbg.Assert(args != null, "Argument 'args' to ParseHelper should never be null"); | ||
| bool noexitSeen = false; | ||
|
|
||
| for (int i = 0; i < args.Length; ++i) | ||
| { | ||
| // Invariant culture used because command-line parameters are not localized. | ||
|
|
||
| string switchKey = args[i].Trim().ToLowerInvariant(); | ||
| if (String.IsNullOrEmpty(switchKey)) | ||
| var switchKeyResults = GetSwitchKey(args, ref i, this, ref noexitSeen); | ||
| if (switchKeyResults.ShouldBreak) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure tuple field names are case sensitive.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
| { | ||
| continue; | ||
| } | ||
|
|
||
| if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/') | ||
| { | ||
| // then its a file | ||
|
|
||
| --i; | ||
| ParseFile(args, ref i, noexitSeen); | ||
| break; | ||
| } | ||
|
|
||
| // chop off the first character so that we're agnostic wrt specifying / or - | ||
| // in front of the switch name. | ||
| switchKey = switchKey.Substring(1); | ||
|
|
||
| // chop off the second dash so we're agnostic wrt specifying - or -- | ||
| if (!String.IsNullOrEmpty(switchKey) && SpecialCharacters.IsDash(switchKey[0])) | ||
| { | ||
| switchKey = switchKey.Substring(1); | ||
| } | ||
| string switchKey = switchKeyResults.SwitchKey; | ||
|
|
||
| // If version is in the commandline, don't continue to look at any other parameters | ||
| if (MatchSwitch(switchKey, "version", "v")) | ||
|
|
@@ -711,34 +887,13 @@ private void ParseHelper(string[] args) | |
| } | ||
| } | ||
|
|
||
| else if (MatchSwitch(switchKey, "settingsfile", "settings") ) | ||
| else if (MatchSwitch(switchKey, "settingsfile", "settings")) | ||
| { | ||
| ++i; | ||
| if (i >= args.Length) | ||
| // Parse setting file arg and write error | ||
| if (!ParseSettingFileHelper(args, ++i, this)) | ||
| { | ||
| WriteCommandLineError( | ||
| CommandLineParameterParserStrings.MissingSettingsFileArgument); | ||
| break; | ||
| } | ||
| string configFile = null; | ||
| try | ||
| { | ||
| configFile = NormalizeFilePath(args[i]); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[i], ex.Message); | ||
| WriteCommandLineError(error); | ||
| break; | ||
| } | ||
|
|
||
| if (!System.IO.File.Exists(configFile)) | ||
| { | ||
| string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.SettingsFileNotExists, configFile); | ||
| WriteCommandLineError(error); | ||
| break; | ||
| } | ||
| PowerShellConfig.Instance.SetSystemConfigFilePath(configFile); | ||
| } | ||
| #if STAMODE | ||
| // explicit setting of the ApartmentState Not supported on NanoServer | ||
|
|
@@ -818,25 +973,6 @@ private void WriteCommandLineError(string msg, bool showHelp = false, bool showB | |
| _exitCode = ConsoleHost.ExitCodeBadCommandLineParameter; | ||
| } | ||
|
|
||
| private bool MatchSwitch(string switchKey, string match, string smallestUnambiguousMatch) | ||
| { | ||
| Dbg.Assert(switchKey != null, "need a value"); | ||
| Dbg.Assert(!String.IsNullOrEmpty(match), "need a value"); | ||
| Dbg.Assert(match.Trim().ToLowerInvariant() == match, "match should be normalized to lowercase w/ no outside whitespace"); | ||
| Dbg.Assert(smallestUnambiguousMatch.Trim().ToLowerInvariant() == smallestUnambiguousMatch, "match should be normalized to lowercase w/ no outside whitespace"); | ||
| Dbg.Assert(match.Contains(smallestUnambiguousMatch), "sUM should be a substring of match"); | ||
|
|
||
| if (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0) | ||
| { | ||
| if (switchKey.Length >= smallestUnambiguousMatch.Length) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| private void ParseFormat(string[] args, ref int i, ref Serialization.DataFormat format, string resourceStr) | ||
| { | ||
| StringBuilder sb = new StringBuilder(); | ||
|
|
@@ -892,15 +1028,6 @@ private void ParseExecutionPolicy(string[] args, ref int i, ref string execution | |
| executionPolicy = args[i]; | ||
| } | ||
|
|
||
| private static string NormalizeFilePath(string path) | ||
| { | ||
| // Normalize slashes | ||
| path = path.Replace(StringLiterals.AlternatePathSeparator, | ||
| StringLiterals.DefaultPathSeparator); | ||
|
|
||
| return Path.GetFullPath(path); | ||
| } | ||
|
|
||
| private bool ParseFile(string[] args, ref int i, bool noexitSeen) | ||
| { | ||
| // Process file execution. We don't need to worry about checking -command | ||
|
|
@@ -1201,6 +1328,7 @@ private bool CollectArgs(string[] args, ref int i) | |
| return true; | ||
| } | ||
|
|
||
| private static bool _dirtyEarlyParse; | ||
| private bool _socketServerMode; | ||
| private bool _serverMode; | ||
| private bool _namedPipeServerMode; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this means we won't be running tests against the prior OS version, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found no differences in the log format, but yes correct