Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/System.Management.Automation/engine/PSConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ internal sealed class PowerShellPolicies
public ProtectedEventLogging ProtectedEventLogging { get; set; }
public Transcription Transcription { get; set; }
public UpdatableHelp UpdatableHelp { get; set; }
public PipelineMaxStackSize PipelineMaxStackSizeMB { get; set; }
public ConsoleSessionConfiguration ConsoleSessionConfiguration { get; set; }
}

Expand Down Expand Up @@ -618,6 +619,14 @@ internal sealed class ConsoleSessionConfiguration : PolicyBase
public string ConsoleSessionConfigurationName { get; set; }
}

/// <summary>
/// Setting about PipelineMaxStackSize
/// </summary>
internal sealed class PipelineMaxStackSize : PolicyBase
{
public int PipelineMaxStackSizeMB { get; set; }
}

/// <summary>
/// Setting about ProtectedEventLogging
/// </summary>
Expand Down
37 changes: 31 additions & 6 deletions src/System.Management.Automation/engine/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ internal static bool IsValidPSEditionValue(string editionValue)
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.
// If the requested policy is not defined in registry, we query the configuration file.
policy = GetPolicySettingFromGPO<T>(preferenceOrder);
if (policy != null) { return policy; }
#endif
Expand Down Expand Up @@ -547,6 +547,7 @@ internal static bool IsValidPSEditionValue(string editionValue)
case nameof(ScriptExecution): result = policies.ScriptExecution; break;
case nameof(ScriptBlockLogging): result = policies.ScriptBlockLogging; break;
case nameof(ModuleLogging): result = policies.ModuleLogging; break;
case nameof(PipelineMaxStackSize): result = policies.PipelineMaxStackSizeMB; break;
case nameof(ProtectedEventLogging): result = policies.ProtectedEventLogging; break;
case nameof(Transcription): result = policies.Transcription; break;
case nameof(UpdatableHelp): result = policies.UpdatableHelp; break;
Expand All @@ -566,6 +567,7 @@ internal static bool IsValidPSEditionValue(string editionValue)
{nameof(ScriptExecution), @"Software\Policies\Microsoft\PowerShellCore"},
{nameof(ScriptBlockLogging), @"Software\Policies\Microsoft\PowerShellCore\ScriptBlockLogging"},
{nameof(ModuleLogging), @"Software\Policies\Microsoft\PowerShellCore\ModuleLogging"},
{nameof(PipelineMaxStackSize), @"Software\Policies\Microsoft\PowerShellCore"},
{nameof(ProtectedEventLogging), @"Software\Policies\Microsoft\Windows\EventLog\ProtectedEventLogging"},
{nameof(Transcription), @"Software\Policies\Microsoft\PowerShellCore\Transcription"},
{nameof(UpdatableHelp), @"Software\Policies\Microsoft\PowerShellCore\UpdatableHelp"},
Expand All @@ -586,8 +588,11 @@ internal static bool IsValidPSEditionValue(string editionValue)
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))
RegistryKey gpoKey = null;
try
{
gpoKey = rootKey.OpenSubKey(gpoKeyPath, writable: false);

// If the corresponding GPO key doesn't exist, return null
if (gpoKey == null) { return null; }

Expand All @@ -614,7 +619,7 @@ internal static bool IsValidPSEditionValue(string editionValue)
}
else if (subKeyNameSet != null && subKeyNameSet.Contains(settingName))
{
using (RegistryKey subKey = gpoKey.OpenSubKey(settingName))
using (RegistryKey subKey = gpoKey.OpenSubKey(settingName, writable: false))
{
if (subKey != null) { rawRegistryValue = subKey.GetValueNames(); }
}
Expand All @@ -629,11 +634,17 @@ internal static bool IsValidPSEditionValue(string editionValue)

switch (propertyType)
{
case var _ when propertyType == typeof(bool?):
case var _ when propertyType == typeof(int):
if (rawRegistryValue is int rawIntValue)
{
if (rawIntValue == 1) { propertyValue = true; }
else if (rawIntValue == 0) { propertyValue = false; }
propertyValue = rawIntValue;
}
break;
case var _ when propertyType == typeof(bool?):
if (rawRegistryValue is int rawBoolValue)
{
if (rawBoolValue == 1) { propertyValue = true; }
else if (rawBoolValue == 0) { propertyValue = false; }
}
break;
case var _ when propertyType == typeof(string):
Expand Down Expand Up @@ -669,6 +680,20 @@ internal static bool IsValidPSEditionValue(string editionValue)
// If no property is set, then we consider this policy as undefined
return isAnyPropertySet ? (T) tInstance : null;
}
catch
{
// In any case, if the registry key or value does not exist or we do not have permissions to read it,
// we continue silently to use a default value.
}
finally
{
if (gpoKey != null)
{
gpoKey.Dispose();
}
}

return null;
}

/// <summary>
Expand Down
63 changes: 23 additions & 40 deletions src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Globalization;
using System.Threading;
using Microsoft.Win32;
using System.Management.Automation.Configuration;
using System.Management.Automation.Internal;
using System.Management.Automation.Internal.Host;
using System.Management.Automation.Tracing;
Expand Down Expand Up @@ -247,54 +248,36 @@ private void SetupInvokeThread(Thread invokeThread, bool changeName)
}
}

#if !CORECLR
/// <summary>
/// Stack Reserve setting for pipeline threads
/// Set stack size for local pipeline threads.
/// Default is 10MB.
/// Default 10MB may be too large if we use many local pipelines for paralleling.PipelineMaxStackSizeMB
/// </summary>
internal static int MaxStack
{
get
{
int i = ReadRegistryInt("PipelineMaxStackSizeMB", 10);
if (i < 10)
i = 10; // minimum 10MB
else if (i > 100)
i = 100; // maximum 100MB
return i * 1000000;
}
}
private const int DefaultPipelineStackSize = 10;
private const int MaxPipelineStackSize = 100;

internal static int ReadRegistryInt(string policyValueName, int defaultValue)
internal static int GetPipelineStackSizeOption()
{
RegistryKey key;
try
{
key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\PowerShell\\1\\ShellIds");
}
catch (System.Security.SecurityException)
{
return defaultValue;
}
if (null == key)
return defaultValue;
int stackSize = DefaultPipelineStackSize;

object temp;
try
var pipelineMaxStackSizeOption = Utils.GetPolicySetting<PipelineMaxStackSize>(Utils.SystemWideThenCurrentUserConfig);

if (pipelineMaxStackSizeOption != null)
{
temp = key.GetValue(policyValueName);
stackSize = pipelineMaxStackSizeOption.PipelineMaxStackSizeMB;
}
catch (System.Security.SecurityException)

if (stackSize < DefaultPipelineStackSize)
{
return defaultValue;
stackSize = DefaultPipelineStackSize;
}
if (!(temp is int))
else if (stackSize > MaxPipelineStackSize)
{
return defaultValue;
stackSize = MaxPipelineStackSize;
}
int i = (int)temp;
return i;

return stackSize * 1_000_000;
}
#endif

///<summary>
/// Helper method for asynchronous invoke
Expand Down Expand Up @@ -1225,25 +1208,25 @@ protected override
}

/// <summary>
/// Helper class that holds the thread used to execute pipelines when CreateThreadOptions.ReuseThread is used
/// Helper class that holds the thread used to execute pipelines when CreateThreadOptions.ReuseThread is used.
/// </summary>
internal class PipelineThread : IDisposable
{
/// <summary>
/// Creates the worker thread and waits for it to be ready
/// Creates the worker thread and waits for it to be ready.
/// </summary>
#if CORECLR
internal PipelineThread()
{
_worker = new Thread(WorkerProc);
_worker = new Thread(WorkerProc, LocalPipeline.GetPipelineStackSizeOption());
_workItem = null;
_workItemReady = new AutoResetEvent(false);
_closed = false;
}
#else
internal PipelineThread(ApartmentState apartmentState)
{
_worker = new Thread(WorkerProc, LocalPipeline.MaxStack);
_worker = new Thread(WorkerProc, LocalPipeline.GetPipelineStackSizeOption());
_workItem = null;
_workItemReady = new AutoResetEvent(false);
_closed = false;
Expand Down