diff --git a/build.psm1 b/build.psm1 index 0fed7d091dd..1f8a8b43800 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1364,7 +1364,8 @@ function Test-PSPesterResults function Start-PSxUnit { [CmdletBinding()]param( - [string] $TestResultsFile = "XUnitResults.xml" + [string] $SequentialTestResultsFile = "SequentialXUnitResults.xml", + [string] $ParallelTestResultsFile = "ParallelXUnitResults.xml" ) # Add .NET CLI tools to PATH @@ -1375,9 +1376,11 @@ function Start-PSxUnit { throw "PowerShell must be built before running tests!" } - if(Test-Path $TestResultsFile) - { - Remove-Item $TestResultsFile -Force -ErrorAction SilentlyContinue + if (Test-Path $SequentialTestResultsFile) { + Remove-Item $SequentialTestResultsFile -Force -ErrorAction SilentlyContinue + } + if (Test-Path $ParallelTestResultsFile) { + Remove-Item $ParallelTestResultsFile -Force -ErrorAction SilentlyContinue } try { @@ -1386,12 +1389,7 @@ function Start-PSxUnit { # Path manipulation to obtain test project output directory dotnet restore - # --fx-version workaround required due to https://github.com/dotnet/cli/issues/7901#issuecomment-343323674 - if($Environment.IsWindows) - { - dotnet xunit --fx-version 2.0.0 -xml $TestResultsFile - } - else + if(-not $Environment.IsWindows) { if($Environment.IsMacOS) { @@ -1419,9 +1417,12 @@ function Start-PSxUnit { { throw "Dependencies $requiredDependencies not met." } - - dotnet xunit --fx-version 2.0.0 -configuration $Options.configuration -xml $TestResultsFile } + + # '-fxversion' workaround required due to https://github.com/dotnet/cli/issues/7901#issuecomment-343323674 + # Run sequential tests first, and then run the tests that can execute in parallel + dotnet xunit -fxversion 2.0.0 -configuration $Options.configuration -xml $SequentialTestResultsFile -namespace "PSTests.Sequential" -parallel none + dotnet xunit -fxversion 2.0.0 -configuration $Options.configuration -xml $ParallelTestResultsFile -namespace "PSTests.Parallel" -nobuild } finally { Pop-Location diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs index cbce5c675dc..40eed14d8e8 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParameterParser.cs @@ -10,6 +10,7 @@ using System.IO; using System.Collections.ObjectModel; using System.Management.Automation; +using System.Management.Automation.Configuration; using System.Management.Automation.Runspaces; using System.Management.Automation.Internal; using System.Diagnostics; @@ -459,29 +460,17 @@ internal void Parse(string[] args) } } - private static string s_groupPolicyBase = @"Software\Policies\Microsoft\Windows\PowerShell"; - private static string s_consoleSessionConfigurationKey = "ConsoleSessionConfiguration"; - private static string s_enableConsoleSessionConfiguration = "EnableConsoleSessionConfiguration"; - private static string s_consoleSessionConfigurationName = "ConsoleSessionConfigurationName"; private static string GetConfigurationNameFromGroupPolicy() { // Current user policy takes precedence. - var groupPolicySettings = Utils.GetGroupPolicySetting(s_groupPolicyBase, s_consoleSessionConfigurationKey, Utils.RegCurrentUserThenLocalMachine); - if (groupPolicySettings != null) + var consoleSessionSetting = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + if (consoleSessionSetting != null) { - object keyValue; - if (groupPolicySettings.TryGetValue(s_enableConsoleSessionConfiguration, out keyValue)) + if (consoleSessionSetting.EnableConsoleSessionConfiguration == true) { - if (String.Equals(keyValue.ToString(), "1", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(consoleSessionSetting.ConsoleSessionConfigurationName)) { - if (groupPolicySettings.TryGetValue(s_consoleSessionConfigurationName, out keyValue)) - { - string consoleSessionConfigurationName = keyValue.ToString(); - if (!string.IsNullOrEmpty(consoleSessionConfigurationName)) - { - return consoleSessionConfigurationName; - } - } + return consoleSessionSetting.ConsoleSessionConfigurationName; } } } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index 826bb6bc6a2..395078354a6 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1643,59 +1643,6 @@ private int GetCmdletRemovalIndex(List cacheEntry, string PSSnapin) internal ExecutionContext Context { get; } - /// - /// Reads the path for the appropriate shellID from the registry. - /// - /// - /// - /// The ID of the shell to retrieve the path for. - /// - /// - /// - /// The path to the shell represented by the shellID. - /// - /// - /// - /// The shellID must be registered in the Windows Registry in either - /// the HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE hive under - /// Software/Microsoft/MSH/<ShellID> and are searched in that order. - /// - /// - internal static string GetShellPathFromRegistry(string shellID) - { - string result = null; - -#if !UNIX - try - { - RegistryKey shellKey = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPath(shellID)); - if (shellKey != null) - { - // verify the value kind as a string - RegistryValueKind kind = shellKey.GetValueKind("path"); - - if (kind == RegistryValueKind.ExpandString || - kind == RegistryValueKind.String) - { - result = shellKey.GetValue("path") as string; - } - } - } - // Ignore these exceptions and return an empty or null result - catch (SecurityException) - { - } - catch (IOException) - { - } - catch (ArgumentException) - { - } -#endif - - return result; - } - internal static PSModuleAutoLoadingPreference GetCommandDiscoveryPreference(ExecutionContext context, VariablePath variablePath, string environmentVariable) { Dbg.Assert(context != null, "context cannot be Null"); diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index a44549cf99c..6d703e93624 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -11,6 +11,7 @@ using System.IO; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Management.Automation.Runspaces; using System.Management.Automation.Security; @@ -4749,28 +4750,18 @@ internal static ModuleLoggingGroupPolicyStatus GetModuleLoggingInformation(out I { moduleNames = null; ModuleLoggingGroupPolicyStatus status = ModuleLoggingGroupPolicyStatus.Undefined; - Dictionary groupPolicySettings = Utils.GetGroupPolicySetting("ModuleLogging", Utils.RegLocalMachineThenCurrentUser); - if (groupPolicySettings != null) + var moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + if (moduleLogging != null) { - object enableModuleLoggingValue = null; - if (groupPolicySettings.TryGetValue("EnableModuleLogging", out enableModuleLoggingValue)) + if (moduleLogging.EnableModuleLogging == false) { - if (String.Equals(enableModuleLoggingValue.ToString(), "0", StringComparison.OrdinalIgnoreCase)) - { - return ModuleLoggingGroupPolicyStatus.Disabled; - } - - if (String.Equals(enableModuleLoggingValue.ToString(), "1", StringComparison.OrdinalIgnoreCase)) - { - status = ModuleLoggingGroupPolicyStatus.Enabled; - - object moduleNamesValue = null; - if (groupPolicySettings.TryGetValue("ModuleNames", out moduleNamesValue)) - { - moduleNames = new List((string[])moduleNamesValue); - } - } + status = ModuleLoggingGroupPolicyStatus.Disabled; + } + else if (moduleLogging.EnableModuleLogging == true) + { + status = ModuleLoggingGroupPolicyStatus.Enabled; + moduleNames = moduleLogging.ModuleNames; } } diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index a6b70bbc466..1a71b3b619c 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Management.Automation.Language; using Microsoft.PowerShell.Commands; @@ -977,8 +978,8 @@ internal static string GetModulePath() internal static string SetModulePath() { string currentModulePath = GetExpandedEnvironmentVariable(Constants.PSModulePathEnvVar, EnvironmentVariableTarget.Process); - string systemWideModulePath = ConfigPropertyAccessor.Instance.GetModulePath(ConfigPropertyAccessor.PropertyScope.SystemWide); - string personalModulePath = ConfigPropertyAccessor.Instance.GetModulePath(ConfigPropertyAccessor.PropertyScope.CurrentUser); + string systemWideModulePath = PowerShellConfig.Instance.GetModulePath(ConfigScope.SystemWide); + string personalModulePath = PowerShellConfig.Instance.GetModulePath(ConfigScope.CurrentUser); string newModulePathString = GetModulePath(currentModulePath, systemWideModulePath, personalModulePath); diff --git a/src/System.Management.Automation/engine/PropertyAccessor.cs b/src/System.Management.Automation/engine/PSConfiguration.cs similarity index 62% rename from src/System.Management.Automation/engine/PropertyAccessor.cs rename to src/System.Management.Automation/engine/PSConfiguration.cs index d44e34461fa..ef01eba36c7 100644 --- a/src/System.Management.Automation/engine/PropertyAccessor.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -1,206 +1,65 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Xml; using System.IO; using System.Text; -using System.Reflection; -using System.Globalization; using System.Threading; - -using System.Management.Automation; -using System.Management.Automation.Internal; -using Microsoft.Win32; - using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.Management.Automation.Internal; - -namespace System.Management.Automation +namespace System.Management.Automation.Configuration { - - /// - /// Leverages the strategy pattern to abstract away the details of gathering properties from outside sources. - /// Note: This is a class so that it can be internal. - /// - internal abstract class ConfigPropertyAccessor + internal enum ConfigScope { - #region Statics - /// - /// Static constructor to instantiate an instance - /// - static ConfigPropertyAccessor() - { - Instance = new JsonConfigFileAccessor(); - } - /// - /// The instance of the ConfigPropertyAccessor to use to interact with properties. - /// Derived classes should not be directly instantiated. - /// - internal static readonly ConfigPropertyAccessor Instance; - - #endregion // Statics - - #region Enums - - /// - /// Describes the scope of the property query. - /// SystemWide properties apply to all users. - /// CurrentUser properties apply to the current user that is impersonated. - /// - internal enum PropertyScope - { - SystemWide = 0, - CurrentUser = 1 - } - - #endregion // Enums - - #region Interface Methods - - /// - /// Existing Key = HKLM:\System\CurrentControlSet\Control\Session Manager\Environment - /// Proposed value = %ProgramFiles%\PowerShell\Modules by default - /// - /// Note: There is no setter because this value is immutable. - /// - /// Module path values from the config file. - internal abstract string GetModulePath(PropertyScope scope); - - /// - /// Existing Key = HKCU and HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell - /// Proposed value = Existing default execution policy if not already specified - /// - /// Where it should check for the value. - /// The shell associated with this policy. Typically, it is "Microsoft.PowerShell" - /// - internal abstract string GetExecutionPolicy(PropertyScope scope, string shellId); - internal abstract void RemoveExecutionPolicy(PropertyScope scope, string shellId); - internal abstract void SetExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy); - - /// - /// Existing Key = HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds - /// Proposed value = existing default. Probably "1" - /// - /// Whether console prompting should happen. - internal abstract bool GetConsolePrompting(); - internal abstract void SetConsolePrompting(bool shouldPrompt); - - /// - /// Existing Key = HKLM\SOFTWARE\Microsoft\PowerShell - /// Proposed value = Existing default. Probably "0" - /// - /// Boolean indicating whether Update-Help should prompt - internal abstract bool GetDisablePromptToUpdateHelp(); - internal abstract void SetDisablePromptToUpdateHelp(bool prompt); - - /// - /// Existing Key = HKCU and HKLM\Software\Policies\Microsoft\Windows\PowerShell\UpdatableHelp - /// Proposed value = blank.This should be supported though - /// - /// - internal abstract string GetDefaultSourcePath(); - internal abstract void SetDefaultSourcePath(string defaultPath); + // SystemWide configuration applies to all users. + SystemWide = 0, -#if UNIX - /// - /// Gets the application identity (name) to use for writing to syslog. - /// - /// - /// The string identity to use for writing to syslog. - /// - /// The default value is 'powershell' - /// - /// - internal abstract string GetSysLogIdentity(); - - /// - /// Gets the log level filter. - /// - /// One of the PSLevel values indicating the level to log. - /// - /// The default value is PSLevel.Informational - /// - /// - internal abstract PSLevel GetLogLevel(); - - /// - /// Gets the bitmask of the PSChannel values to log. - /// - /// - /// A bitmask of PSChannel.Operational and/or PSChannel.Analytic - /// - /// The default value is PSChannel.Operational - /// - /// - internal abstract PSChannel GetLogChannels(); - - /// - /// Gets the bitmask of keywords to log. - /// - /// - /// A bitmask of PSKeyword values. - /// - /// The default value is all keywords other than UseAlwaysAnalytic - /// - /// - internal abstract PSKeyword GetLogKeywords(); - -#endif // UNIX - #endregion // Interface Methods + // CurrentUser configuration applies to the current user. + CurrentUser = 1 } /// - /// JSON configuration file accessor - /// - /// Reads from and writes to configuration files. The values stored were - /// originally stored in the Windows registry. + /// Reads from and writes to the JSON configuration files. + /// The config values were originally stored in the Windows registry. /// - internal class JsonConfigFileAccessor : ConfigPropertyAccessor + internal sealed class PowerShellConfig { + // Provide a singleton + private static readonly PowerShellConfig s_instance = new PowerShellConfig(); + internal static PowerShellConfig Instance => s_instance; + private string psHomeConfigDirectory; private string appDataConfigDirectory; - private const string configFileName = "PowerShellProperties.json"; + private const string configFileName = "powershell.config.json"; /// - /// Lock used to enable multiple concurrent readers and singular write locks within a - /// single process. - /// TODO: This solution only works for IO from a single process. A more robust solution is needed to enable ReaderWriterLockSlim behavior between processes. + /// Lock used to enable multiple concurrent readers and singular write locks within a single process. + /// TODO: This solution only works for IO from a single process. + /// A more robust solution is needed to enable ReaderWriterLockSlim behavior between processes. /// private ReaderWriterLockSlim fileLock = new ReaderWriterLockSlim(); - internal JsonConfigFileAccessor() + private PowerShellConfig() { - // // Sets the system-wide configuration directory - // - Assembly assembly = typeof(PSObject).GetTypeInfo().Assembly; - psHomeConfigDirectory = Path.GetDirectoryName(assembly.Location); + psHomeConfigDirectory = Utils.DefaultPowerShellAppBase; - // // Sets the per-user configuration directory // Note: This directory may or may not exist depending upon the // execution scenario. Writes will attempt to create the directory // if it does not already exist. - // appDataConfigDirectory = Utils.GetUserConfigurationDirectory(); } /// - /// This value is not writable via the API and must be set using a text editor. + /// Existing Key = HKLM:\System\CurrentControlSet\Control\Session Manager\Environment + /// Proposed value = %ProgramFiles%\PowerShell\Modules by default + /// Note: There is no setter because this value is immutable. /// - /// + /// Whether this is a system-wide or per-user setting. /// Value if found, null otherwise. The behavior matches ModuleIntrinsics.GetExpandedEnvironmentVariable(). - internal override string GetModulePath(PropertyScope scope) + internal string GetModulePath(ConfigScope scope) { - string scopeDirectory = psHomeConfigDirectory; - - // Defaults to system wide. - if (PropertyScope.CurrentUser == scope) - { - scopeDirectory = appDataConfigDirectory; - } - + string scopeDirectory = scope == ConfigScope.SystemWide ? psHomeConfigDirectory : appDataConfigDirectory; string fileName = Path.Combine(scopeDirectory, configFileName); string modulePath = ReadValueFromFile(fileName, Constants.PSModulePathEnvVar); @@ -217,7 +76,7 @@ internal override string GetModulePath(PropertyScope scope) /// /// Schema: /// { - /// "shell ID string","ExecutionPolicy" : "execution policy string" + /// "shell-ID-string:ExecutionPolicy" : "execution policy string" /// } /// /// TODO: In a single config file, it might be better to nest this. It is unnecessary complexity until a need arises for more nested values. @@ -225,13 +84,13 @@ internal override string GetModulePath(PropertyScope scope) /// Whether this is a system-wide or per-user setting. /// The shell associated with this policy. Typically, it is "Microsoft.PowerShell" /// The execution policy if found. Null otherwise. - internal override string GetExecutionPolicy(PropertyScope scope, string shellId) + internal string GetExecutionPolicy(ConfigScope scope, string shellId) { string execPolicy = null; string scopeDirectory = psHomeConfigDirectory; // Defaults to system wide. - if(PropertyScope.CurrentUser == scope) + if(ConfigScope.CurrentUser == scope) { scopeDirectory = appDataConfigDirectory; } @@ -247,12 +106,12 @@ internal override string GetExecutionPolicy(PropertyScope scope, string shellId) return execPolicy; } - internal override void RemoveExecutionPolicy(PropertyScope scope, string shellId) + internal void RemoveExecutionPolicy(ConfigScope scope, string shellId) { string scopeDirectory = psHomeConfigDirectory; // Defaults to system wide. - if (PropertyScope.CurrentUser == scope) + if (ConfigScope.CurrentUser == scope) { scopeDirectory = appDataConfigDirectory; } @@ -262,12 +121,12 @@ internal override void RemoveExecutionPolicy(PropertyScope scope, string shellId RemoveValueFromFile(fileName, valueName); } - internal override void SetExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy) + internal void SetExecutionPolicy(ConfigScope scope, string shellId, string executionPolicy) { string scopeDirectory = psHomeConfigDirectory; // Defaults to system wide. - if (PropertyScope.CurrentUser == scope) + if (ConfigScope.CurrentUser == scope) { // Exceptions are not caught so that they will propagate to the // host for display to the user. @@ -292,13 +151,13 @@ internal override void SetExecutionPolicy(PropertyScope scope, string shellId, s /// } /// /// Whether console prompting should happen. If the value cannot be read it defaults to false. - internal override bool GetConsolePrompting() + internal bool GetConsolePrompting() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); return ReadValueFromFile(fileName, "ConsolePrompting"); } - internal override void SetConsolePrompting(bool shouldPrompt) + internal void SetConsolePrompting(bool shouldPrompt) { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); WriteValueToFile(fileName, "ConsolePrompting", shouldPrompt); @@ -314,46 +173,26 @@ internal override void SetConsolePrompting(bool shouldPrompt) /// } /// /// Boolean indicating whether Update-Help should prompt. If the value cannot be read, it defaults to false. - internal override bool GetDisablePromptToUpdateHelp() + internal bool GetDisablePromptToUpdateHelp() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); return ReadValueFromFile(fileName, "DisablePromptToUpdateHelp"); } - internal override void SetDisablePromptToUpdateHelp(bool prompt) + internal void SetDisablePromptToUpdateHelp(bool prompt) { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); WriteValueToFile(fileName, "DisablePromptToUpdateHelp", prompt); } /// - /// Existing Key = HKCU and HKLM\Software\Policies\Microsoft\Windows\PowerShell\UpdatableHelp - /// Proposed value = blank.This should be supported though - /// - /// Schema: - /// { - /// "DefaultSourcePath" : "path to local updatable help location" - /// } + /// Corresponding settings of the original Group Policies /// - /// The source path if found, null otherwise. - internal override string GetDefaultSourcePath() + internal PowerShellPolicies GetPowerShellPolicies(ConfigScope scope) { - string fileName = Path.Combine(psHomeConfigDirectory, configFileName); - - string rawExecPolicy = ReadValueFromFile(fileName, "DefaultSourcePath"); - - if (!String.IsNullOrEmpty(rawExecPolicy)) - { - return rawExecPolicy; - } - return null; - } - - internal override void SetDefaultSourcePath(string defaultPath) - { - string fileName = Path.Combine(psHomeConfigDirectory, configFileName); - - WriteValueToFile(fileName, "DefaultSourcePath", defaultPath); + string scopeDirectory = (scope == ConfigScope.SystemWide) ? psHomeConfigDirectory : appDataConfigDirectory; + string fileName = Path.Combine(scopeDirectory, configFileName); + return ReadValueFromFile(fileName, nameof(PowerShellPolicies)); } #if UNIX @@ -361,12 +200,9 @@ internal override void SetDefaultSourcePath(string defaultPath) /// Gets the identity name to use for writing to syslog. /// /// - /// The string identity to use for writing to syslog. - /// - /// The default value is 'powershell'. - /// + /// The string identity to use for writing to syslog. The default value is 'powershell'. /// - internal override string GetSysLogIdentity() + internal string GetSysLogIdentity() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); string identity = ReadValueFromFile(fileName, "LogIdentity"); @@ -382,12 +218,10 @@ internal override string GetSysLogIdentity() /// /// Gets the log level filter. /// - /// One of the PSLevel values indicating the level to log. - /// - /// The default value is PSLevel.Informational. - /// + /// + /// One of the PSLevel values indicating the level to log. The default value is PSLevel.Informational. /// - internal override PSLevel GetLogLevel() + internal PSLevel GetLogLevel() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); string levelName = ReadValueFromFile(fileName, "LogLevel"); @@ -418,12 +252,9 @@ internal override PSLevel GetLogLevel() /// Gets the bitmask of the PSChannel values to log. /// /// - /// A bitmask of PSChannel.Operational and/or PSChannel.Analytic. - /// - /// The default value is PSChannel.Operational. - /// + /// A bitmask of PSChannel.Operational and/or PSChannel.Analytic. The default value is PSChannel.Operational. /// - internal override PSChannel GetLogChannels() + internal PSChannel GetLogChannels() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); string values = ReadValueFromFile(fileName, "LogChannels"); @@ -464,12 +295,9 @@ internal override PSChannel GetLogChannels() /// Gets the bitmask of keywords to log. /// /// - /// A bitmask of PSKeyword values. - /// - /// The default value is all keywords other than UseAlwaysAnalytic. - /// + /// A bitmask of PSKeyword values. The default value is all keywords other than UseAlwaysAnalytic. /// - internal override PSKeyword GetLogKeywords() + internal PSKeyword GetLogKeywords() { string fileName = Path.Combine(psHomeConfigDirectory, configFileName); string values = ReadValueFromFile(fileName, "LogKeywords"); @@ -502,48 +330,36 @@ internal override PSKeyword GetLogKeywords() return result; } - #endif // UNIX - - private T ReadValueFromFile(string fileName, string key) + + private T ReadValueFromFile(string fileName, string key, T defaultValue = default(T), + Func readImpl = null) { + if (!File.Exists(fileName)) { return defaultValue; } + + // Open file for reading, but allow multiple readers fileLock.EnterReadLock(); try { - // Open file for reading, but allow multiple readers - using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (StreamReader streamRdr = new StreamReader(fs)) - using (JsonTextReader jsonReader = new JsonTextReader(streamRdr)) + using (var streamReader = new StreamReader(fileName)) + using (var jsonReader = new JsonTextReader(streamReader)) { - // Safely determines whether there is content to read from the file - bool isReadSuccess = jsonReader.Read(); - if (isReadSuccess) + var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 10 }; + var serializer = JsonSerializer.Create(settings); + + var configData = serializer.Deserialize(jsonReader); + if (configData != null && configData.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken jToken)) { - JObject jsonObject = (JObject) JToken.ReadFrom(jsonReader); - JToken value = jsonObject.GetValue(key); - if (null != value) - { - return value.ToObject(); - } + return readImpl != null ? readImpl(jToken, serializer, defaultValue) : jToken.ToObject(serializer); } } } - catch (FileNotFoundException) - { - // The file doesn't exist. Treat this the same way as if the - // key was not present in the file. - } - catch (DirectoryNotFoundException) - { - // A directory in the path does not exist. Treat this as if the - // key is not present in the file. - } finally { fileLock.ExitReadLock(); } - return default(T); + return defaultValue; } /// @@ -677,5 +493,129 @@ private void RemoveValueFromFile(string fileName, string key) } } } -} // Namespace System.Management.Automation + #region GroupPolicy Configs + + /// + /// The GroupPolicy related settings used in PowerShell are as follows in Registry: + /// - Software\Policies\Microsoft\PowerShellCore -- { EnableScripts (0 or 1); ExecutionPolicy (string) } + /// SubKeys Name-Value-Pairs + /// - ScriptBlockLogging { EnableScriptBlockLogging (0 or 1); EnableScriptBlockInvocationLogging (0 or 1) } + /// - ModuleLogging { EnableModuleLogging (0 or 1); ModuleNames (string[]) } + /// - Transcription { EnableTranscripting (0 or 1); OutputDirectory (string); EnableInvocationHeader (0 or 1) } + /// - UpdatableHelp { DefaultSourcePath (string) } + /// - ConsoleSessionConfiguration { EnableConsoleSessionConfiguration (0 or 1); ConsoleSessionConfigurationName (string) } + /// - Software\Policies\Microsoft\Windows\EventLog + /// SubKeys Name-Value-Pairs + /// - ProtectedEventLogging { EnableProtectedEventLogging (0 or 1); EncryptionCertificate (string[]) } + /// + /// The JSON representation is in sync with the 'PowerShellPolicies' type. Here is an example: + /// { + /// "PowerShellPolicies": { + /// "ScriptExecution": { + /// "ExecutionPolicy": "RemoteSigned" + /// }, + /// "ScriptBlockLogging": { + /// "EnableScriptBlockInvocationLogging": true, + /// "EnableScriptBlockLogging": false + /// }, + /// "ProtectedEventLogging": { + /// "EnableProtectedEventLogging": false, + /// "EncryptionCertificate": [ + /// "Joe" + /// ] + /// }, + /// "Transcription": { + /// "EnableTranscripting": true, + /// "EnableInvocationHeader": true, + /// "OutputDirectory": "c:\\tmp" + /// }, + /// "UpdatableHelp": { + /// "DefaultSourcePath": "f:\\temp" + /// }, + /// "ConsoleSessionConfiguration": { + /// "EnableConsoleSessionConfiguration": true, + /// "ConsoleSessionConfigurationName": "name" + /// } + /// } + /// } + /// + internal sealed class PowerShellPolicies + { + public ScriptExecution ScriptExecution { get; set; } + public ScriptBlockLogging ScriptBlockLogging { get; set; } + public ModuleLogging ModuleLogging { get; set; } + public ProtectedEventLogging ProtectedEventLogging { get; set; } + public Transcription Transcription { get; set; } + public UpdatableHelp UpdatableHelp { get; set; } + public ConsoleSessionConfiguration ConsoleSessionConfiguration { get; set; } + } + + internal abstract class PolicyBase { } + + /// + /// Setting about ScriptExecution + /// + internal sealed class ScriptExecution : PolicyBase + { + public string ExecutionPolicy { get; set; } + public bool? EnableScripts { get; set; } + } + + /// + /// Setting about ScriptBlockLogging + /// + internal sealed class ScriptBlockLogging : PolicyBase + { + public bool? EnableScriptBlockInvocationLogging { get; set; } + public bool? EnableScriptBlockLogging { get; set; } + } + + /// + /// Setting about ModuleLogging + /// + internal sealed class ModuleLogging : PolicyBase + { + public bool? EnableModuleLogging { get; set; } + public string[] ModuleNames { get; set; } + } + + /// + /// Setting about Transcription + /// + internal sealed class Transcription : PolicyBase + { + public bool? EnableTranscripting { get; set; } + public bool? EnableInvocationHeader { get; set; } + public string OutputDirectory { get; set; } + } + + /// + /// Setting about UpdatableHelp + /// + internal sealed class UpdatableHelp : PolicyBase + { + public bool? EnableUpdateHelpDefaultSourcePath { get; set; } + public string DefaultSourcePath { get; set; } + } + + /// + /// Setting about ConsoleSessionConfiguration + /// + internal sealed class ConsoleSessionConfiguration : PolicyBase + { + public bool? EnableConsoleSessionConfiguration { get; set; } + public string ConsoleSessionConfigurationName { get; set; } + } + + /// + /// Setting about ProtectedEventLogging + /// + internal sealed class ProtectedEventLogging : PolicyBase + { + public bool? EnableProtectedEventLogging { get; set; } + public string[] EncryptionCertificate { get; set; } + } + + #endregion +} diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 11798694ea0..3659d0c4cdd 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -5,6 +5,7 @@ using System.Security; using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Management.Automation.Security; using System.Reflection; @@ -233,12 +234,11 @@ internal static string GetApplicationBaseFromRegistry(string shellId) } #endif - internal static string DefaultPowerShellAppBase { get; } = GetApplicationBase(DefaultPowerShellShellID); - + internal static string DefaultPowerShellAppBase => GetApplicationBase(DefaultPowerShellShellID); internal static string GetApplicationBase(string shellId) { // Use the location of SMA.dll as the application base. - Assembly assembly = typeof(PSObject).GetTypeInfo().Assembly; + Assembly assembly = typeof(PSObject).Assembly; return Path.GetDirectoryName(assembly.Location); } @@ -497,125 +497,210 @@ internal static bool IsValidPSEditionValue(string editionValue) /// internal static string ModuleDirectory = Path.Combine(ProductNameForDirectory, "Modules"); - internal static string GetRegistryConfigurationPrefix() - { - // For 3.0 PowerShell, we still use "1" as the registry version key for - // Snapin and Custom shell lookup/discovery. - // For 3.0 PowerShell, we use "3" as the registry version key only for Engine - // related data like ApplicationBase etc. - return "SOFTWARE\\Microsoft\\PowerShell\\" + PSVersionInfo.RegistryVersion1Key + "\\ShellIds"; - } + internal readonly static ConfigScope[] SystemWideOnlyConfig = new[] { ConfigScope.SystemWide }; + internal readonly static ConfigScope[] CurrentUserOnlyConfig = new[] { ConfigScope.CurrentUser }; + internal readonly static ConfigScope[] SystemWideThenCurrentUserConfig = new[] { ConfigScope.SystemWide, ConfigScope.CurrentUser }; + internal readonly static ConfigScope[] CurrentUserThenSystemWideConfig = new[] { ConfigScope.CurrentUser, ConfigScope.SystemWide }; - internal static string GetRegistryConfigurationPath(string shellID) + internal static T GetPolicySetting(ConfigScope[] preferenceOrder) where T : PolicyBase, new() { - return GetRegistryConfigurationPrefix() + "\\" + shellID; - } - - // Calling static members of 'Registry' on UNIX will raise 'PlatformNotSupportedException' -#if UNIX - internal static RegistryKey[] RegLocalMachine = null; - internal static RegistryKey[] RegCurrentUser = null; - internal static RegistryKey[] RegLocalMachineThenCurrentUser = null; - internal static RegistryKey[] RegCurrentUserThenLocalMachine = null; -#else - internal static RegistryKey[] RegLocalMachine = new[] { Registry.LocalMachine }; - internal static RegistryKey[] RegCurrentUser = new[] { Registry.CurrentUser }; - internal static RegistryKey[] RegLocalMachineThenCurrentUser = new[] { Registry.LocalMachine, Registry.CurrentUser }; - internal static RegistryKey[] RegCurrentUserThenLocalMachine = new[] { Registry.CurrentUser, Registry.LocalMachine }; + T policy = null; +#if !UNIX + // On Windows, group policy settings from registry take precedence. + // If the requested policy is not defined in registry, we query the configuration file. + policy = GetPolicySettingFromGPO(preferenceOrder); + if (policy != null) { return policy; } #endif - - internal static Dictionary GetGroupPolicySetting(string settingName, RegistryKey[] preferenceOrder) - { - string groupPolicyBase = "Software\\Policies\\Microsoft\\Windows\\PowerShell"; - return GetGroupPolicySetting(groupPolicyBase, settingName, preferenceOrder); + policy = GetPolicySettingFromConfigFile(preferenceOrder); + return policy; } - // We use a static to avoid creating "extra garbage." - private static Dictionary s_emptyDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly static ConcurrentDictionary s_cachedPoliciesFromConfigFile = + new ConcurrentDictionary(); - internal static Dictionary GetGroupPolicySetting(string groupPolicyBase, string settingName, RegistryKey[] preferenceOrder) + /// + /// Get a specific kind of policy setting from the configuration file. + /// + private static T GetPolicySettingFromConfigFile(ConfigScope[] preferenceOrder) where T : PolicyBase, new() { -#if UNIX - return s_emptyDictionary; -#else - lock (s_cachedGroupPolicySettings) + foreach (ConfigScope scope in preferenceOrder) { - // Return cached information, if we have it - Dictionary settings; - if ((s_cachedGroupPolicySettings.TryGetValue(settingName, out settings)) && - !InternalTestHooks.BypassGroupPolicyCaching) + PowerShellPolicies policies; + if (InternalTestHooks.BypassGroupPolicyCaching) { - return settings; + policies = PowerShellConfig.Instance.GetPowerShellPolicies(scope); + } + else if (!s_cachedPoliciesFromConfigFile.TryGetValue(scope, out policies)) + { + // Use lock here to reduce the contention on accessing the configuration file + lock (s_cachedPoliciesFromConfigFile) + { + policies = s_cachedPoliciesFromConfigFile.GetOrAdd(scope, PowerShellConfig.Instance.GetPowerShellPolicies); + } } - if (!String.Equals(".", settingName, StringComparison.OrdinalIgnoreCase)) + if (policies != null) { - groupPolicyBase += "\\" + settingName; + PolicyBase result = null; + switch (typeof(T).Name) + { + case nameof(ScriptExecution): result = policies.ScriptExecution; break; + case nameof(ScriptBlockLogging): result = policies.ScriptBlockLogging; break; + case nameof(ModuleLogging): result = policies.ModuleLogging; break; + case nameof(ProtectedEventLogging): result = policies.ProtectedEventLogging; break; + case nameof(Transcription): result = policies.Transcription; break; + case nameof(UpdatableHelp): result = policies.UpdatableHelp; break; + case nameof(ConsoleSessionConfiguration): result = policies.ConsoleSessionConfiguration; break; + default: Diagnostics.Assert(false, "Should be unreachable code. Update this switch block when new PowerShell policy types are added."); break; + } + if (result != null) { return (T) result; } } + } + + return null; + } - settings = new Dictionary(StringComparer.OrdinalIgnoreCase); +#if !UNIX + private static readonly Dictionary GroupPolicyKeys = new Dictionary + { + {nameof(ScriptExecution), @"Software\Policies\Microsoft\PowerShellCore"}, + {nameof(ScriptBlockLogging), @"Software\Policies\Microsoft\PowerShellCore\ScriptBlockLogging"}, + {nameof(ModuleLogging), @"Software\Policies\Microsoft\PowerShellCore\ModuleLogging"}, + {nameof(ProtectedEventLogging), @"Software\Policies\Microsoft\Windows\EventLog\ProtectedEventLogging"}, + {nameof(Transcription), @"Software\Policies\Microsoft\PowerShellCore\Transcription"}, + {nameof(UpdatableHelp), @"Software\Policies\Microsoft\PowerShellCore\UpdatableHelp"}, + {nameof(ConsoleSessionConfiguration), @"Software\Policies\Microsoft\PowerShellCore\ConsoleSessionConfiguration"} + }; + private readonly static ConcurrentDictionary, PolicyBase> s_cachedPoliciesFromRegistry = + new ConcurrentDictionary, PolicyBase>(); - foreach (RegistryKey searchKey in preferenceOrder) + /// + /// The implementation of fetching a specific kind of policy setting from the given configuration scope. + /// + private static T GetPolicySettingFromGPOImpl(ConfigScope scope) where T : PolicyBase, new() + { + Type tType = typeof(T); + // SystemWide scope means 'LocalMachine' root key when query from registry + RegistryKey rootKey = (scope == ConfigScope.SystemWide) ? Registry.LocalMachine : Registry.CurrentUser; + + GroupPolicyKeys.TryGetValue(tType.Name, out string gpoKeyPath); + Diagnostics.Assert(gpoKeyPath != null, StringUtil.Format("The GPO registry key path should be pre-defined for {0}", tType.Name)); + + using (RegistryKey gpoKey = rootKey.OpenSubKey(gpoKeyPath)) + { + // If the corresponding GPO key doesn't exist, return null + if (gpoKey == null) { return null; } + + // The corresponding GPO key exists, then create an instance of T + // and populate its properties with the settings + object tInstance = Activator.CreateInstance(tType, nonPublic: true); + var properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public); + bool isAnyPropertySet = false; + + string[] valueNames = gpoKey.GetValueNames(); + string[] subKeyNames = gpoKey.GetSubKeyNames(); + var valueNameSet = valueNames.Length > 0 ? new HashSet(valueNames, StringComparer.OrdinalIgnoreCase) : null; + var subKeyNameSet = subKeyNames.Length > 0 ? new HashSet(subKeyNames, StringComparer.OrdinalIgnoreCase) : null; + + foreach (var property in properties) { - try + string settingName = property.Name; + object rawRegistryValue = null; + + // Get the raw value from registry. + if (valueNameSet != null && valueNameSet.Contains(settingName)) + { + rawRegistryValue = gpoKey.GetValue(settingName); + } + else if (subKeyNameSet != null && subKeyNameSet.Contains(settingName)) { - // Look up the machine-wide group policy - using (RegistryKey key = searchKey.OpenSubKey(groupPolicyBase)) + using (RegistryKey subKey = gpoKey.OpenSubKey(settingName)) { - if (key != null) - { - foreach (string subkeyName in key.GetValueNames()) - { - // A null or empty subkey name string corresponds to a (Default) key. - // If it is null, make it an empty string which the Dictionary can handle. - string keyName = subkeyName ?? string.Empty; + if (subKey != null) { rawRegistryValue = subKey.GetValueNames(); } + } + } - settings[keyName] = key.GetValue(keyName); - } + // Get the actual property value based on the property type. + // If the final property value is not null, then set the property. + if (rawRegistryValue != null) + { + Type propertyType = property.PropertyType; + object propertyValue = null; - foreach (string subkeyName in key.GetSubKeyNames()) + switch (propertyType) + { + case var _ when propertyType == typeof(bool?): + if (rawRegistryValue is int rawIntValue) { - // A null or empty subkey name string corresponds to a (Default) key. - // If it is null, make it an empty string which the Dictionary can handle. - string keyName = subkeyName ?? string.Empty; - - using (RegistryKey subkey = key.OpenSubKey(keyName)) - { - if (subkey != null) - { - settings[keyName] = subkey.GetValueNames(); - } - } + if (rawIntValue == 1) { propertyValue = true; } + else if (rawIntValue == 0) { propertyValue = false; } } - break; - } + case var _ when propertyType == typeof(string): + if (rawRegistryValue is string rawStringValue) + { + propertyValue = rawStringValue; + } + break; + case var _ when propertyType == typeof(string[]): + if (rawRegistryValue is string[] rawStringArrayValue) + { + propertyValue = rawStringArrayValue; + } + else if (rawRegistryValue is string stringValue) + { + propertyValue = new string[] { stringValue }; + } + break; + default: + Diagnostics.Assert(false, "Should be unreachable code. Update this switch block when properties of new types are added to PowerShell policy types."); + break; + } + + // Set the property if the value is not null + if (propertyValue != null) + { + property.SetValue(tInstance, propertyValue); + isAnyPropertySet = true; } - } - catch (System.Security.SecurityException) - { - // User doesn't have access to open group policy key } } - // No group policy settings, then return null - if (settings.Count == 0) + // If no property is set, then we consider this policy as undefined + return isAnyPropertySet ? (T) tInstance : null; + } + } + + /// + /// Get a specific kind of policy setting from the group policy registry key. + /// + private static T GetPolicySettingFromGPO(ConfigScope[] preferenceOrder) where T : PolicyBase, new() + { + PolicyBase policy = null; + foreach (ConfigScope scope in preferenceOrder) + { + if (InternalTestHooks.BypassGroupPolicyCaching) { - settings = null; + policy = GetPolicySettingFromGPOImpl(scope); } - - // Cache the data - if (!InternalTestHooks.BypassGroupPolicyCaching) + else { - s_cachedGroupPolicySettings[settingName] = settings; + var key = Tuple.Create(scope, typeof(T).Name); + if (!s_cachedPoliciesFromRegistry.TryGetValue(key, out policy)) + { + lock (s_cachedPoliciesFromRegistry) + { + policy = s_cachedPoliciesFromRegistry.GetOrAdd(key, tuple => GetPolicySettingFromGPOImpl(tuple.Item1)); + } + } } - return settings; + if (policy != null) { return (T) policy; } } -#endif + + return null; } - private static ConcurrentDictionary> s_cachedGroupPolicySettings = - new ConcurrentDictionary>(); +#endif /// /// Scheduled job module name. diff --git a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs index ce77c12f538..2cac96bb84f 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs @@ -269,7 +269,7 @@ internal static int ReadRegistryInt(string policyValueName, int defaultValue) RegistryKey key; try { - key = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPrefix()); + key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds"); } catch (System.Security.SecurityException) { diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 3caa17609b3..bac5cdd0124 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -9,6 +9,7 @@ using System.Collections.ObjectModel; using System.Security; using System.Globalization; +using System.Management.Automation.Configuration; using System.Management.Automation.Runspaces; using Microsoft.PowerShell.Commands; using System.Threading; @@ -909,9 +910,8 @@ internal void TranscribeError(ExecutionContext context, InvocationInfo invocatio /// internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOption currentTranscript) { - Dictionary groupPolicySettings = Utils.GetGroupPolicySetting("Transcription", Utils.RegLocalMachineThenCurrentUser); - - if (groupPolicySettings != null) + var transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + if (transcription != null) { // If we have an existing system transcript for this process, use that. // Otherwise, populate the static variable with the result of the group policy setting. @@ -921,7 +921,7 @@ internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOptio { if (systemTranscript == null) { - systemTranscript = PSHostUserInterface.GetTranscriptOptionFromSettings(groupPolicySettings, currentTranscript); + systemTranscript = PSHostUserInterface.GetTranscriptOptionFromSettings(transcription, currentTranscript); } } } @@ -931,44 +931,31 @@ internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOptio internal static TranscriptionOption systemTranscript = null; private static Object s_systemTranscriptLock = new Object(); - private static TranscriptionOption GetTranscriptOptionFromSettings(Dictionary settings, TranscriptionOption currentTranscript) + private static TranscriptionOption GetTranscriptOptionFromSettings(Transcription transcriptConfig, TranscriptionOption currentTranscript) { TranscriptionOption transcript = null; - object keyValue = null; - if (settings.TryGetValue("EnableTranscripting", out keyValue)) + if (transcriptConfig.EnableTranscripting == true) { - if (String.Equals(keyValue.ToString(), "1", StringComparison.OrdinalIgnoreCase)) + if (currentTranscript != null) { - if (currentTranscript != null) - { - return currentTranscript; - } - - transcript = new TranscriptionOption(); + return currentTranscript; + } - // Pull out the transcript path - object outputDirectoryValue = null; - if (settings.TryGetValue("OutputDirectory", out outputDirectoryValue)) - { - string outputDirectoryString = outputDirectoryValue as string; - transcript.Path = GetTranscriptPath(outputDirectoryString, true); - } - else - { - transcript.Path = GetTranscriptPath(); - } + transcript = new TranscriptionOption(); - // Pull out the "enable invocation header" - object enableInvocationHeaderValue = null; - if (settings.TryGetValue("EnableInvocationHeader", out enableInvocationHeaderValue)) - { - if (String.Equals("1", enableInvocationHeaderValue.ToString(), StringComparison.OrdinalIgnoreCase)) - { - transcript.IncludeInvocationHeader = true; - } - } + // Pull out the transcript path + if (transcriptConfig.OutputDirectory != null) + { + transcript.Path = GetTranscriptPath(transcriptConfig.OutputDirectory, true); } + else + { + transcript.Path = GetTranscriptPath(); + } + + // Pull out the "enable invocation header" + transcript.IncludeInvocationHeader = transcriptConfig.EnableInvocationHeader == true; } return transcript; diff --git a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs index 87d7e3b140b..6362edd0bcf 100644 --- a/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs +++ b/src/System.Management.Automation/engine/runtime/CompiledScriptBlock.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; @@ -1234,13 +1235,14 @@ internal bool Compile(bool optimized) internal static void LogScriptBlockCreation(ScriptBlock scriptBlock, bool force) { - if (force || ShouldLogScriptBlockActivity("EnableScriptBlockLogging")) + ScriptBlockLogging logSetting = GetScriptBlockLoggingSetting(); + if (force || logSetting?.EnableScriptBlockLogging == true) { if (!scriptBlock.HasLogged || InternalTestHooks.ForceScriptBlockLogging) { // If script block logging is explicitly disabled, or it's from a trusted // file or internal, skip logging. - if (ScriptBlockLoggingExplicitlyDisabled() || + if (logSetting?.EnableScriptBlockLogging == false || scriptBlock.ScriptBlockData.IsProductCode) { return; @@ -1284,18 +1286,17 @@ internal static void LogScriptBlockCreation(ScriptBlock scriptBlock, bool force) private static bool WriteScriptBlockToLog(ScriptBlock scriptBlock, int segment, int segments, string textToLog) { - // See if we need to encrypt the event log message. This info is all cached by Utils.GetGroupPolicySetting(), - // so we're not hitting the registry for every script block we compile. - Dictionary protectedEventLoggingSettings = Utils.GetGroupPolicySetting( - "Software\\Policies\\Microsoft\\Windows\\EventLog", "ProtectedEventLogging", Utils.RegLocalMachine); - if (protectedEventLoggingSettings != null) + // See if we need to encrypt the event log message. This info is all cached by Utils.GetPolicySetting(), + // so we're not hitting the configuration file for every script block we compile. + ProtectedEventLogging logSetting = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + if (logSetting != null) { lock (s_syncObject) { // Populates the encryptionRecipients list from the Group Policy, if possible. If not possible, // does all appropriate logging and encryptionRecipients is 'null'. 'CouldLog' being false // implies the engine wasn't ready for logging yet. - bool couldLog = GetAndValidateEncryptionRecipients(scriptBlock); + bool couldLog = GetAndValidateEncryptionRecipients(scriptBlock, logSetting); if (!couldLog) { return false; @@ -1345,109 +1346,92 @@ private static bool WriteScriptBlockToLog(ScriptBlock scriptBlock, int segment, return true; } - private static bool GetAndValidateEncryptionRecipients(ScriptBlock scriptBlock) + private static bool GetAndValidateEncryptionRecipients(ScriptBlock scriptBlock, ProtectedEventLogging logSetting) { - Dictionary protectedEventLoggingSettings = Utils.GetGroupPolicySetting( - "Software\\Policies\\Microsoft\\Windows\\EventLog", "ProtectedEventLogging", Utils.RegLocalMachine); - // See if protected event logging is enabled - object enableProtectedEventLogging = null; - if (protectedEventLoggingSettings.TryGetValue("EnableProtectedEventLogging", out enableProtectedEventLogging)) + if (logSetting.EnableProtectedEventLogging == true) { - if (String.Equals("1", enableProtectedEventLogging.ToString(), StringComparison.OrdinalIgnoreCase)) + // Get the encryption certificate + if (logSetting.EncryptionCertificate != null) { - // Get the encryption certificate - object encryptionCertificate = null; - if (protectedEventLoggingSettings.TryGetValue("EncryptionCertificate", out encryptionCertificate)) - { - ErrorRecord error = null; - ExecutionContext executionContext = LocalPipeline.GetExecutionContextFromTLS(); - SessionState sessionState = null; + ErrorRecord error = null; + ExecutionContext executionContext = LocalPipeline.GetExecutionContextFromTLS(); + SessionState sessionState = null; - // Use the session state from the current pipeline, if it exists. - if (executionContext != null) - { - sessionState = executionContext.SessionState; - } + // Use the session state from the current pipeline, if it exists. + if (executionContext != null) + { + sessionState = executionContext.SessionState; + } - // If the engine hasn't started up yet, then we're just compiling script - // blocks. We'll have to log them when they are used and we have an engine - // to work with. - if (sessionState == null) - { - return false; - } + // If the engine hasn't started up yet, then we're just compiling script + // blocks. We'll have to log them when they are used and we have an engine + // to work with. + if (sessionState == null) + { + return false; + } - string[] encryptionCertificateContent = encryptionCertificate as string[]; - string fullCertificateContent = null; - if (encryptionCertificateContent != null) - { - fullCertificateContent = String.Join(Environment.NewLine, encryptionCertificateContent); - } - else - { - fullCertificateContent = encryptionCertificate as string; - } + string fullCertificateContent = String.Join(Environment.NewLine, logSetting.EncryptionCertificate); - // If the certificate has changed, drop all of our cached information - ResetCertificateCacheIfNeeded(fullCertificateContent); + // If the certificate has changed, drop all of our cached information + ResetCertificateCacheIfNeeded(fullCertificateContent); - // If we have valid recipients, no need for further analysis. - if (s_encryptionRecipients != null) - { - return true; - } + // If we have valid recipients, no need for further analysis. + if (s_encryptionRecipients != null) + { + return true; + } - // If we've already verified all of the properties of the cert we care about (even if it - // didn't result in a valid cert), return now. - if (s_hasProcessedCertificate) - { - return true; - } + // If we've already verified all of the properties of the cert we care about (even if it + // didn't result in a valid cert), return now. + if (s_hasProcessedCertificate) + { + return true; + } - // Resolve the certificate to a recipient - CmsMessageRecipient recipient = new CmsMessageRecipient(fullCertificateContent); - recipient.Resolve(sessionState, ResolutionPurpose.Encryption, out error); - s_hasProcessedCertificate = true; + // Resolve the certificate to a recipient + CmsMessageRecipient recipient = new CmsMessageRecipient(fullCertificateContent); + recipient.Resolve(sessionState, ResolutionPurpose.Encryption, out error); + s_hasProcessedCertificate = true; - // If there's an error that we haven't already reported, report it in the event log. - // We only do this once, as the error will always be the same for a given certificate. - if (error != null) - { - // If we got an error resolving the encryption certificate, log a warning and continue - // logging the (unencrypted) message anyways. Logging trumps protected logging - - // being able to detect that an attacker has compromised a box outweighs the danger of the - // attacker seeing potentially sensitive data. Because if they aren't detected, then - // they can just wait on the compromised box and see the sensitive data eventually anyways. - string errorMessage = StringUtil.Format(SecuritySupportStrings.CouldNotUseCertificate, error.ToString()); - PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, - 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); + // If there's an error that we haven't already reported, report it in the event log. + // We only do this once, as the error will always be the same for a given certificate. + if (error != null) + { + // If we got an error resolving the encryption certificate, log a warning and continue + // logging the (unencrypted) message anyways. Logging trumps protected logging - + // being able to detect that an attacker has compromised a box outweighs the danger of the + // attacker seeing potentially sensitive data. Because if they aren't detected, then + // they can just wait on the compromised box and see the sensitive data eventually anyways. + string errorMessage = StringUtil.Format(SecuritySupportStrings.CouldNotUseCertificate, error.ToString()); + PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, + 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); - return true; - } + return true; + } - // Now, save the certificate. We'll be comfortable using this one from now on. - s_encryptionRecipients = new CmsMessageRecipient[] { recipient }; + // Now, save the certificate. We'll be comfortable using this one from now on. + s_encryptionRecipients = new CmsMessageRecipient[] { recipient }; - // Check if the certificate has a private key, and report a warning if so. - // We only do this once, as the error will always be the same for a given certificate. - foreach (X509Certificate2 validationCertificate in recipient.Certificates) + // Check if the certificate has a private key, and report a warning if so. + // We only do this once, as the error will always be the same for a given certificate. + foreach (X509Certificate2 validationCertificate in recipient.Certificates) + { + if (validationCertificate.HasPrivateKey) { - if (validationCertificate.HasPrivateKey) + // Only log the first line of what we pulled from the configuration. If this is a path, this will have enough information. + // If this is the actual certificate, only include the first line of the certificate content so that we're not permanently keeping the private + // key in the log. + string certificateForLog = fullCertificateContent; + if (logSetting.EncryptionCertificate.Length > 1) { - // Only log the first line of what we pulled from the registry. If this is a path, this will have enough information. - // If this is the actual certificate, only include the first line of the certificate content so that we're not permanently keeping the private - // key in the log. - string certificateForLog = fullCertificateContent; - if ((encryptionCertificateContent != null) && (encryptionCertificateContent.Length > 1)) - { - certificateForLog = encryptionCertificateContent[1]; - } - - string errorMessage = StringUtil.Format(SecuritySupportStrings.CertificateContainsPrivateKey, certificateForLog); - PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, - 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); + certificateForLog = logSetting.EncryptionCertificate[1]; } + + string errorMessage = StringUtil.Format(SecuritySupportStrings.CertificateContainsPrivateKey, certificateForLog); + PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, + 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); } } } @@ -1472,23 +1456,9 @@ private static void ResetCertificateCacheIfNeeded(string certificate) } } - private static bool ShouldLogScriptBlockActivity(string activity) + private static ScriptBlockLogging GetScriptBlockLoggingSetting() { - // If script block logging is turned on, log this one. - Dictionary groupPolicySettings = Utils.GetGroupPolicySetting("ScriptBlockLogging", Utils.RegLocalMachineThenCurrentUser); - if (groupPolicySettings != null) - { - object logScriptBlockExecution = null; - if (groupPolicySettings.TryGetValue(activity, out logScriptBlockExecution)) - { - if (String.Equals("1", logScriptBlockExecution.ToString(), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - - return false; + return Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); } // Quick check for script blocks that may have suspicious content. If this @@ -1808,27 +1778,6 @@ char ToLower(char c) #endif } - internal static bool ScriptBlockLoggingExplicitlyDisabled() - { - // Verify they haven't explicitly turned off script block logging. - Dictionary groupPolicySettings = Utils.GetGroupPolicySetting("ScriptBlockLogging", Utils.RegLocalMachineThenCurrentUser); - if (groupPolicySettings != null) - { - object logScriptBlockExecution; - if (groupPolicySettings.TryGetValue("EnableScriptBlockLogging", out logScriptBlockExecution)) - { - // If it is configured and explicitly disabled, return true. - // (Don't even auto-log ones with suspicious content) - if (String.Equals("0", logScriptBlockExecution.ToString(), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - - return false; - } - internal static void LogScriptBlockStart(ScriptBlock scriptBlock, Guid runspaceId) { // When invoking, log the creation of the script block if it has suspicious @@ -1843,7 +1792,7 @@ internal static void LogScriptBlockStart(ScriptBlock scriptBlock, Guid runspaceI // properly analyzed the script block's security. LogScriptBlockCreation(scriptBlock, forceLogCreation); - if (ShouldLogScriptBlockActivity("EnableScriptBlockInvocationLogging")) + if (GetScriptBlockLoggingSetting()?.EnableScriptBlockInvocationLogging == true) { PSEtwLog.LogOperationalVerbose(PSEventId.ScriptBlock_Invoke_Start_Detail, PSOpcode.Create, PSTask.CommandStart, PSKeyword.UseAlwaysAnalytic, scriptBlock.Id.ToString(), runspaceId.ToString()); @@ -1852,7 +1801,7 @@ internal static void LogScriptBlockStart(ScriptBlock scriptBlock, Guid runspaceI internal static void LogScriptBlockEnd(ScriptBlock scriptBlock, Guid runspaceId) { - if (ShouldLogScriptBlockActivity("EnableScriptBlockInvocationLogging")) + if (GetScriptBlockLoggingSetting()?.EnableScriptBlockInvocationLogging == true) { PSEtwLog.LogOperationalVerbose(PSEventId.ScriptBlock_Invoke_Complete_Detail, PSOpcode.Create, PSTask.CommandStop, PSKeyword.UseAlwaysAnalytic, scriptBlock.Id.ToString(), runspaceId.ToString()); diff --git a/src/System.Management.Automation/help/UpdatableHelpSystem.cs b/src/System.Management.Automation/help/UpdatableHelpSystem.cs index 6c1fc5f75a5..cadd34fa5e6 100644 --- a/src/System.Management.Automation/help/UpdatableHelpSystem.cs +++ b/src/System.Management.Automation/help/UpdatableHelpSystem.cs @@ -6,6 +6,7 @@ using System.Collections.ObjectModel; using System.Net; using System.ComponentModel; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Diagnostics; using System.Threading; @@ -1665,14 +1666,9 @@ internal static string GetFilePath(string path) /// internal string GetDefaultSourcePath() { - try - { - return ConfigPropertyAccessor.Instance.GetDefaultSourcePath(); - } - catch (SecurityException) - { - return null; - } + var updatableHelpSetting = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + string defaultSourcePath = updatableHelpSetting?.DefaultSourcePath; + return String.IsNullOrEmpty(defaultSourcePath) ? null : defaultSourcePath; } /// @@ -1682,7 +1678,7 @@ internal static void SetDisablePromptToUpdateHelp() { try { - ConfigPropertyAccessor.Instance.SetDisablePromptToUpdateHelp(true); + PowerShellConfig.Instance.SetDisablePromptToUpdateHelp(true); } catch (UnauthorizedAccessException) { @@ -1712,7 +1708,7 @@ internal static bool ShouldPromptToUpdateHelp() return false; } - return ConfigPropertyAccessor.Instance.GetDisablePromptToUpdateHelp(); + return PowerShellConfig.Instance.GetDisablePromptToUpdateHelp(); } catch (SecurityException) { diff --git a/src/System.Management.Automation/logging/MshLog.cs b/src/System.Management.Automation/logging/MshLog.cs index 5e9c554cb52..354da12f6b6 100644 --- a/src/System.Management.Automation/logging/MshLog.cs +++ b/src/System.Management.Automation/logging/MshLog.cs @@ -134,54 +134,23 @@ private static IEnumerable GetLogProvider(LogContext logContext) /// private static Collection CreateLogProvider(string shellId) { -#if V2 - try - { - Assembly crimsonAssembly = Assembly.Load(_crimsonLogProviderAssemblyName); - - if (crimsonAssembly != null) - { - LogProvider logProvider = (LogProvider)crimsonAssembly.CreateInstance(_crimsonLogProviderTypeName, - false, // don't ignore case - BindingFlags.CreateInstance, - null, // use default binder - null, - null, // use current culture - null // no special activation attributes - ); - - System.Diagnostics.Debug.Assert(logProvider != null); - return logProvider; - } - } - catch (FileNotFoundException e) - { - _trace.TraceException(e); - } - catch (BadImageFormatException e) - { - _trace.TraceException(e); - } - catch (SecurityException e) - { - _trace.TraceException(e); - } - catch (TargetInvocationException e) - { - _trace.TraceException(e); - } -#endif Collection providers = new Collection(); // Porting note: Linux does not support ETW -#if !UNIX + try { #if !CORECLR //TODO:CORECLR EventLogLogProvider not handled yet LogProvider eventLogLogProvider = new EventLogLogProvider(shellId); providers.Add(eventLogLogProvider); #endif + +#if UNIX + LogProvider sysLogProvider = new PSSysLogProvider(); + providers.Add(sysLogProvider); +#else LogProvider etwLogProvider = new PSEtwLogProvider(); providers.Add(etwLogProvider); +#endif return providers; } @@ -198,7 +167,7 @@ private static Collection CreateLogProvider(string shellId) // when running as non-admin user. In that case, we will default // to dummy log. } -#endif + providers.Add(new DummyLogProvider()); return providers; } diff --git a/src/System.Management.Automation/PowerShellProperties.json b/src/System.Management.Automation/powershell.config.json similarity index 100% rename from src/System.Management.Automation/PowerShellProperties.json rename to src/System.Management.Automation/powershell.config.json diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index bf0e87c867d..625590e74df 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -11,6 +11,7 @@ using Microsoft.PowerShell; using Microsoft.PowerShell.Commands; using Microsoft.Win32; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -141,7 +142,6 @@ internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPol throw new PlatformNotSupportedException(); #else string executionPolicy = "Restricted"; - string preferenceKey = Utils.GetRegistryConfigurationPath(shellId); switch (policy) { @@ -174,12 +174,11 @@ internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPol // They want to remove it if (policy == ExecutionPolicy.Undefined) { - ConfigPropertyAccessor.Instance.RemoveExecutionPolicy(ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId); - CleanKeyParents(Registry.CurrentUser, preferenceKey); + PowerShellConfig.Instance.RemoveExecutionPolicy(ConfigScope.CurrentUser, shellId); } else { - ConfigPropertyAccessor.Instance.SetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId, executionPolicy); + PowerShellConfig.Instance.SetExecutionPolicy(ConfigScope.CurrentUser, shellId, executionPolicy); } break; } @@ -189,12 +188,11 @@ internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPol // They want to remove it if (policy == ExecutionPolicy.Undefined) { - ConfigPropertyAccessor.Instance.RemoveExecutionPolicy(ConfigPropertyAccessor.PropertyScope.SystemWide, shellId); - CleanKeyParents(Registry.LocalMachine, preferenceKey); + PowerShellConfig.Instance.RemoveExecutionPolicy(ConfigScope.SystemWide, shellId); } else { - ConfigPropertyAccessor.Instance.SetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.SystemWide, shellId, executionPolicy); + PowerShellConfig.Instance.SetExecutionPolicy(ConfigScope.SystemWide, shellId, executionPolicy); } break; } @@ -202,50 +200,6 @@ internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPol #endif } - // Clean up the parents of a registry key as long as they - // contain at most a single child - private static void CleanKeyParents(RegistryKey baseKey, string keyPath) - { -#if CORECLR - if (!Platform.IsInbox) - return; -#endif - using (RegistryKey key = baseKey.OpenSubKey(keyPath, true)) - { - // Verify the child key has no children - if ((key == null) || ((key.ValueCount == 0) && (key.SubKeyCount == 0))) - { - // If so, split the key into its path elements - string[] parentKeys = keyPath.Split(Utils.Separators.Backslash); - - // Verify we aren't traveling into SOFTWARE\Microsoft - if (parentKeys.Length <= 2) - return; - - string currentItem = parentKeys[parentKeys.Length - 1]; - - // Figure out the parent key name - string parentKeyPath = keyPath.Remove(keyPath.Length - currentItem.Length - 1); - - // Open the parent, and clear the child key - if (key != null) - { - using (RegistryKey parentKey = baseKey.OpenSubKey(parentKeyPath, true)) - { - parentKey.DeleteSubKey(currentItem, true); - } - } - - // Now, process the parent key - CleanKeyParents(baseKey, parentKeyPath); - } - else - { - return; - } - } - } - internal static ExecutionPolicy GetExecutionPolicy(string shellId) { foreach (ExecutionPolicyScope scope in ExecutionPolicyScopePreferences) @@ -556,41 +510,31 @@ internal static SaferPolicy GetSaferPolicy(string path, SafeHandle handle) /// NULL if it is not defined at this level private static string GetGroupPolicyValue(string shellId, ExecutionPolicyScope scope) { - RegistryKey[] scopeKey = null; + ConfigScope[] scopeKey = null; switch (scope) { case ExecutionPolicyScope.MachinePolicy: - { - scopeKey = Utils.RegLocalMachine; - }; break; + scopeKey = Utils.SystemWideOnlyConfig; + break; case ExecutionPolicyScope.UserPolicy: - { - scopeKey = Utils.RegCurrentUser; - }; break; - } - - Dictionary groupPolicySettings = Utils.GetGroupPolicySetting(".", scopeKey); - if (groupPolicySettings == null) - { - return null; + scopeKey = Utils.CurrentUserOnlyConfig; + break; } - Object enableScriptsValue = null; - if (groupPolicySettings.TryGetValue("EnableScripts", out enableScriptsValue)) + var scriptExecutionSetting = Utils.GetPolicySetting(scopeKey); + if (scriptExecutionSetting != null) { - if (String.Equals(enableScriptsValue.ToString(), "0", StringComparison.OrdinalIgnoreCase)) + if (scriptExecutionSetting.EnableScripts == false) { + // Script execution is explicitly disabled return "Restricted"; } - else if (String.Equals(enableScriptsValue.ToString(), "1", StringComparison.OrdinalIgnoreCase)) + else if (scriptExecutionSetting.EnableScripts == true) { - Object executionPolicyValue = null; - if (groupPolicySettings.TryGetValue("ExecutionPolicy", out executionPolicyValue)) - { - return executionPolicyValue.ToString(); - } + // Script execution is explicitly enabled + return scriptExecutionSetting.ExecutionPolicy; } } @@ -608,11 +552,11 @@ private static string GetLocalPreferenceValue(string shellId, ExecutionPolicySco { // 1: Look up the current-user preference case ExecutionPolicyScope.CurrentUser: - return ConfigPropertyAccessor.Instance.GetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId); + return PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.CurrentUser, shellId); // 2: Look up the system-wide preference case ExecutionPolicyScope.LocalMachine: - return ConfigPropertyAccessor.Instance.GetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.SystemWide, shellId); + return PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.SystemWide, shellId); } return null; diff --git a/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs b/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs index 3f316b1e55a..49d5c8c2f29 100755 --- a/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs @@ -3,6 +3,7 @@ // Copyright (C) Microsoft. All rights reserved. // using System.Diagnostics.Eventing; +using System.Management.Automation.Configuration; using System.Management.Automation.Internal; using System.Text; using System.Collections.Generic; @@ -24,10 +25,10 @@ internal class PSSysLogProvider : LogProvider /// static PSSysLogProvider() { - s_provider = new SysLogProvider(ConfigPropertyAccessor.Instance.GetSysLogIdentity(), - ConfigPropertyAccessor.Instance.GetLogLevel(), - ConfigPropertyAccessor.Instance.GetLogKeywords(), - ConfigPropertyAccessor.Instance.GetLogChannels()); + s_provider = new SysLogProvider(PowerShellConfig.Instance.GetSysLogIdentity(), + PowerShellConfig.Instance.GetLogLevel(), + PowerShellConfig.Instance.GetLogKeywords(), + PowerShellConfig.Instance.GetLogChannels()); } /// diff --git a/src/System.Management.Automation/utils/tracing/SysLogProvider.cs b/src/System.Management.Automation/utils/tracing/SysLogProvider.cs index 03d5d17e9eb..614bdbdc9ec 100755 --- a/src/System.Management.Automation/utils/tracing/SysLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/SysLogProvider.cs @@ -88,7 +88,7 @@ internal class SysLogProvider /// Initializes a new instance of this class. /// /// The log identity name used to identify the application in syslog. - /// The trace lavel to enable. + /// The trace level to enable. /// The keywords to enable. /// The output channels to enable. public SysLogProvider(string applicationId, PSLevel level, PSKeyword keywords, PSChannel channels) @@ -313,6 +313,13 @@ public void SetActivity(Guid activity) /// The payload for the log message. public void Log(PSEventId eventId, PSChannel channel, PSTask task, PSOpcode opcode, PSLevel level, PSKeyword keyword, params object[] args) { + if (keyword == PSKeyword.UseAlwaysAnalytic) + { + // Use the 'DefaultKeywords' to work around the default keyword filter. + // Note that the PSKeyword argument is not really used in writing SysLog. + keyword = PSSysLogProvider.DefaultKeywords; + } + if (ShouldLog(level, keyword, channel)) { int threadId = Thread.CurrentThread.ManagedThreadId; diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj index f6c2d9c5c2d..3774aa40dc1 100644 --- a/src/powershell-win-core/powershell-win-core.csproj +++ b/src/powershell-win-core/powershell-win-core.csproj @@ -10,8 +10,8 @@ - - PowerShellProperties.json + + powershell.config.json PreserveNewest diff --git a/test/csharp/test_Binders.cs b/test/csharp/test_Binders.cs index e73d6b44ca4..a6baa1c179d 100644 --- a/test/csharp/test_Binders.cs +++ b/test/csharp/test_Binders.cs @@ -2,7 +2,7 @@ using System; using System.Management.Automation.Language; -namespace PSTests +namespace PSTests.Parallel { public static class PSEnumerableBinderTests { diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index 11a744b4046..f1682e60012 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Management.Automation; -namespace PSTests +namespace PSTests.Parallel { public static class PlatformTests { diff --git a/test/csharp/test_ExtensionMethods.cs b/test/csharp/test_ExtensionMethods.cs index 0b2273fb3d2..04fd1259eb0 100644 --- a/test/csharp/test_ExtensionMethods.cs +++ b/test/csharp/test_ExtensionMethods.cs @@ -2,7 +2,7 @@ using System; using System.Management.Automation; -namespace PSTests +namespace PSTests.Parallel { public static class PSTypeExtensionsTests { diff --git a/test/csharp/test_FileSystemProvider.cs b/test/csharp/test_FileSystemProvider.cs index 76d52137478..340c648356b 100644 --- a/test/csharp/test_FileSystemProvider.cs +++ b/test/csharp/test_FileSystemProvider.cs @@ -15,7 +15,7 @@ using Microsoft.PowerShell.Commands; using System.Reflection; -namespace PSTests +namespace PSTests.Parallel { public class FileSystemProviderTests: IDisposable { diff --git a/test/csharp/test_MshSnapinInfo.cs b/test/csharp/test_MshSnapinInfo.cs index 454a4ec0a60..ffc5bf825de 100644 --- a/test/csharp/test_MshSnapinInfo.cs +++ b/test/csharp/test_MshSnapinInfo.cs @@ -2,7 +2,7 @@ using System; using System.Management.Automation; -namespace PSTests +namespace PSTests.Parallel { // Not static because a test requires non-const variables public class MshSnapinInfoTests diff --git a/test/csharp/test_PSConfiguration.cs b/test/csharp/test_PSConfiguration.cs new file mode 100644 index 00000000000..ed0255950fc --- /dev/null +++ b/test/csharp/test_PSConfiguration.cs @@ -0,0 +1,900 @@ +using Xunit; +using System; +using System.IO; +using System.Management.Automation; +using System.Management.Automation.Configuration; +using System.Management.Automation.Internal; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace PSTests.Sequential +{ + public class PowerShellPolicyFixture : IDisposable + { + private const string configFileName = "powershell.config.json"; + private readonly string systemWideConfigFile; + private readonly string currentUserConfigFile; + + private readonly string systemWideConfigBackupFile; + private readonly string currentUserConfigBackupFile; + + private readonly string systemWideConfigDirectory; + private readonly string currentUserConfigDirectory; + + private readonly JsonSerializer serializer; + + private readonly PowerShellPolicies systemWidePolicies; + private readonly PowerShellPolicies currentUserPolicies; + + private readonly bool originalTestHookValue; + + public PowerShellPolicyFixture() + { + systemWideConfigDirectory = Utils.DefaultPowerShellAppBase; + currentUserConfigDirectory = Utils.GetUserConfigurationDirectory(); + + if (!Directory.Exists(currentUserConfigDirectory)) + { + // Create the CurrentUser config directory if it doesn't exist + Directory.CreateDirectory(currentUserConfigDirectory); + } + + systemWideConfigFile = Path.Combine(systemWideConfigDirectory, configFileName); + currentUserConfigFile = Path.Combine(currentUserConfigDirectory, configFileName); + + if (File.Exists(systemWideConfigFile)) + { + systemWideConfigBackupFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + File.Move(systemWideConfigFile, systemWideConfigBackupFile); + } + if (File.Exists(currentUserConfigFile)) + { + currentUserConfigBackupFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + File.Move(currentUserConfigFile, currentUserConfigBackupFile); + } + + var settings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.None, + MaxDepth = 10, + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore + }; + serializer = JsonSerializer.Create(settings); + + systemWidePolicies = new PowerShellPolicies() + { + ScriptExecution = new ScriptExecution() { ExecutionPolicy = "RemoteSigned", EnableScripts = true }, + ScriptBlockLogging = new ScriptBlockLogging() { EnableScriptBlockInvocationLogging = true, EnableScriptBlockLogging = false }, + ModuleLogging = new ModuleLogging() { EnableModuleLogging = false, ModuleNames = new string[] { "PSReadline", "PowerShellGet" } }, + ProtectedEventLogging = new ProtectedEventLogging() { EnableProtectedEventLogging = false, EncryptionCertificate = new string[] { "Joe" } }, + Transcription = new Transcription() { EnableInvocationHeader = true, EnableTranscripting = true, OutputDirectory = "c:\tmp" }, + UpdatableHelp = new UpdatableHelp() { DefaultSourcePath = "f:\temp" }, + ConsoleSessionConfiguration = new ConsoleSessionConfiguration() { EnableConsoleSessionConfiguration = true, ConsoleSessionConfigurationName = "name" } + }; + + currentUserPolicies = new PowerShellPolicies() + { + ScriptExecution = new ScriptExecution() { ExecutionPolicy = "RemoteSigned" }, + ScriptBlockLogging = new ScriptBlockLogging() { EnableScriptBlockLogging = false }, + ModuleLogging = new ModuleLogging() { EnableModuleLogging = false }, + ProtectedEventLogging = new ProtectedEventLogging() { EncryptionCertificate = new string[] { "Joe" } } + }; + + // Set the test hook to disable policy caching + originalTestHookValue = InternalTestHooks.BypassGroupPolicyCaching; + InternalTestHooks.BypassGroupPolicyCaching = true; + } + + public void Dispose() + { + CleanupConfigFiles(); + if (systemWideConfigBackupFile != null) + { + File.Move(systemWideConfigBackupFile, systemWideConfigFile); + } + + if (currentUserConfigBackupFile != null) + { + File.Move(currentUserConfigBackupFile, currentUserConfigFile); + } + InternalTestHooks.BypassGroupPolicyCaching = originalTestHookValue; + } + + internal PowerShellPolicies SystemWidePolicies + { + get { return systemWidePolicies; } + } + + internal PowerShellPolicies CurrentUserPolicies + { + get { return currentUserPolicies; } + } + + #region Compare_Policy_Settings + + internal void CompareScriptExecution(ScriptExecution a, ScriptExecution b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableScripts, b.EnableScripts); + Assert.Equal(a.ExecutionPolicy, b.ExecutionPolicy); + } + } + + internal void CompareScriptBlockLogging(ScriptBlockLogging a, ScriptBlockLogging b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableScriptBlockInvocationLogging, b.EnableScriptBlockInvocationLogging); + Assert.Equal(a.EnableScriptBlockLogging, b.EnableScriptBlockLogging); + } + } + + internal void CompareModuleLogging(ModuleLogging a, ModuleLogging b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableModuleLogging, b.EnableModuleLogging); + if (a.ModuleNames == null) + { + Assert.Null(b.ModuleNames); + } + else + { + Assert.Equal(a.ModuleNames.Length, b.ModuleNames.Length); + for (int i = 0; i < a.ModuleNames.Length; i++) + { + Assert.Equal(a.ModuleNames[i], b.ModuleNames[i]); + } + } + } + } + + internal void CompareProtectedEventLogging(ProtectedEventLogging a, ProtectedEventLogging b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableProtectedEventLogging, b.EnableProtectedEventLogging); + if (a.EncryptionCertificate == null) + { + Assert.Null(b.EncryptionCertificate); + } + else + { + Assert.Equal(a.EncryptionCertificate.Length, b.EncryptionCertificate.Length); + for (int i = 0; i < a.EncryptionCertificate.Length; i++) + { + Assert.Equal(a.EncryptionCertificate[i], b.EncryptionCertificate[i]); + } + } + } + } + + internal void CompareTranscription(Transcription a, Transcription b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableTranscripting, b.EnableTranscripting); + Assert.Equal(a.EnableInvocationHeader, b.EnableInvocationHeader); + Assert.Equal(a.OutputDirectory, b.OutputDirectory); + } + } + + internal void CompareUpdatableHelp(UpdatableHelp a, UpdatableHelp b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.DefaultSourcePath, b.DefaultSourcePath); + } + } + + internal void CompareConsoleSessionConfiguration(ConsoleSessionConfiguration a, ConsoleSessionConfiguration b) + { + if (a == null) + { + Assert.Null(b); + } + else + { + Assert.Equal(a.EnableConsoleSessionConfiguration, b.EnableConsoleSessionConfiguration); + Assert.Equal(a.ConsoleSessionConfigurationName, b.ConsoleSessionConfigurationName); + } + } + + internal void CompareTwoPolicies(PowerShellPolicies a, PowerShellPolicies b) + { + // Compare 'ScriptExecution' settings + CompareScriptExecution(a.ScriptExecution, b.ScriptExecution); + + // Compare 'ScriptBlockLogging' settings + CompareScriptBlockLogging(a.ScriptBlockLogging, b.ScriptBlockLogging); + + // Compare 'ModuleLogging' settings + CompareModuleLogging(a.ModuleLogging, b.ModuleLogging); + + // Compare 'ProtectedEventLogging' settings + CompareProtectedEventLogging(a.ProtectedEventLogging, b.ProtectedEventLogging); + + // Compare 'Transcription' settings + CompareTranscription(a.Transcription, b.Transcription); + + // Compare 'UpdatableHelp' settings + CompareUpdatableHelp(a.UpdatableHelp, b.UpdatableHelp); + + // Compare 'ConsoleSessionConfiguration' settings + CompareConsoleSessionConfiguration(a.ConsoleSessionConfiguration, b.ConsoleSessionConfiguration); + } + + #endregion + + #region Configuration_File_Setup + + public void CleanupConfigFiles() + { + if (File.Exists(systemWideConfigFile)) + { + File.Delete(systemWideConfigFile); + } + if (File.Exists(currentUserConfigFile)) + { + File.Delete(currentUserConfigFile); + } + } + + public void SetupConfigFile1() + { + CleanupConfigFiles(); + + // System wide config file has all policy settings + var systemWideConfig = new { ConsolePrompting = true, PowerShellPolicies = systemWidePolicies }; + using (var streamWriter = new StreamWriter(systemWideConfigFile)) + { + serializer.Serialize(streamWriter, systemWideConfig); + } + + // Current user config file has partial policy settings + var currentUserConfig = new { DisablePromptToUpdateHelp = false, PowerShellPolicies = currentUserPolicies }; + using (var streamWriter = new StreamWriter(currentUserConfigFile)) + { + serializer.Serialize(streamWriter, currentUserConfig); + } + } + + public void SetupConfigFile2() + { + CleanupConfigFiles(); + + // System wide config file has all policy settings + var systemWideConfig = new { ConsolePrompting = true, PowerShellPolicies = systemWidePolicies }; + using (var streamWriter = new StreamWriter(systemWideConfigFile)) + { + serializer.Serialize(streamWriter, systemWideConfig); + } + + // Current user config file is empty + CreateEmptyFile(currentUserConfigFile); + } + + public void SetupConfigFile3() + { + CleanupConfigFiles(); + + // System wide config file is empty + CreateEmptyFile(systemWideConfigFile); + + // Current user config file has partial policy settings + var currentUserConfig = new { DisablePromptToUpdateHelp = false, PowerShellPolicies = currentUserPolicies }; + using (var streamWriter = new StreamWriter(currentUserConfigFile)) + { + serializer.Serialize(streamWriter, currentUserConfig); + } + } + + public void SetupConfigFile4() + { + CleanupConfigFiles(); + // System wide config file is empty + CreateEmptyFile(systemWideConfigFile); + // Current user config file is empty + CreateEmptyFile(currentUserConfigFile); + } + + private void CreateEmptyFile(string fileName) + { + File.Create(fileName).Dispose(); + } + + #endregion + } + + public class PowerShellPolicyTests : IClassFixture + { + PowerShellPolicyFixture fixture; + + public PowerShellPolicyTests(PowerShellPolicyFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + public void PowerShellConfig_GetPowerShellPolicies_BothConfigFilesNotEmpty() + { + fixture.SetupConfigFile1(); + var sysPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.SystemWide); + var userPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser); + + Assert.NotNull(sysPolicies); + Assert.NotNull(userPolicies); + + fixture.CompareTwoPolicies(sysPolicies, fixture.SystemWidePolicies); + fixture.CompareTwoPolicies(userPolicies, fixture.CurrentUserPolicies); + } + + [Fact] + public void PowerShellConfig_GetPowerShellPolicies_EmptyUserConfig() + { + fixture.SetupConfigFile2(); + var sysPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.SystemWide); + var userPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser); + + Assert.NotNull(sysPolicies); + Assert.Null(userPolicies); + + fixture.CompareTwoPolicies(sysPolicies, fixture.SystemWidePolicies); + } + + [Fact] + public void PowerShellConfig_GetPowerShellPolicies_EmptySystemConfig() + { + fixture.SetupConfigFile3(); + var sysPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.SystemWide); + var userPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser); + + Assert.Null(sysPolicies); + Assert.NotNull(userPolicies); + + fixture.CompareTwoPolicies(userPolicies, fixture.CurrentUserPolicies); + } + + [Fact] + public void PowerShellConfig_GetPowerShellPolicies_BothConfigFilesEmpty() + { + fixture.SetupConfigFile4(); + var sysPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.SystemWide); + var userPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser); + + Assert.Null(sysPolicies); + Assert.Null(userPolicies); + } + + [Fact] + public void PowerShellConfig_GetPowerShellPolicies_BothConfigFilesNotExist() + { + fixture.CleanupConfigFiles(); + var sysPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.SystemWide); + var userPolicies = PowerShellConfig.Instance.GetPowerShellPolicies(ConfigScope.CurrentUser); + + Assert.Null(sysPolicies); + Assert.Null(userPolicies); + } + + [Fact] + public void Utils_GetPolicySetting_BothConfigFilesNotEmpty() + { + fixture.SetupConfigFile1(); + + ScriptExecution scriptExecution; + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.SystemWidePolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.CurrentUserPolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.SystemWidePolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.CurrentUserPolicies.ScriptExecution); + + ScriptBlockLogging scriptBlockLogging; + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.SystemWidePolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.CurrentUserPolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.SystemWidePolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.CurrentUserPolicies.ScriptBlockLogging); + + ModuleLogging moduleLogging; + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.SystemWidePolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.CurrentUserPolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.SystemWidePolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.CurrentUserPolicies.ModuleLogging); + + ProtectedEventLogging protectedEventLogging; + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.SystemWidePolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.CurrentUserPolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.SystemWidePolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.CurrentUserPolicies.ProtectedEventLogging); + + // The CurrentUser config doesn't contain any settings for 'Transcription', 'UpdatableHelp' and 'ConsoleSessionConfiguration' + Transcription transcription; + transcription = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + UpdatableHelp updatableHelp; + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + ConsoleSessionConfiguration consoleSessionConfiguration; + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + } + + [Fact] + public void Utils_GetPolicySetting_EmptyUserConfig() + { + fixture.SetupConfigFile2(); + + // The CurrentUser config is empty + ScriptExecution scriptExecution; + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.SystemWidePolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.SystemWidePolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.SystemWidePolicies.ScriptExecution); + + ScriptBlockLogging scriptBlockLogging; + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.SystemWidePolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.SystemWidePolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.SystemWidePolicies.ScriptBlockLogging); + + ModuleLogging moduleLogging; + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.SystemWidePolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.SystemWidePolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.SystemWidePolicies.ModuleLogging); + + ProtectedEventLogging protectedEventLogging; + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.SystemWidePolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.SystemWidePolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.SystemWidePolicies.ProtectedEventLogging); + + Transcription transcription; + transcription = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareTranscription(transcription, fixture.SystemWidePolicies.Transcription); + + UpdatableHelp updatableHelp; + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareUpdatableHelp(updatableHelp, fixture.SystemWidePolicies.UpdatableHelp); + + ConsoleSessionConfiguration consoleSessionConfiguration; + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, fixture.SystemWidePolicies.ConsoleSessionConfiguration); + } + + [Fact] + public void Utils_GetPolicySetting_EmptySystemConfig() + { + fixture.SetupConfigFile3(); + + // The SystemWide config is empty + ScriptExecution scriptExecution; + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.CurrentUserPolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.CurrentUserPolicies.ScriptExecution); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptExecution(scriptExecution, fixture.CurrentUserPolicies.ScriptExecution); + + ScriptBlockLogging scriptBlockLogging; + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.CurrentUserPolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.CurrentUserPolicies.ScriptBlockLogging); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, fixture.CurrentUserPolicies.ScriptBlockLogging); + + ModuleLogging moduleLogging; + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.CurrentUserPolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.CurrentUserPolicies.ModuleLogging); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareModuleLogging(moduleLogging, fixture.CurrentUserPolicies.ModuleLogging); + + ProtectedEventLogging protectedEventLogging; + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.CurrentUserPolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.CurrentUserPolicies.ProtectedEventLogging); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, fixture.CurrentUserPolicies.ProtectedEventLogging); + + // The CurrentUser config doesn't contain any settings for 'Transcription', 'UpdatableHelp' and 'ConsoleSessionConfiguration' + Transcription transcription; + transcription = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareTranscription(transcription, null); + + UpdatableHelp updatableHelp; + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + ConsoleSessionConfiguration consoleSessionConfiguration; + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + } + + [Fact] + public void Utils_GetPolicySetting_BothConfigFilesEmpty() + { + fixture.SetupConfigFile4(); + + // Both config files are empty + ScriptExecution scriptExecution; + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + ScriptBlockLogging scriptBlockLogging; + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + ModuleLogging moduleLogging; + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + ProtectedEventLogging protectedEventLogging; + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + // The CurrentUser config doesn't contain any settings for 'Transcription', 'UpdatableHelp' and 'ConsoleSessionConfiguration' + Transcription transcription; + transcription = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareTranscription(transcription, null); + + UpdatableHelp updatableHelp; + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + ConsoleSessionConfiguration consoleSessionConfiguration; + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + } + + [Fact] + public void Utils_GetPolicySetting_BothConfigFilesNotExist() + { + fixture.CleanupConfigFiles(); + + // Both config files don't exist + ScriptExecution scriptExecution; + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + scriptExecution = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptExecution(scriptExecution, null); + + ScriptBlockLogging scriptBlockLogging; + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + scriptBlockLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareScriptBlockLogging(scriptBlockLogging, null); + + ModuleLogging moduleLogging; + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + moduleLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareModuleLogging(moduleLogging, null); + + ProtectedEventLogging protectedEventLogging; + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + protectedEventLogging = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareProtectedEventLogging(protectedEventLogging, null); + + // The CurrentUser config doesn't contain any settings for 'Transcription', 'UpdatableHelp' and 'ConsoleSessionConfiguration' + Transcription transcription; + transcription = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareTranscription(transcription, null); + + transcription = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareTranscription(transcription, null); + + UpdatableHelp updatableHelp; + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + updatableHelp = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareUpdatableHelp(updatableHelp, null); + + ConsoleSessionConfiguration consoleSessionConfiguration; + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserOnlyConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.SystemWideThenCurrentUserConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + + consoleSessionConfiguration = Utils.GetPolicySetting(Utils.CurrentUserThenSystemWideConfig); + fixture.CompareConsoleSessionConfiguration(consoleSessionConfiguration, null); + } + } +} \ No newline at end of file diff --git a/test/csharp/test_PSVersionInfo.cs b/test/csharp/test_PSVersionInfo.cs index ef980475ebf..80714e7d7e8 100644 --- a/test/csharp/test_PSVersionInfo.cs +++ b/test/csharp/test_PSVersionInfo.cs @@ -2,7 +2,7 @@ using System; using System.Management.Automation; -namespace PSTests +namespace PSTests.Parallel { public static class PSVersionInfoTests { diff --git a/test/csharp/test_Runspace.cs b/test/csharp/test_Runspace.cs index ee7877523ac..0407cbae6cc 100644 --- a/test/csharp/test_Runspace.cs +++ b/test/csharp/test_Runspace.cs @@ -3,7 +3,7 @@ using System.Management.Automation; using System.Management.Automation.Runspaces; -namespace PSTests +namespace PSTests.Parallel { // NOTE: do not call AddCommand("out-host") after invoking or MergeMyResults, // otherwise Invoke will not return any objects diff --git a/test/csharp/test_SecuritySupport.cs b/test/csharp/test_SecuritySupport.cs index aef3ac5ee8a..040c90dcc4d 100644 --- a/test/csharp/test_SecuritySupport.cs +++ b/test/csharp/test_SecuritySupport.cs @@ -2,7 +2,7 @@ using System; using System.Management.Automation; -namespace PSTests +namespace PSTests.Parallel { public static class SecuritySupportTests { diff --git a/test/csharp/test_SessionState.cs b/test/csharp/test_SessionState.cs index 990242f69f1..452bfc188ca 100644 --- a/test/csharp/test_SessionState.cs +++ b/test/csharp/test_SessionState.cs @@ -10,7 +10,7 @@ using System.Management.Automation.Runspaces; using Microsoft.PowerShell; -namespace PSTests +namespace PSTests.Parallel { public class SessionStateTests { diff --git a/test/csharp/test_Utils.cs b/test/csharp/test_Utils.cs index be1c5cfa492..ea9fc915065 100644 --- a/test/csharp/test_Utils.cs +++ b/test/csharp/test_Utils.cs @@ -3,7 +3,7 @@ using System.Management.Automation; using System.Reflection; -namespace PSTests +namespace PSTests.Parallel { public static class UtilsTests { diff --git a/test/powershell/engine/Basic/PropertyAccessor.Tests.ps1 b/test/powershell/engine/Basic/PropertyAccessor.Tests.ps1 index 1b009436072..7a718852f50 100644 --- a/test/powershell/engine/Basic/PropertyAccessor.Tests.ps1 +++ b/test/powershell/engine/Basic/PropertyAccessor.Tests.ps1 @@ -1,5 +1,5 @@ # -# Functional tests to verify basic conditions for IO to the PowerShellProperties.json files +# Functional tests to verify basic conditions for IO to the powershell.config.json files # The properties files are supported on non-Windows OSes, but the tests are specific to # Windows so that file IO can be verified using supported cmdlets. # @@ -14,18 +14,18 @@ try { $IsNotSkipped = ($IsWindows -and !$IsInbox) # Only execute for PowerShell Core on Windows $PSDefaultParameterValues["it:skip"] = !$IsNotSkipped - Describe "User-Specific PowerShellProperties.json Modifications" -Tags "CI" { + Describe "User-Specific powershell.config.json Modifications" -Tags "CI" { BeforeAll { if ($IsNotSkipped) { - # Discover the user-specific PowerShellProperties.json file + # Discover the user-specific powershell.config.json file $userSettingsDir = [System.IO.Path]::Combine($env:USERPROFILE, "Documents", $productName) - $userPropertiesFile = Join-Path $userSettingsDir "PowerShellProperties.json" + $userPropertiesFile = Join-Path $userSettingsDir "powershell.config.json" # Save the file for restoration after the tests are complete $backupPropertiesFile = "" if (Test-Path $userPropertiesFile) { - $backupPropertiesFile = Join-Path $userSettingsDir "ORIGINAL_PowerShellProperties.json" + $backupPropertiesFile = Join-Path $userSettingsDir "ORIGINAL_powershell.config.json" Copy-Item -Path $userPropertiesFile -Destination $backupPropertiesFile -Force -ErrorAction Continue } elseif (-not (Test-Path $userSettingsDir)) { @@ -49,12 +49,12 @@ try { if ($IsNotSkipped) { if (-not $backupPropertiesFile) { - # Remove PowerShellProperties.json if it did not exist before the tests + # Remove powershell.config.json if it did not exist before the tests Remove-Item -Path $userPropertiesFile -Force -ErrorAction SilentlyContinue } else { - # Restore the original PowerShellProperties.json file if it existed before the test pass. + # Restore the original powershell.config.json file if it existed before the test pass. Move-Item -Path $backupPropertiesFile -Destination $userPropertiesFile -Force -ErrorAction Continue } diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index 7e256db8111..7e683460189 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -325,7 +325,8 @@ function Invoke-AppVeyorTest Write-Host -Foreground Green 'Run CoreCLR tests' $testResultsNonAdminFile = "$pwd\TestsResultsNonAdmin.xml" $testResultsAdminFile = "$pwd\TestsResultsAdmin.xml" - $testResultsXUnitFile = "$pwd\TestResultsXUnit.xml" + $SequentialXUnitTestResultsFile = "$pwd\SequentialXUnitTestResults.xml" + $ParallelXUnitTestResultsFile = "$pwd\ParallelXUnitTestResults.xml" if(!(Test-Path "$env:CoreOutput\pwsh.exe")) { throw "CoreCLR pwsh.exe was not built" @@ -359,9 +360,10 @@ function Invoke-AppVeyorTest Write-Host -Foreground Green 'Upload CoreCLR Admin test results' Update-AppVeyorTestResults -resultsFile $testResultsAdminFile - Start-PSxUnit -TestResultsFile $testResultsXUnitFile + Start-PSxUnit -SequentialTestResultsFile $SequentialXUnitTestResultsFile -ParallelTestResultsFile $ParallelXUnitTestResultsFile Write-Host -ForegroundColor Green 'Uploading PSxUnit test results' - Update-AppVeyorTestResults -resultsFile $testResultsXUnitFile + Update-AppVeyorTestResults -resultsFile $SequentialXUnitTestResultsFile + Update-AppVeyorTestResults -resultsFile $ParallelXUnitTestResultsFile # # Fail the build, if tests failed @@ -372,7 +374,12 @@ function Invoke-AppVeyorTest Test-PSPesterResults -TestResultsFile $_ } - $testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile + @( + $SequentialXUnitTestResultsFile, + $ParallelXUnitTestResultsFile + ) | ForEach-Object { + Test-XUnitTestResults -TestResultsFile $_ + } Set-BuildVariable -Name TestPassed -Value True } diff --git a/tools/travis.ps1 b/tools/travis.ps1 index d94d3403bc1..8976c57ec60 100644 --- a/tools/travis.ps1 +++ b/tools/travis.ps1 @@ -240,10 +240,12 @@ elseif($Stage -eq 'Build') } try { - $testResultsXUnitFile = "$pwd/TestResultsXUnit.xml" - Start-PSxUnit -TestResultsFile $testResultsXUnitFile + $SequentialXUnitTestResultsFile = "$pwd/SequentialXUnitTestResults.xml" + $ParallelXUnitTestResultsFile = "$pwd/ParallelXUnitTestResults.xml" + + Start-PSxUnit -SequentialTestResultsFile $SequentialXUnitTestResultsFile -ParallelTestResultsFile $ParallelXUnitTestResultsFile # If there are failures, Test-XUnitTestResults throws - $testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile + $SequentialXUnitTestResultsFile, $ParallelXUnitTestResultsFile | ForEach-Object { Test-XUnitTestResults -TestResultsFile $_ } } catch { $result = "FAIL"