diff --git a/appveyor.yml b/appveyor.yml index f53c786d2..6caea8428 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,7 +40,7 @@ test_script: $env:CoreOutput = Split-Path -Parent (Get-PSOutput -Options (New-PSOptions -Publish)) Write-Host -Foreground Green 'Run CoreCLR tests' $testResultsFile = "$pwd\TestsResults.xml" - & ("$env:CoreOutput\powershell.exe") -noprofile -noninteractive -c "Invoke-Pester test/powershell -Tag 'CI' -ExcludeTag 'Slow' -OutputFormat NUnitXml -OutputFile $testResultsFile" + & ("$env:CoreOutput\powershell.exe") -noprofile -noninteractive -c "Set-ExecutionPolicy -Scope Process Unrestricted; Invoke-Pester test/powershell -Tag 'CI' -ExcludeTag 'Slow' -OutputFormat NUnitXml -OutputFile $testResultsFile" (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile)) # @@ -48,7 +48,7 @@ test_script: $env:FullOutput = Split-Path -Parent (Get-PSOutput -Options (New-PSOptions -FullCLR)) Write-Host -Foreground Green 'Run FullCLR tests' $testResultsFileFullCLR = "$pwd\TestsResults.FullCLR.xml" - Start-DevPowerShell -FullCLR -NoNewWindow -ArgumentList '-noprofile', '-noninteractive' -Command "Invoke-Pester test/fullCLR -ExcludeTag 'Slow' -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR" + Start-DevPowerShell -FullCLR -NoNewWindow -ArgumentList '-noprofile', '-noninteractive' -Command "Set-ExecutionPolicy -Scope Process Unrestricted; Invoke-Pester test/fullCLR -ExcludeTag 'Slow' -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR" (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFileFullCLR)) # # Fail the build, if tests failed diff --git a/build.psm1 b/build.psm1 index b345f7617..89db96c77 100644 --- a/build.psm1 +++ b/build.psm1 @@ -271,7 +271,7 @@ function Start-PSBuild { $nativeResourcesFolder = $_ Get-ChildItem $nativeResourcesFolder -Filter "*.mc" | % { $command = @" -cmd.exe /C cd /d "(Get-Location)" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch" "&" "$mcexe" -o -d -c -U $($_.FullName) -h "$nativeResourcesFolder" -r "$nativeResourcesFolder" +cmd.exe /C cd /d "(Get-Location)" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch" "&" mc.exe -o -d -c -U $($_.FullName) -h "$nativeResourcesFolder" -r "$nativeResourcesFolder" "@ log " Executing mc.exe Command: $command" Start-NativeExecution { Invoke-Expression -Command:$command } @@ -526,6 +526,7 @@ function Start-PSPester { [string[]]$Tag = "CI", [string]$Path = "$PSScriptRoot/test/powershell" ) + $tagString = "-outputFormat ${OutputFormat} -outputFile ${outputFile} " if ( ! $DisableExit ) { $tagString += " -EnableExit" } if ( $ExcludeTag -and ($ExcludeTag -ne "")) { $tagString += " -ExcludeTag @('" + (${ExcludeTag} -join "','") + "')" } @@ -537,7 +538,7 @@ function Start-PSPester { Write-Verbose "Import-Module '$moduleDir'; Invoke-Pester $tagString $Path" $powershellexe = get-psoutput - & $powershell -noprofile -c "Set-ExecutionPolicy Unrestricted; Import-Module '$moduleDir'; Invoke-Pester $tagString $Path" + & $powershell -noprofile -c "Set-ExecutionPolicy -Scope Process Unrestricted; Import-Module '$moduleDir'; Invoke-Pester $tagString $Path" if ($LASTEXITCODE -ne 0) { throw "$LASTEXITCODE Pester tests failed" } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs index 15c63ce7a..c5c88d67d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterfaceSecurity.cs @@ -170,12 +170,12 @@ namespace Microsoft.PowerShell // APIs private bool PromptUsingConsole() { -#if CORECLR // on Nano there is no other way to prompt except by using console +#if CORECLR + // on Nano there is no other way to prompt except by using console return true; #else - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); Exception exception = null; - bool promptUsingConsole = propertyAccessor.GetConsolePrompting(ref exception); + bool promptUsingConsole = ConfigPropertyAccessor.Instance.GetConsolePrompting(ref exception); if (null != exception) { s_tracer.TraceError("Could not read CredUI registry key: " + exception.Message); diff --git a/src/System.Management.Automation/engine/PropertyAccessor.cs b/src/System.Management.Automation/engine/PropertyAccessor.cs index 10ca8c5fc..c83f737c8 100644 --- a/src/System.Management.Automation/engine/PropertyAccessor.cs +++ b/src/System.Management.Automation/engine/PropertyAccessor.cs @@ -9,20 +9,17 @@ using System.Globalization; using System.Threading; using System.Management.Automation; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using Microsoft.Win32; #if CORECLR // Some APIs are missing from System.Environment. We use System.Management.Automation.Environment as a proxy type: // - for missing APIs, System.Management.Automation.Environment has extension implementation. // - for existing APIs, System.Management.Automation.Environment redirect the call to System.Environment. using Environment = System.Management.Automation.Environment; -#else -//using Microsoft.Win32; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; #endif -using Microsoft.Win32; - namespace System.Management.Automation { @@ -30,8 +27,40 @@ namespace System.Management.Automation /// 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 PropertyAccessor + internal abstract class ConfigPropertyAccessor { + #region Statics + /// + /// Static constructor to instantiate an instance + /// + static ConfigPropertyAccessor() + { +#if CORECLR + // TODO: Update this for #1184 + //if (Platform.IsInbox()) + //{ + // Instance = new RegistryAccessor(); + //} + //else + //{ + // Instance = new JsonConfigFileAccessor(); + //} + // Remove this following line: + Instance = new JsonConfigFileAccessor(); +#else + Instance = new RegistryAccessor(); +#endif + } + /// + /// The instance of the ConfigPropertyAccessor to use to iteract 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. @@ -53,6 +82,10 @@ namespace System.Management.Automation VersionSpecific = 2 } + #endregion // Enums + + #region Interface Methods + /// /// Existing Key = HKLM:\System\CurrentControlSet\Control\Session Manager\Environment /// Proposed value = %ProgramFiles%\PowerShell\Modules by default @@ -69,18 +102,9 @@ namespace System.Management.Automation /// Where it should check for the value. /// The shell associated with this policy. Typically, it is "Microsoft.PowerShell" /// - internal abstract string GetMachineExecutionPolicy(PropertyScope scope, string shellId); - internal abstract void RemoveMachineExecutionPolicy(PropertyScope scope, string shellId); - internal abstract void SetMachineExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy); - - /// - /// Existing Key = HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds - /// Proposed value = Existing value, otherwise 10. - /// - /// Max stack size in MB. If not set, defaults to 10 MB. - internal abstract int GetPipeLineMaxStackSizeMb(int defaultValue); - - internal abstract void SetPipeLineMaxStackSizeMb(int maxStackSize); + 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 @@ -105,30 +129,12 @@ namespace System.Management.Automation /// internal abstract string GetDefaultSourcePath(); internal abstract void SetDefaultSourcePath(string defaultPath); + + #endregion // Interface Methods } - internal class PropertyAccessorFactory - { - /// - /// Template method to generate the appropriate accessor for a given environment. - /// - /// - internal static PropertyAccessor GetPropertyAccessor() - { - if (null == _activePropertyAccessor) - { #if CORECLR - // TODO: I must differentiate between inbox PS and side-by-side PS here eventually - _activePropertyAccessor = new JsonConfigFileAccessor(); -#else - _activePropertyAccessor = new RegistryAccessor(); -#endif - } - return _activePropertyAccessor; - } - - private static PropertyAccessor _activePropertyAccessor; - } + // TODO: JSON .Net should not be a required component for inbox PowerShell. We need to decide on the long term plan. /// /// JSON configuration file accessor @@ -136,24 +142,18 @@ namespace System.Management.Automation /// Reads from and writes to configuration files. The values stored were /// originally stored in the Windows registry. /// - internal class JsonConfigFileAccessor : PropertyAccessor + internal class JsonConfigFileAccessor : ConfigPropertyAccessor { private string psHomeConfigDirectory; private string appDataConfigDirectory; private const string configDirectoryName = "Configuration"; - private const string modulePathFileName = "PSModulePath.json"; - private const string execPolicyFileName = "ExecutionPolicy.json"; - private const string maxStackSizeFileName = "PipeLineMaxStackSizeMB.json"; - private const string consolePromptingFileName = "ConsolePrompting.json"; - private const string updateHelpPromptFileName = "UpdateHelpPrompt.json"; - private const string updatableHelpSourcePathFileName = "UpdatableHelpDefaultSourcePath.json"; + private const string configFileName = "PowerShellProperties.json"; internal JsonConfigFileAccessor() { // // Initialize (and create if necessary) the system-wide configuration directory // - // TODO: Use Utils.GetApplicationBase("Microsoft.PowerShell") instead? Assembly assembly = typeof(PSObject).GetTypeInfo().Assembly; psHomeConfigDirectory = Path.Combine(Path.GetDirectoryName(assembly.Location), configDirectoryName); @@ -174,25 +174,26 @@ namespace System.Management.Automation } /// - /// Note: This value is not writable, so it MUST be set during post-install configuration + /// Note: This value is not writable, so it MUST be set during post-install configuration. + /// Also, it will only be written to the $PSHOME configuration file (not the per-user file). /// /// - /// + /// Value if found, null otherwise. The behavior matches Environment.GetEnvironmentVariable(). internal override string GetModulePath(ModulePathTarget target) { + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); if (ModulePathTarget.CurrentUser == target) { // TODO: This feels unnecessary since it can be calculated based on the current user... - return ReadValueFromFile(modulePathFileName, "UserModulePath"); + return ReadValueFromFile(fileName, "UserModulePath"); } else if (ModulePathTarget.SharedCommon == target) { - return ReadValueFromFile(modulePathFileName, "SharedCommonModulePath"); + return ReadValueFromFile(fileName, "SharedCommonModulePath"); } else { - // TODO: Is there a better way to handle this? - throw new ArgumentException(); + return null; } } @@ -202,15 +203,15 @@ namespace System.Management.Automation /// /// Schema: /// { - /// "shell ID string" : "execution policy string" + /// "shell ID string","ExecutionPolicy" : "execution policy string" /// } /// - /// Note: If we switch to a single config file, then this will need to be nested + /// 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. /// /// 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 GetMachineExecutionPolicy(PropertyScope scope, string shellId) + internal override string GetExecutionPolicy(PropertyScope scope, string shellId) { string execPolicy = null; string scopeDirectory = psHomeConfigDirectory; @@ -221,9 +222,9 @@ namespace System.Management.Automation scopeDirectory = appDataConfigDirectory; } - string fileName = Path.Combine(scopeDirectory, execPolicyFileName); - - string rawExecPolicy = ReadValueFromFile(fileName, shellId); + string fileName = Path.Combine(scopeDirectory, configFileName); + string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); + string rawExecPolicy = ReadValueFromFile(fileName, valueName); if (!String.IsNullOrEmpty(rawExecPolicy)) { @@ -232,7 +233,7 @@ namespace System.Management.Automation return execPolicy; } - internal override void RemoveMachineExecutionPolicy(PropertyScope scope, string shellId) + internal override void RemoveExecutionPolicy(PropertyScope scope, string shellId) { string scopeDirectory = psHomeConfigDirectory; @@ -242,12 +243,12 @@ namespace System.Management.Automation scopeDirectory = appDataConfigDirectory; } - string fileName = Path.Combine(scopeDirectory, execPolicyFileName); - - RemoveValueFromFile(fileName, shellId); + string fileName = Path.Combine(scopeDirectory, configFileName); + string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); + RemoveValueFromFile(fileName, valueName); } - internal override void SetMachineExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy) + internal override void SetExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy) { string scopeDirectory = psHomeConfigDirectory; @@ -257,39 +258,9 @@ namespace System.Management.Automation scopeDirectory = appDataConfigDirectory; } - string fileName = Path.Combine(scopeDirectory, execPolicyFileName); - - WriteValueToFile(fileName, shellId, executionPolicy); - } - - /// - /// Existing Key = HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds - /// Proposed value = Existing value, otherwise 10. - /// - /// Schema: - /// { - /// "PipeLineMaxStackSizeMB" : int - /// } - /// - /// Max stack size in MB. If not set, defaults to 10 MB. - internal override int GetPipeLineMaxStackSizeMb(int defaultValue) - { - string fileName = Path.Combine(psHomeConfigDirectory, maxStackSizeFileName); - - int maxStackSize = defaultValue; - int rawMaxStackSize = ReadValueFromFile(fileName, "PipeLineMaxStackSizeMB"); - - if (0 != rawMaxStackSize) - { - maxStackSize = rawMaxStackSize; - } - return maxStackSize; - } - - internal override void SetPipeLineMaxStackSizeMb(int maxStackSize) - { - string fileName = Path.Combine(psHomeConfigDirectory, maxStackSizeFileName); - WriteValueToFile(fileName, "PipeLineMaxStackSizeMB", maxStackSize); + string fileName = Path.Combine(scopeDirectory, configFileName); + string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); + WriteValueToFile(fileName, valueName, executionPolicy); } /// @@ -304,13 +275,13 @@ namespace System.Management.Automation /// Whether console prompting should happen. If the value cannot be read it defaults to false. internal override bool GetConsolePrompting(ref Exception exception) { - string fileName = Path.Combine(psHomeConfigDirectory, consolePromptingFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); return ReadValueFromFile(fileName, "ConsolePrompting"); } internal override void SetConsolePrompting(bool shouldPrompt) { - string fileName = Path.Combine(psHomeConfigDirectory, consolePromptingFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); WriteValueToFile(fileName, "ConsolePrompting", shouldPrompt); } @@ -326,13 +297,13 @@ namespace System.Management.Automation /// Boolean indicating whether Update-Help should prompt. If the value cannot be read, it defaults to false. internal override bool GetDisablePromptToUpdateHelp() { - string fileName = Path.Combine(psHomeConfigDirectory, updateHelpPromptFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); return ReadValueFromFile(fileName, "DisablePromptToUpdateHelp"); } internal override void SetDisablePromptToUpdateHelp(bool prompt) { - string fileName = Path.Combine(psHomeConfigDirectory, updateHelpPromptFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); WriteValueToFile(fileName, "DisablePromptToUpdateHelp", prompt); } @@ -348,7 +319,7 @@ namespace System.Management.Automation /// The source path if found, null otherwise. internal override string GetDefaultSourcePath() { - string fileName = Path.Combine(psHomeConfigDirectory, updatableHelpSourcePathFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); string rawExecPolicy = ReadValueFromFile(fileName, "DefaultSourcePath"); @@ -361,7 +332,7 @@ namespace System.Management.Automation internal override void SetDefaultSourcePath(string defaultPath) { - string fileName = Path.Combine(psHomeConfigDirectory, updatableHelpSourcePathFileName); + string fileName = Path.Combine(psHomeConfigDirectory, configFileName); WriteValueToFile(fileName, "DefaultSourcePath", defaultPath); } @@ -383,15 +354,11 @@ namespace System.Management.Automation } } catch (ArgumentException) { } - //catch (ArgumentNullException) { } catch (NotSupportedException) { } catch (FileNotFoundException) { } - catch (System.IO.IOException) { } - //catch (DirectoryNotFoundException) { } + catch (IOException) { } catch (System.Security.SecurityException) { } catch (UnauthorizedAccessException) { } - //catch (PathTooLongException) { } - //catch (ArgumentOutOfRangeException) { } return default(T); } @@ -403,71 +370,94 @@ namespace System.Management.Automation /// /// /// - /// Whether the key-value pair should be added or removed from the file + /// Whether the key-value pair should be added to or removed from the file private void UpdateValueInFile(string fileName, string key, T value, bool addValue) { try { - JObject objectToWrite = new JObject(); - - if (File.Exists(fileName)) + // Since multiple properties can be in a single file, replacement + // is required instead of overwrite if a file already exists. + // Handling the read and write operations within a single FileStream + // prevents other processes from reading or writing the file while + // the update is in progress. + using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) + using (StreamReader streamRdr = new StreamReader(fs)) + using (JsonTextReader jsonReader = new JsonTextReader(streamRdr)) { - // Since multiple properties can be in a single file, replacement - // is required instead of overwrite if a file already exists. - using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) - using (StreamReader streamRdr = new StreamReader(fs)) - using (JsonTextReader jsonReader = new JsonTextReader(streamRdr)) + JObject jsonObject = null; + bool isReadSuccess = jsonReader.Read(); // Safely determines whether there is content to read from the file + + if ( ! isReadSuccess) { - JObject jsonObject = (JObject) JToken.ReadFrom(jsonReader); - IEnumerable properties = jsonObject.Properties(); - foreach (JProperty property in properties) + // The file doesn't already exist and we want to write to it or + // exists with no content. + // A new file will be created that contains only this value. + // If the file doesn't exist and a we don't want to write to it, no + // action is necessary. + if (addValue) { - if (String.Equals(property.Name, key, StringComparison.OrdinalIgnoreCase)) + jsonObject = new JObject(new JProperty(key, value)); + } + else + { + return; + } + } + else + { + // Read the stream into a root JObject for manipulation + jsonObject = (JObject) JToken.ReadFrom(jsonReader); + JProperty propertyToModify = jsonObject.Property(key); + + if (null == propertyToModify) + { + // The property doesn't exist, so add it + if (addValue) { - if (addValue) - { - // Add the updated value to the output object instead - // of the preexisting one - objectToWrite.Add(new JProperty(key, value)); - } - // else the value is skipped so it is removed from the file + jsonObject.Add(new JProperty(key, value)); + } + // else the property doesn't exist so there is nothing to remove + } + // The property exists + else + { + if (addValue) + { + propertyToModify.Replace(new JProperty(key, value)); } else { - // This preserves existing properties that do not - // match the one to update - objectToWrite.Add(new JProperty(property)); + propertyToModify.Remove(); } } } - } - else - { - if (addValue) + + // Reset the stream position to the beginning so that the + // changes to the file can be written to disk + fs.Seek(0, SeekOrigin.Begin); + + // Update the file with new content + using (StreamWriter streamWriter = new StreamWriter(fs)) + using (JsonTextWriter jsonWriter = new JsonTextWriter(streamWriter)) { - // The file doesn't exist, so create it with the new property - objectToWrite.Add(new JProperty(key, value)); + // The entire document exists within the root JObject. + // I just need to write that object to produce the document. + jsonObject.WriteTo(jsonWriter); + + // This trims the file if the file shrank. If the file grew, + // it is a no-op. The purpose is to trim extraneous characters + // from the file stream when the resultant JObject is smaller + // than the input JObject. + fs.SetLength(fs.Position); } } - - using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) - using (StreamWriter streamWriter = new StreamWriter(fs)) - using (JsonTextWriter jsonWriter = new JsonTextWriter(streamWriter)) - { - objectToWrite.WriteTo(jsonWriter); - } - } catch (ArgumentException) { } - //catch (ArgumentNullException) { } catch (NotSupportedException) { } catch (FileNotFoundException) { } - catch (System.IO.IOException) { } - //catch (DirectoryNotFoundException) { } + catch (IOException) { } catch (System.Security.SecurityException) { } catch (UnauthorizedAccessException) { } - //catch (PathTooLongException) { } - //catch (ArgumentOutOfRangeException) { } } /// @@ -494,7 +484,9 @@ namespace System.Management.Automation } } - internal class RegistryAccessor : PropertyAccessor +#endif // CORECLR + + internal class RegistryAccessor : ConfigPropertyAccessor { private const string DisablePromptToUpdateHelpRegPath = "Software\\Microsoft\\PowerShell"; private const string DisablePromptToUpdateHelpRegPath32 = "Software\\Wow6432Node\\Microsoft\\PowerShell"; @@ -524,7 +516,7 @@ namespace System.Management.Automation /// /// /// The execution policy string if found, otherwise null. - internal override string GetMachineExecutionPolicy(PropertyScope scope, string shellId) + internal override string GetExecutionPolicy(PropertyScope scope, string shellId) { string regKeyName = Utils.GetRegistryConfigurationPath(shellId); RegistryKey scopedKey = Registry.LocalMachine; @@ -538,7 +530,7 @@ namespace System.Management.Automation return GetRegistryString(scopedKey, regKeyName, "ExecutionPolicy"); } - internal override void SetMachineExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy) + internal override void SetExecutionPolicy(PropertyScope scope, string shellId, string executionPolicy) { string regKeyName = Utils.GetRegistryConfigurationPath(shellId); RegistryKey scopedKey = Registry.LocalMachine; @@ -558,7 +550,7 @@ namespace System.Management.Automation } } - internal override void RemoveMachineExecutionPolicy(PropertyScope scope, string shellId) + internal override void RemoveExecutionPolicy(PropertyScope scope, string shellId) { string regKeyName = Utils.GetRegistryConfigurationPath(shellId); RegistryKey scopedKey = Registry.LocalMachine; @@ -579,21 +571,6 @@ namespace System.Management.Automation } } - internal override int GetPipeLineMaxStackSizeMb(int defaultValue) - { - string regKeyName = Utils.GetRegistryConfigurationPrefix(); - - int? tempInt = GetRegistryDword(Registry.LocalMachine, regKeyName, "PipelineMaxStackSizeMB"); - - return (tempInt.HasValue ? tempInt.Value : defaultValue); - } - - internal override void SetPipeLineMaxStackSizeMb(int maxStackSize) - { - string regKeyName = Utils.GetRegistryConfigurationPrefix(); - SetRegistryDword(Registry.LocalMachine, regKeyName, "PipelineMaxStackSizeMB", maxStackSize); - } - /// /// Existing Key = HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds /// Proposed value = existing default. Probably "1" @@ -727,7 +704,7 @@ namespace System.Management.Automation catch (ObjectDisposedException) { } catch (System.Security.SecurityException) { } catch (ArgumentException) { } - catch (System.IO.IOException) { } + catch (IOException) { } catch (UnauthorizedAccessException) { } catch (FormatException) { } catch (OverflowException) { } @@ -751,7 +728,7 @@ namespace System.Management.Automation catch (ObjectDisposedException) { } catch (System.Security.SecurityException) { } catch (ArgumentException) { } - catch (System.IO.IOException) { } + catch (IOException) { } catch (UnauthorizedAccessException) { } catch (FormatException) { } catch (OverflowException) { } @@ -794,7 +771,7 @@ namespace System.Management.Automation catch (ObjectDisposedException e) { exception = e; } catch (System.Security.SecurityException e) { exception = e; } catch (ArgumentException e) { exception = e; } - catch (System.IO.IOException e) { exception = e; } + catch (IOException e) { exception = e; } catch (UnauthorizedAccessException e) { exception = e; } catch (FormatException e) { exception = e; } catch (OverflowException e) { exception = e; } @@ -818,7 +795,7 @@ namespace System.Management.Automation catch (ObjectDisposedException) { } catch (System.Security.SecurityException) { } catch (ArgumentException) { } - catch (System.IO.IOException) { } + catch (IOException) { } catch (UnauthorizedAccessException) { } catch (FormatException) { } catch (OverflowException) { } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index d79544da6..3ba32c7bf 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -237,8 +237,9 @@ namespace System.Management.Automation /// internal static string GetApplicationBase(string shellId) { -#if CORECLR // Use the location of SMA.dll as the application base - // Assembly.GetEntryAssembly is not in CoreCLR. GAC is not in CoreCLR. +#if CORECLR + // Use the location of SMA.dll as the application base + // Assembly.GetEntryAssembly and GAC are not in CoreCLR. Assembly assembly = typeof(PSObject).GetTypeInfo().Assembly; return Path.GetDirectoryName(assembly.Location); #else @@ -280,14 +281,16 @@ namespace System.Management.Automation /// /// Specifies the per-user configuration settings directory in a platform agnostic manner. - /// Ex: - /// %LOCALAPPDATA%\PowerShell\ + /// Windows Ex: + /// %LOCALAPPDATA%\PowerShell + /// Non-Windows Ex: + /// ~/.config/PowerShell /// /// The current user's configuration settings directory internal static string GetUserSettingsDirectory() { string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - return Path.Combine(appDataPath, "PowerShell", PSVersionInfo.PSVersion.ToString()); // TODO: This should be the external version#, but I don't see it anywhere in the code + return Path.Combine(appDataPath, "PowerShell"); } private static string[] GetProductFolderDirectories() diff --git a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs index 6ff6f7a1e..f2b305058 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs @@ -254,8 +254,7 @@ namespace System.Management.Automation.Runspaces { get { - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); - int i = propertyAccessor.GetPipeLineMaxStackSizeMb(10); + int i = ReadRegistryInt("PipelineMaxStackSizeMB", 10); if (i < 10) i = 10; // minimum 10MB @@ -533,6 +532,40 @@ namespace System.Management.Automation.Runspaces return flowControlException; } + // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 + // Removed HandleUnexpectedExceptions infrastructure + + internal static int ReadRegistryInt(string policyValueName, int defaultValue) + { + RegistryKey key; + try + { + key = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPrefix()); + } + catch (System.Security.SecurityException) + { + return defaultValue; + } + if (null == key) + return defaultValue; + + object temp; + try + { + temp = key.GetValue(policyValueName); + } + catch (System.Security.SecurityException) + { + return defaultValue; + } + if (!(temp is int)) + { + return defaultValue; + } + int i = (int)temp; + return i; + } + // NTRAID#Windows Out Of Band Releases-915506-2005/09/09 // Removed HandleUnexpectedExceptions infrastructure /// diff --git a/src/System.Management.Automation/help/UpdatableHelpSystem.cs b/src/System.Management.Automation/help/UpdatableHelpSystem.cs index 0776fb8a1..4d7b43016 100644 --- a/src/System.Management.Automation/help/UpdatableHelpSystem.cs +++ b/src/System.Management.Automation/help/UpdatableHelpSystem.cs @@ -1593,8 +1593,7 @@ namespace System.Management.Automation.Help /// internal string GetDefaultSourcePath() { - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); - return propertyAccessor.GetDefaultSourcePath(); + return ConfigPropertyAccessor.Instance.GetDefaultSourcePath(); } /// @@ -1602,8 +1601,7 @@ namespace System.Management.Automation.Help /// internal static void SetDisablePromptToUpdateHelp() { - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); - propertyAccessor.SetDisablePromptToUpdateHelp(true); + ConfigPropertyAccessor.Instance.SetDisablePromptToUpdateHelp(true); } /// @@ -1619,8 +1617,7 @@ namespace System.Management.Automation.Help return false; } - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); - return propertyAccessor.GetDisablePromptToUpdateHelp(); + return ConfigPropertyAccessor.Instance.GetDisablePromptToUpdateHelp(); } catch (SecurityException) { diff --git a/src/System.Management.Automation/project.json b/src/System.Management.Automation/project.json index f60feb16c..d692a01fe 100644 --- a/src/System.Management.Automation/project.json +++ b/src/System.Management.Automation/project.json @@ -197,6 +197,9 @@ "System.Management": "", "System.Configuration": "", "System.Configuration.Install": "" + }, + "dependencies": { + "Newtonsoft.Json": "7.0.1" } } } diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index f3b731745..17e6851ff 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -146,7 +146,6 @@ namespace System.Management.Automation.Internal #else string executionPolicy = "Restricted"; string preferenceKey = Utils.GetRegistryConfigurationPath(shellId); - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); switch (policy) { @@ -166,43 +165,47 @@ namespace System.Management.Automation.Internal switch (scope) { case ExecutionPolicyScope.Process: - { - if (policy == ExecutionPolicy.Undefined) - executionPolicy = null; + { + if (policy == ExecutionPolicy.Undefined) + executionPolicy = null; - Environment.SetEnvironmentVariable("PSExecutionPolicyPreference", executionPolicy); - break; - } + Environment.SetEnvironmentVariable("PSExecutionPolicyPreference", executionPolicy); + break; + } case ExecutionPolicyScope.CurrentUser: + { + // They want to remove it + if (policy == ExecutionPolicy.Undefined) { - // They want to remove it - if (policy == ExecutionPolicy.Undefined) - { - propertyAccessor.RemoveMachineExecutionPolicy(PropertyAccessor.PropertyScope.CurrentUser, shellId); - CleanKeyParents(Registry.CurrentUser, preferenceKey); - } - else - { - propertyAccessor.SetMachineExecutionPolicy(PropertyAccessor.PropertyScope.CurrentUser, shellId, executionPolicy); - } - break; + ConfigPropertyAccessor.Instance.RemoveExecutionPolicy( + ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId); + CleanKeyParents(Registry.CurrentUser, preferenceKey); } + else + { + ConfigPropertyAccessor.Instance.SetExecutionPolicy( + ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId, executionPolicy); + } + break; + } case ExecutionPolicyScope.LocalMachine: + { + // They want to remove it + if (policy == ExecutionPolicy.Undefined) { - // They want to remove it - if (policy == ExecutionPolicy.Undefined) - { - propertyAccessor.RemoveMachineExecutionPolicy(PropertyAccessor.PropertyScope.SystemWide, shellId); - CleanKeyParents(Registry.LocalMachine, preferenceKey); - } - else - { - propertyAccessor.SetMachineExecutionPolicy(PropertyAccessor.PropertyScope.SystemWide, shellId, executionPolicy); - } - break; + ConfigPropertyAccessor.Instance.RemoveExecutionPolicy( + ConfigPropertyAccessor.PropertyScope.SystemWide, shellId); + CleanKeyParents(Registry.LocalMachine, preferenceKey); } + else + { + ConfigPropertyAccessor.Instance.SetExecutionPolicy( + ConfigPropertyAccessor.PropertyScope.SystemWide, shellId, executionPolicy); + } + break; + } } #endif } @@ -586,17 +589,15 @@ namespace System.Management.Automation.Internal /// NULL if it is not defined at this level private static string GetLocalPreferenceValue(string shellId, ExecutionPolicyScope scope) { - PropertyAccessor propertyAccessor = PropertyAccessorFactory.GetPropertyAccessor(); - switch (scope) { // 1: Look up the current-user preference case ExecutionPolicyScope.CurrentUser: - return propertyAccessor.GetMachineExecutionPolicy(PropertyAccessor.PropertyScope.CurrentUser, shellId); + return ConfigPropertyAccessor.Instance.GetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.CurrentUser, shellId); // 2: Look up the system-wide preference case ExecutionPolicyScope.LocalMachine: - return propertyAccessor.GetMachineExecutionPolicy(PropertyAccessor.PropertyScope.SystemWide, shellId); + return ConfigPropertyAccessor.Instance.GetExecutionPolicy(ConfigPropertyAccessor.PropertyScope.SystemWide, shellId); } return null; diff --git a/src/powershell-native/CMakeLists.txt b/src/powershell-native/CMakeLists.txt index 7a7d72a53..dd039341f 100644 --- a/src/powershell-native/CMakeLists.txt +++ b/src/powershell-native/CMakeLists.txt @@ -40,7 +40,7 @@ endif (BUILD_ONECORE) foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${PROJECT_SOURCE_DIR}/Bin/${OUTPUTCONFIG}/${PWRSH_NATIVE_OUTPUT_DIRECTORY}") - message(" Setting output directory for ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG}}") + # message(" Setting output directory for ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG}}") endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) #