From 1c07bfcd01a44c938f7d1454b33accd998d8ba35 Mon Sep 17 00:00:00 2001 From: "James Truher [MSFT]" Date: Fri, 22 Sep 2023 17:01:22 -0700 Subject: [PATCH] Set experimental features to stable for 7.4 release (#20285) --- .../common/FormatViewGenerator_Table.cs | 2 +- .../engine/BytePipe.cs | 4 +- .../ExperimentalFeature.cs | 20 ------ .../engine/InitialSessionState.cs | 27 +++----- .../engine/NativeCommandProcessor.cs | 66 +++++++------------ .../engine/pipeline.cs | 33 ++++------ .../engine/runtime/Operations/MiscOps.cs | 22 +++---- .../Basic/NativeCommandBytePiping.Tests.ps1 | 5 -- .../NativeCommandErrorHandling.Tests.ps1 | 6 -- 9 files changed, 55 insertions(+), 130 deletions(-) diff --git a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs index 442603b448e..64ed5bad6cf 100644 --- a/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs +++ b/src/System.Management.Automation/FormatAndOutput/common/FormatViewGenerator_Table.cs @@ -173,7 +173,7 @@ private TableHeaderInfo GenerateTableHeaderInfoFromDataBaseInfo(PSObject so) ci.alignment = colHeader.alignment; if (colHeader.label != null) { - ci.HeaderMatchesProperty = so.Properties[colHeader.label.text] is not null || !ExperimentalFeature.IsEnabled(ExperimentalFeature.PSCustomTableHeaderLabelDecoration); + ci.HeaderMatchesProperty = so.Properties[colHeader.label.text] is not null; ci.label = this.dataBaseInfo.db.displayResourceManagerCache.GetTextTokenString(colHeader.label); } diff --git a/src/System.Management.Automation/engine/BytePipe.cs b/src/System.Management.Automation/engine/BytePipe.cs index 3d4832d6043..03eb827df98 100644 --- a/src/System.Management.Automation/engine/BytePipe.cs +++ b/src/System.Management.Automation/engine/BytePipe.cs @@ -104,9 +104,7 @@ internal static FileBytePipe Create(string fileName, bool append) throw new RuntimeException(null, e, errorRecord); } - ApplicationInsightsTelemetry.SendExperimentalUseData( - ExperimentalFeature.PSNativeCommandPreserveBytePipe, - "f"); + ApplicationInsightsTelemetry.SendExperimentalUseData("PSNativeCommandPreserveBytePipe", "f"); return new FileBytePipe(fileStream); } diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 45f8c98e7a0..25d9b6e2743 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -21,14 +21,9 @@ public class ExperimentalFeature #region Const Members internal const string EngineSource = "PSEngine"; - internal const string PSNativeCommandErrorActionPreferenceFeatureName = "PSNativeCommandErrorActionPreference"; - internal const string PSNativeCommandPreserveBytePipe = "PSNativeCommandPreserveBytePipe"; internal const string PSModuleAutoLoadSkipOfflineFilesFeatureName = "PSModuleAutoLoadSkipOfflineFiles"; - internal const string PSCustomTableHeaderLabelDecoration = "PSCustomTableHeaderLabelDecoration"; internal const string PSFeedbackProvider = "PSFeedbackProvider"; internal const string PSCommandWithArgs = "PSCommandWithArgs"; - internal const string PSConstrainedAuditLogging = "PSConstrainedAuditLogging"; - internal const string PSWindowsNativeCommandArgPassing = "PSWindowsNativeCommandArgPassing"; #endregion @@ -120,30 +115,15 @@ static ExperimentalFeature() new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), - new ExperimentalFeature( - name: PSNativeCommandErrorActionPreferenceFeatureName, - description: "Native commands with non-zero exit codes issue errors according to $ErrorActionPreference when $PSNativeCommandUseErrorActionPreference is $true"), new ExperimentalFeature( name: PSModuleAutoLoadSkipOfflineFilesFeatureName, description: "Module discovery will skip over files that are marked by cloud providers as not fully on disk."), - new ExperimentalFeature( - name: PSCustomTableHeaderLabelDecoration, - description: "Formatting differentiation for table header labels that aren't property members"), - new ExperimentalFeature( - name: PSNativeCommandPreserveBytePipe, - description: "Byte output is retained when piping between two or more native commands"), new ExperimentalFeature( name: PSFeedbackProvider, description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), new ExperimentalFeature( name: PSCommandWithArgs, description: "Enable `-CommandWithArgs` parameter for pwsh"), - new ExperimentalFeature( - name: PSConstrainedAuditLogging, - description: "PowerShell restriction logging when WDAC (Windows Defender Application Control) Code Integrity policy is set to Audit mode."), - new ExperimentalFeature( - name: "PSWindowsNativeCommandArgPassing", - description: "Enable 'Windows' as the native command argument passing mode"), }; EngineExperimentalFeatures = new ReadOnlyCollection(engineFeatures); diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index d367f4eb106..0a2d3fa74df 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -4652,16 +4652,13 @@ static InitialSessionState() #endregion }; - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandErrorActionPreferenceFeatureName)) - { - builtinVariables.Add( - new SessionStateVariableEntry( - SpecialVariables.PSNativeCommandUseErrorActionPreference, - value: true, // when this feature is changed to stable, this should default to `false` - RunspaceInit.PSNativeCommandUseErrorActionPreferenceDescription, - ScopedItemOptions.None, - new ArgumentTypeConverterAttribute(typeof(bool)))); - } + builtinVariables.Add( + new SessionStateVariableEntry( + SpecialVariables.PSNativeCommandUseErrorActionPreference, + value: false, + RunspaceInit.PSNativeCommandUseErrorActionPreferenceDescription, + ScopedItemOptions.None, + new ArgumentTypeConverterAttribute(typeof(bool)))); builtinVariables.Add( new SessionStateVariableEntry( @@ -4677,20 +4674,14 @@ static InitialSessionState() /// /// Assigns the default behavior for native argument passing. /// If the system is non-Windows, we will return Standard. - /// If the experimental feature is enabled, we will return Windows. - /// Otherwise, we will return Legacy. + /// Otherwise, we will return Windows. /// private static NativeArgumentPassingStyle GetPassingStyle() { #if UNIX return NativeArgumentPassingStyle.Standard; #else - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSWindowsNativeCommandArgPassing)) - { - return NativeArgumentPassingStyle.Windows; - } - - return NativeArgumentPassingStyle.Legacy; + return NativeArgumentPassingStyle.Windows; #endif } diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 326e96dfac8..85b675a9ae9 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -397,8 +397,7 @@ internal override void ProcessRecord() { // If upstream is a native command it'll be writing directly to our stdin stream // so we can skip reading here. - if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - || !UpstreamIsNativeCommand) + if (!UpstreamIsNativeCommand) { while (Read()) { @@ -547,7 +546,7 @@ private void InitNativeProcess() // Send Telemetry indicating what argument passing mode we are in. ApplicationInsightsTelemetry.SendExperimentalUseData( - ExperimentalFeature.PSWindowsNativeCommandArgPassing, + "PSWindowsNativeCommandArgPassing", NativeParameterBinderController.ArgumentPassingStyle.ToString()); #if !UNIX @@ -720,9 +719,7 @@ private void InitNativeProcess() lock (_sync) { - if (!_stopped - && (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - || !UpstreamIsNativeCommand)) + if (!_stopped && !UpstreamIsNativeCommand) { _inputWriter.Start(_nativeProcess, inputFormat); } @@ -785,21 +782,16 @@ private void InitOutputQueue() if (CommandRuntime.ErrorMergeTo is MshCommandRuntime.MergeDataStream.Output) { StdOutDestination = null; - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)) + if (DownStreamNativeCommand is not null) { - if (DownStreamNativeCommand is not null) - { - DownStreamNativeCommand.UpstreamIsNativeCommand = false; - DownStreamNativeCommand = null; - } + DownStreamNativeCommand.UpstreamIsNativeCommand = false; + DownStreamNativeCommand = null; } } _nativeProcessOutputQueue = new BlockingCollection(); // we don't assign the handler to anything, because it's used only for objects marshaling - BytePipe stdOutDestination = ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - ? StdOutDestination ?? DownStreamNativeCommand?.CreateBytePipe(stdout: false) - : null; + BytePipe stdOutDestination = StdOutDestination ?? DownStreamNativeCommand?.CreateBytePipe(stdout: false); BytePipe stdOutSource = null; if (stdOutDestination is not null) @@ -823,8 +815,7 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) { if (blocking) { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - && _stdOutByteTransfer is not null) + if (_stdOutByteTransfer is not null) { _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); return null; @@ -853,8 +844,7 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) } else { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - && _stdOutByteTransfer is not null) + if (_stdOutByteTransfer is not null) { return null; } @@ -897,8 +887,7 @@ internal override void Complete() if (!_isRunningInBackground) { // Wait for input writer to finish. - if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - || !UpstreamIsNativeCommand) + if (!UpstreamIsNativeCommand) { _inputWriter.Done(); } @@ -952,12 +941,6 @@ internal override void Complete() this.commandRuntime.PipelineProcessor.ExecutionFailed = true; - // Feature is not enabled, so return - if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandErrorActionPreferenceFeatureName)) - { - return; - } - // We send telemetry information only if the feature is enabled. // This shouldn't be done once, because it's a run-time check we should send telemetry every time. // Report on the following conditions: @@ -973,12 +956,12 @@ internal override void Complete() // The variable is unset if (useDefaultSetting) { - ApplicationInsightsTelemetry.SendExperimentalUseData(ExperimentalFeature.PSNativeCommandErrorActionPreferenceFeatureName, "unset"); + ApplicationInsightsTelemetry.SendExperimentalUseData("PSNativeCommandErrorActionPreference", "unset"); return; } // Send the value that was set. - ApplicationInsightsTelemetry.SendExperimentalUseData(ExperimentalFeature.PSNativeCommandErrorActionPreferenceFeatureName, nativeErrorActionPreferenceSetting.ToString()); + ApplicationInsightsTelemetry.SendExperimentalUseData("PSNativeCommandErrorActionPreference", nativeErrorActionPreferenceSetting.ToString()); // if it was explicitly set to false, return if (!nativeErrorActionPreferenceSetting) @@ -1267,8 +1250,7 @@ internal void StopProcessing() if (!_runStandAlone) { // Stop input writer - if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - || !UpstreamIsNativeCommand) + if (!UpstreamIsNativeCommand) { _inputWriter.Stop(); } @@ -1816,8 +1798,7 @@ public ProcessOutputHandler( return; } - if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - || stdOutDestination is null) + if (stdOutDestination is null) { _isFirstOutput = true; _isXmlCliOutput = false; @@ -2074,19 +2055,16 @@ internal void Add(object input) object baseObjInput = PSObject.Base(input); - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)) + if (baseObjInput is byte[] bytes) { - if (baseObjInput is byte[] bytes) - { - _streamWriter.BaseStream.Write(bytes, 0, bytes.Length); - return; - } + _streamWriter.BaseStream.Write(bytes, 0, bytes.Length); + return; + } - if (baseObjInput is byte b) - { - _streamWriter.BaseStream.WriteByte(b); - return; - } + if (baseObjInput is byte b) + { + _streamWriter.BaseStream.WriteByte(b); + return; } AddTextInput(input); diff --git a/src/System.Management.Automation/engine/pipeline.cs b/src/System.Management.Automation/engine/pipeline.cs index a045a4f83ff..e19bf3be843 100644 --- a/src/System.Management.Automation/engine/pipeline.cs +++ b/src/System.Management.Automation/engine/pipeline.cs @@ -261,31 +261,26 @@ private void LogToEventLog() /// internal int Add(CommandProcessorBase commandProcessor) { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)) + if (commandProcessor is NativeCommandProcessor nativeCommand) { - if (commandProcessor is NativeCommandProcessor nativeCommand) + if (_lastNativeCommand is not null) { - if (_lastNativeCommand is not null) + // Only report experimental feature usage once per pipeline. + if (!_haveReportedNativePipeUsage) { - // Only report experimental feature usage once per pipeline. - if (!_haveReportedNativePipeUsage) - { - ApplicationInsightsTelemetry.SendExperimentalUseData( - ExperimentalFeature.PSNativeCommandPreserveBytePipe, - "p"); - _haveReportedNativePipeUsage = true; - } - - _lastNativeCommand.DownStreamNativeCommand = nativeCommand; - nativeCommand.UpstreamIsNativeCommand = true; + ApplicationInsightsTelemetry.SendExperimentalUseData("PSNativeCommandPreserveBytePipe", "p"); + _haveReportedNativePipeUsage = true; } - _lastNativeCommand = nativeCommand; - } - else - { - _lastNativeCommand = null; + _lastNativeCommand.DownStreamNativeCommand = nativeCommand; + nativeCommand.UpstreamIsNativeCommand = true; } + + _lastNativeCommand = nativeCommand; + } + else + { + _lastNativeCommand = null; } commandProcessor.CommandRuntime.PipelineProcessor = this; diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index 583288905c2..eb3100ea512 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -221,10 +221,7 @@ private static CommandProcessorBase AddCommand(PipelineProcessor pipe, bool redirectedInformation = false; if (redirections != null) { - bool shouldProcessMergesFirst = ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe) - && isNativeCommand; - - if (shouldProcessMergesFirst) + if (isNativeCommand) { foreach (CommandRedirection redirection in redirections) { @@ -237,7 +234,7 @@ private static CommandProcessorBase AddCommand(PipelineProcessor pipe, foreach (CommandRedirection redirection in redirections) { - if (!shouldProcessMergesFirst || redirection is not MergingRedirection) + if (!isNativeCommand || redirection is not MergingRedirection) { redirection.Bind(pipe, commandProcessor, context); } @@ -1081,16 +1078,13 @@ public override string ToString() // dir > out internal override void Bind(PipelineProcessor pipelineProcessor, CommandProcessorBase commandProcessor, ExecutionContext context) { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)) + if (commandProcessor is NativeCommandProcessor nativeCommand + && nativeCommand.CommandRuntime.ErrorMergeTo is not MshCommandRuntime.MergeDataStream.Output + && FromStream is RedirectionStream.Output + && !string.IsNullOrWhiteSpace(File)) { - if (commandProcessor is NativeCommandProcessor nativeCommand - && nativeCommand.CommandRuntime.ErrorMergeTo is not MshCommandRuntime.MergeDataStream.Output - && FromStream is RedirectionStream.Output - && !string.IsNullOrWhiteSpace(File)) - { - nativeCommand.StdOutDestination = FileBytePipe.Create(File, Appending); - return; - } + nativeCommand.StdOutDestination = FileBytePipe.Create(File, Appending); + return; } Pipe pipe = GetRedirectionPipe(context, pipelineProcessor); diff --git a/test/powershell/engine/Basic/NativeCommandBytePiping.Tests.ps1 b/test/powershell/engine/Basic/NativeCommandBytePiping.Tests.ps1 index 1e645df9030..236cbd8c9e6 100644 --- a/test/powershell/engine/Basic/NativeCommandBytePiping.Tests.ps1 +++ b/test/powershell/engine/Basic/NativeCommandBytePiping.Tests.ps1 @@ -8,11 +8,6 @@ Describe 'Native command byte piping tests' -Tags 'CI' { BeforeAll { $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() - if (-not [ExperimentalFeature]::IsEnabled('PSNativeCommandPreserveBytePipe')) - { - $PSDefaultParameterValues['It:Skip'] = $true - return - } # Without this the test would otherwise be hard coded to a specific set # of [Console]::OutputEncoding/$OutputEncoding settings. diff --git a/test/powershell/engine/Basic/NativeCommandErrorHandling.Tests.ps1 b/test/powershell/engine/Basic/NativeCommandErrorHandling.Tests.ps1 index 055382bb5e1..8122e598d2c 100644 --- a/test/powershell/engine/Basic/NativeCommandErrorHandling.Tests.ps1 +++ b/test/powershell/engine/Basic/NativeCommandErrorHandling.Tests.ps1 @@ -7,12 +7,6 @@ Describe 'Native command error handling tests' -Tags 'CI' { BeforeAll { $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() - if (-not [ExperimentalFeature]::IsEnabled('PSNativeCommandErrorActionPreference')) - { - $PSDefaultParameterValues['It:Skip'] = $true - return - } - $exeName = $IsWindows ? 'testexe.exe' : 'testexe' $exePath = @(Get-Command $exeName -Type Application)[0].Path