-
Notifications
You must be signed in to change notification settings - Fork 8.1k
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 all 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 | ||
| { | ||
| get | ||
|
|
@@ -393,6 +394,205 @@ 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="settingFileArgIndex"> | ||
| /// The index in args to the argument following '-SettingFile'. | ||
| /// </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 TryParseSettingFileHelper(string[] args, int settingFileArgIndex, CommandLineParameterParser parser) | ||
| { | ||
| if (settingFileArgIndex >= args.Length) | ||
| { | ||
| if (parser != null) | ||
| { | ||
| parser.WriteCommandLineError( | ||
| CommandLineParameterParserStrings.MissingSettingsFileArgument); | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| string configFile = null; | ||
| try | ||
| { | ||
| configFile = NormalizeFilePath(args[settingFileArgIndex]); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| if (parser != null) | ||
| { | ||
| string error = string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidSettingsFileArgument, args[settingFileArgIndex], 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) | ||
| { | ||
| // indicates that we've called this method on this instance, and that when it's done, the state variables | ||
| // will reflect the parse. | ||
|
|
||
| EarlyParseHelper(args); | ||
| } | ||
|
|
||
| private static string GetConfigurationNameFromGroupPolicy() | ||
| { | ||
| // Current user policy takes precedence. | ||
| var consoleSessionSetting = Utils.GetPolicySetting<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig); | ||
|
|
||
| return (consoleSessionSetting?.EnableConsoleSessionConfiguration == true && !string.IsNullOrEmpty(consoleSessionSetting?.ConsoleSessionConfigurationName)) ? | ||
| consoleSessionSetting.ConsoleSessionConfigurationName : string.Empty; | ||
|
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 more short name like
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. this is an existing variable name. Please file an issues |
||
| } | ||
|
|
||
| /// <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) | ||
| { | ||
| if(args == null) | ||
| { | ||
| Dbg.Assert(args != null, "Argument 'args' to EarlyParseHelper should never be null"); | ||
| return; | ||
| } | ||
|
|
||
| bool noexitSeen = false; | ||
| for (int i = 0; i < args.Length; ++i) | ||
| { | ||
| (string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, parser: null, ref noexitSeen); | ||
| if (switchKeyResults.ShouldBreak) | ||
| { | ||
| break; | ||
| } | ||
|
|
||
| string switchKey = switchKeyResults.SwitchKey; | ||
|
|
||
| if (MatchSwitch(switchKey, match: "settingsfile", smallestUnambiguousMatch: "settings")) | ||
| { | ||
| // parse setting file arg and don't write error as there is no host yet. | ||
| if (!TryParseSettingFileHelper(args, ++i, parser: null)) | ||
| { | ||
| 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 parse files in the args. If not supplied, Files will not be parsed. | ||
| /// </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"); | ||
|
|
||
| return (match.Trim().ToLowerInvariant().IndexOf(switchKey, StringComparison.Ordinal) == 0 && | ||
| switchKey.Length >= smallestUnambiguousMatch.Length); | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| private void ShowHelp() | ||
| { | ||
| Dbg.Assert(_helpText != null, "_helpText should not be null"); | ||
|
|
@@ -463,57 +663,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)) | ||
| (string SwitchKey, bool ShouldBreak) switchKeyResults = GetSwitchKey(args, ref i, this, ref noexitSeen); | ||
| if (switchKeyResults.ShouldBreak) | ||
| { | ||
| 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 +874,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 (!TryParseSettingFileHelper(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 +960,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 +1015,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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -148,6 +148,12 @@ internal static int Start( | |
|
|
||
| try | ||
| { | ||
| // We need to read the settings file before we create the console host | ||
| string[] tempArgs = new string[args.GetLength(0)]; | ||
| args.CopyTo(tempArgs, 0); | ||
|
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. Could you please clarify why we need clone
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. The existing code cloned the args. I don't want to break something by not cloning.
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. Reviewing the code. I don't think it has to be. I especially don't think it has to be twice. compromise, I'll remove the second clone, you file an issue to remove the first one.
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 #7457. |
||
|
|
||
| CommandLineParameterParser.EarlyParse(tempArgs); | ||
|
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've created issue #7460 to move this call to UnmanagedPSEntry.Start prior to PSEtwLog.LogConsoleStartup().
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. Thanks |
||
|
|
||
| // We might be able to ignore console host creation error if we are running in | ||
| // server mode, which does not require a console. | ||
| HostException hostException = null; | ||
|
|
@@ -168,8 +174,6 @@ internal static int Start( | |
| s_cpp = new CommandLineParameterParser( | ||
| (s_theConsoleHost != null) ? s_theConsoleHost.UI : (new NullHostUserInterface()), | ||
| bannerText, helpText); | ||
| string[] tempArgs = new string[args.GetLength(0)]; | ||
| args.CopyTo(tempArgs, 0); | ||
|
|
||
| s_cpp.Parse(tempArgs); | ||
|
|
||
|
|
||
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