-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Make PowerShell able to enable logging of script block execution on Unix platforms #5791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There are a lot of changes in this PR. When reviewing this PR, I recommend you review each commit because I intentionally group logically related changes into separate commits. |
- Remove the unneeded base type; - Rename 'ConfigPropertyAccessor' to 'PowerShellConfig'; - Move 'PowerShellConfig' to the namespace 'System.Management.Automation.Configuration'
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<ConsoleSessionConfiguration>(Utils.CurrentUserThenSystemWideConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change, the Windows PowerShell GPO settings don't apply to PSCore6, correct? This seems correct to me, but is a breaking change
. We should label this PR as such. cc @joeyaiello
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, GPO settings in Registry won't apply to PowerShell Core. I have added the breaking change
label. Thanks for catching that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not seem correct to me. @Indhukrishna DSC has had feedback that seems to indicate that they expect GPO to apply.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will start to work on enabling GPO as well on windows. The preference order of the settings should be config file --> GPO, meaning if a policy setting is defined in the config file, then use it; if it's not defined in the config file, query registry. This way, you can have control whether you want the GPO settings to take effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Common rule is that Computer GPO is high priority, then User GPO, then computer wide config, then user config. It is critical rule and security related.
Update.
Software\Policies\Microsoft\Windows\PowerShell
- here Policies
assume that it is high priority and should overlap other configs - users can not change its.
Software\Microsoft\Windows\PowerShell
- it is a normal config corresponding to a text config file. This setting can be set manually by user or by using Group Policy Preferences (GPP). I think it should be low priority over a text config file (looks as changing defaults or set recommended defaults that the user can change by a config file).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the policy related settings, we are having a debate on which one should take preference. I will talk to @TravisEz13 later today about it.
For non-policy related settings, we shouldn't use registry settings anymore but only refer to the config file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conclusion is: on windows, we query group policies from registry first, and if the requested policy is not defined in GP, then we query from the configuration file.
New commit has been pushed to enable this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For non-policy related settings, we shouldn't use registry settings anymore but only refer to the config file.
I don't agree - GPO is great Enterprise feature and Domain Admins should have full and flexible control on PowerShell. We could discuss this in a Issue (as I mention below too).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean "non-policy related settings", like the settings in "SOFTWARE\Microsoft\PowerShell" today. They are not group policies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still reviewing
/// { | ||
/// "DefaultSourcePath" : "path to local updatable help location" | ||
/// } | ||
/// Corresponding settings of the original Group Policies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're moving GPO support, we shouldn't mention "original Group Policies", just call it "PowerShell Policies"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we now re-enabled the GPO support on Windows, I will leave this comment unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct
@@ -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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this path should be a const somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is in a #if !CORECLR ... #endif
block. I leave the registry key path here only for reference, so that when we clean up this !CORECLR
block, we know what the key is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
{ | ||
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't the IsProductCode check in the outer if statement since it's never logged when set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theoretically, this can be re-written as
if ((force && logSetting?.EnableScriptBlockLogging != false) || logSetting?.EnableScriptBlockLogging == true)
{
if ((!scriptBlock.HasLogged || InternalTestHooks.ForceScriptBlockLogging) && !scriptBlock.ScriptBlockData.IsProductCode)
{
....
}
}
Or even more aggressively, these two if
blocks can be merged into one. But this doesn't look very readable, so I think I'm fine with the original code.
{ | ||
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 || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior change may be confusing without some documentation.
We've essentially now have 3 logging states, on, off, and warnings. When the setting is not defined, scripts that have suspicious content are logged.
I suggest a doc change to clarify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no behavior change, the check logSetting?.EnableScriptBlockLogging == false
is to make sure that the EnableScriptBlockLogging
is explicitly set to false
in the config file. If you look at the original implementation of ScriptBlockLoggingExplicitlyDisabled()
, it returns true
only if the registry key EnableScriptBlockLogging
exists and its value is explicitly 0.
I agree to have docs to clarify how logging works in PowerShell. Not sure if we already have some docs about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@daxian-dbw Could you please add this in PR description for future docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, a documentation section is added to PR description.
{ | ||
object enableModuleLoggingValue = null; | ||
if (groupPolicySettings.TryGetValue("EnableModuleLogging", out enableModuleLoggingValue)) | ||
if (moduleLogging.EnableModuleLogging == false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need multiple return paths? Why not if (... == false) else if (... == true) and set status in both cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't change the original code, will update it to set status
in both cases.
@@ -921,7 +921,7 @@ internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOptio | |||
{ | |||
if (systemTranscript == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lock is not used consistently with other usages. if the intent is to return the updated or original value, the lock should also encapsulate both the "if (transcription != null)" block and the implied else block.
As written, there is a possible race between this path and StopAllTranscribing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't change the original code. I guess you are right, this method could return a TranscriptionOption
object or null depending on whether StopAllTranscribing
set systemTranscript
to null
before return systemTranscript;
in this method. But I'm not familiar enough with the transcribing code to know if that could be a problem.
Can you open an issue tracking this comment? We can look at the transcribing code more closely when addressing that issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal sealed class ScriptExecution : PolicyBase | ||
{ | ||
public string ExecutionPolicy { get; set; } | ||
public bool? EnableScripts { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the value of having this nullable. EnableScripts == null is same as EnableScripts == true, correct? Same question for the nullable properties below where they should have a default value and being null is the same as the default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EnableScripts == null
means this setting is not defined in the config file, so it's up to powershell to define the default behavior. EnableScripts == true
means it's defined in the config file and the value is true
. Likewise, EnableScripts == false
means it's defined in the config file and the value is false
.
It's the same in registry -- a key is not defined, which means the application needs to use the pre-defined behavior; when the key is defined, the value will be either 1 or 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An example is the use of EnableScriptBlockLogging
in LogScriptBlockCreation(ScriptBlock scriptBlock, bool force)
- when it's explicitly set to 'true' (1 in registry), we always do script block logging;
- when it's not defined, we do script block logging when
force == true
- when it's explicitly set to 'false' (0 in registry), we always disable script block logging, even if
force == true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, the force case makes sense that there is a difference with null. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the nullable too. I see no reason to emulate registry keys. If now we use static classes it is more readable and maintainable to set defaults explicitly. Force
works with this too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's mimicking registry keys, but a requirement to represent three states: enabled, disabled and undefined. Without bool?
, if EnableScriptBlockLogging
is not specified in the config file while EnableScriptBlockInvocationLogging
is specified, then the deserialized ScriptBlockLogging
object will have EnableScriptBlockLogging
set to false (the default value), which will be interpreted as "script block logging" is explicitly disabled.
The EnableScriptBlockLogging
example is from existing code, I didn't change the logic. If it turns out we don't need the bool?
type in future, we can always change it since it's internal.
// 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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can install PowerShell Core side-by-side with other PowerShell Core-s. So we should have configs for "default" system wide installation and for "local" for every user installation.
Also it seems we should have GPO option - "Force GPO for Side-By-Side PowerShell installations" - by default we should apply GPO only for system wide PowerShell installation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on internal discussion today, the current plan is to have PSCore6 GPO settings separate from Windows PowerShell. For now, we don't plan to have side-by-side GPO settings per version of PSCore6 until there is customer need for it. New admx will be published later for the PSCore6 settings (which will be the same as Windows PowerShell, but reside in a different location in registry).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GPO is Enterprise feature. GPO should allow Domain Admins get full control on PowerShell. I full trust MSFT experts but I'd prefer discuss GPO in a Issue. Also we forget about AppLocker.
I'd as Domain Admin prefer don't separate PowerShell Core GPO - it is better by default use Windows PowerShell setting until PowerShell Core GPOs is set explicitly otherwise users can ignore corporate policies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iSazonov since PSCore6 is not inbox in Windows and doesn't replace Windows PowerShell, we shouldn't use the same settings. PSCore6 in this case is no different from any 3rd party app.
var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 10 }; | ||
var serializer = JsonSerializer.Create(settings); | ||
|
||
var configData = serializer.Deserialize<JObject>(jsonReader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has a security review been done on this code? Is it possible for the deserializer to create arbitrary types or run arbitrary code? If so is it possible to apply a schema to mitigate? This could be a possible security hole when we (re) implement PowerShell white listing protection. Can you add a comment about this possible vulnerability and create an issue to track?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to apply a schema to mitigate
We have a PR for Test-Json - it can help here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PaulHigin the use of JsonSerailizer
here is the same as in ConverFrom/ConverTo-Json
cmdlets. I will add a comment and create an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a closer look at the usage, and think it should be safe. The usage here can only convert values to the limited types: string, bool, string[], bool?, and sub types of PolicyBase
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@daxian-dbw If that is the case then we should be Ok. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do PowerShell silently eat wrong config options without the schema check? It is bad UX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PowerShell currently doesn't do schema check on the config file, which needs to be addressed. I opened #5809 with 3 tasks. Feel free to bring up more to discuss.
test/csharp/test_PSConfiguration.cs
Outdated
// Create the CurrentUser config directory if it doesn't exist | ||
Directory.CreateDirectory(currentUserConfigDirectory); | ||
} | ||
|
||
systemWideConfigFile = Path.Combine(systemWideConfigDirectory, "PowerShellProperties.json"); | ||
currentUserConfigFile = Path.Combine(currentUserConfigDirectory, "PowerShellProperties.json"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe Properties
should be replaced with Config
.
PowerShellConfig.json
or PowerShell.Config.json
or PowerShell.config.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this file name either. I will see if I can rename it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed new commit to rename the file. The file name is now 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have lock (s_cachedPolicies)
in Utils.cs - maybe that's enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are other settings except for the policy related ones and they may query the config file simultaneously, so this lock is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could find a way to use only one global lock - if we want to have consistency, it doesn't matter how and what settings change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The querying for GP setting is a hot code path, especially for the script block logging, every script block execution will query for it. The lock s_cachedPolicies
is to make sure that when multiple threads are querying for GP settings at the same time, only one thread will actually hit and read the configuration file.
On windows, group policy settings from registry takes precedence over the configuration file. If a policy is not defined in GP, then we query from configuration file.
@@ -921,7 +921,7 @@ internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOptio | |||
{ | |||
if (systemTranscript == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// <summary> | ||
/// Get a specific kind of policy setting from the configuration file. | ||
/// </summary> | ||
internal static T GetPolicySettingFromConfigFile<T>(ConfigScope[] preferenceOrder) where T : PolicyBase, new() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should. Will update.
/// <summary> | ||
/// Get a specific kind of policy setting from the group policy registry key. | ||
/// </summary> | ||
internal static T GetPolicySettingFromGPO<T>(ConfigScope[] preferenceOrder) where T : PolicyBase, new() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be private, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should. Will update.
@@ -29,7 +29,7 @@ internal sealed class PowerShellConfig | |||
|
|||
private string psHomeConfigDirectory; | |||
private string appDataConfigDirectory; | |||
private const string configFileName = "PowerShellProperties.json"; | |||
private const string configFileName = "powershell.config.json"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
about_Logging.md will need to be updated.
See https://github.com/PowerShell/PowerShell-Docs/blob/staging/reference/6/Microsoft.PowerShell.Core/About/about_Logging.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened MicrosoftDocs/PowerShell-Docs#2017 to track the documentation update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that about_logging.md needs to be updated regardless since it refers to 'PowerShellProperties.json'.
{nameof(UpdatableHelp), @"Software\Policies\Microsoft\PowerShellCore\UpdatableHelp"}, | ||
{nameof(ConsoleSessionConfiguration), @"Software\Policies\Microsoft\PowerShellCore\ConsoleSessionConfiguration"} | ||
}; | ||
private readonly static ConcurrentDictionary<Tuple<ConfigScope, string>, PolicyBase> s_cachedPoliciesFromRegistry = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really, we should register for GP change notifications and clear the cache. Not a regression, so, can you add a comment or file an issue: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374404(v=vs.85).aspx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue #5804 is opened to track this.
@dantraMSFT @SteveL-MSFT @iSazonov @TravisEz13 I think all comments have been addressed (code updated, or question answered, or issue opened). Can you please take another look to see if the PR is ready to merge? |
|
||
/// <summary> | ||
/// The GroupPolicy related settings used in PowerShell are as follows in Registry: | ||
/// - Software\Policies\Microsoft\Windows\PowerShell -- { EnableScripts (0 or 1); ExecutionPolicy (string) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to be updated as we're putting it under ...\Microsoft\PowerShellCore
now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do. Done.
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, "Unreachable code"); break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps have the same assert message as line 656 below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add GPO tests at some point.
Thanks all for the reviews! |
@TravisEz13 can you open an issue to track the GPO tests? |
…werShell Core (PowerShell#5791) Make PowerShell Core reads group policy settings from different registry keys (Windows only) and the configuration files (both Windows and Unix). - On Windows, move to different GPO registry keys. - On both Windows and Unix, read GPO related settings from the configuration file `powershell.config.json`. - On Windows, the policy settings in registry take precedence over the configuration file. - Enable policy controlled logging and transcription on Unix.
…werShell Core (#5791) Make PowerShell Core reads group policy settings from different registry keys (Windows only) and the configuration files (both Windows and Unix). - On Windows, move to different GPO registry keys. - On both Windows and Unix, read GPO related settings from the configuration file `powershell.config.json`. - On Windows, the policy settings in registry take precedence over the configuration file. - Enable policy controlled logging and transcription on Unix.
PR Summary
Fix #5695
Enable ScriptBlockLogging on Linux/macOS by moving the GroupPolicy configurations to the configuration file
PowerShellProperties.json
. Including the following tasks:MshLog.cs
on Unix platforms. (the 1st commit)PropertyAccessor.cs
. (the 2nd commit)PowerShellConfig
PowerShellConfig
to the namespaceSystem.Management.Automation.Configuration
PropertyScope
toConfigScope
. (the 3rd commit)PropertyAccessor.cs
toPSConfiguration.cs
. (the 4th commit)SecuritySupport.cs
)CompiledScriptBlock.cs
)ModuleCmdletBase.cs
)CompiledScriptBlock.cs
)MshHostUserInterface.cs
)UpdatableHelpSystem.cs
)CommandLineParameterParser.cs
)PSConfiguration.cs
, updatedReadValueFromFile<T>
to make it flexible to allow a customJsonObject
parsing implementation delegate passed in.PSConfiguration.cs
, addedGetPowerShellPolicies(ConfigScope scope)
and makeDefaultSourcePath
setting part of the new policy settings because it is part of the group policy on windows powershell.Utils.cs
, replace the methodGetGroupPolicySetting
withT GetPolicySetting<T>(ConfigScope[] preferenceOrder) where T : PolicyBase
. The old method was for reading from Registry, while the new one is for reading from configuration file.GetGroupPolicySetting
being replaced.PSTests.Parallel
and the new tests are moved toPSTests.Sequential
and the corresponding build scripts are updated to run sequential xUnit tests first and then run other xUnit tests in parallel.SysLogProvider
to make ScriptBlock logging not ignored on Unix platforms. (the 7th commit)PowerShellProperties.json
topowershell.config.json
. (the 10th commit)An example of the configuration file
powershell.config.json
Limitation that needs to be documented
On Unix platform, the default logging level filter is
information
, while the logging of script block execution writes outverbose
level logging. So the configuration entry"LogLevel": "verbose"
is needed along with the settings in"ScriptBlockLogging"
. This needs to be documented.Documentation needed
We need documentation to clarify how logging works in PowerShell. Not sure if we already have some docs about it. Issue MicrosoftDocs/PowerShell-Docs#2017 is opened.
PR Checklist
Note: Please mark anything not applicable to this PR
NA
.[feature]
if the change is significant or affectes feature testsWIP:
to the beginning of the title and remove the prefix when the PR is ready.