Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 1 addition & 3 deletions src/System.Management.Automation/engine/BytePipe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<ExperimentalFeature>(engineFeatures);
Expand Down
27 changes: 9 additions & 18 deletions src/System.Management.Automation/engine/InitialSessionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -4677,20 +4674,14 @@ static InitialSessionState()
/// <summary>
/// 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.
/// </summary>
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
}

Expand Down
66 changes: 22 additions & 44 deletions src/System.Management.Automation/engine/NativeCommandProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -720,9 +719,7 @@ private void InitNativeProcess()

lock (_sync)
{
if (!_stopped
&& (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)
|| !UpstreamIsNativeCommand))
if (!_stopped && !UpstreamIsNativeCommand)
{
_inputWriter.Start(_nativeProcess, inputFormat);
}
Expand Down Expand Up @@ -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<ProcessOutputObject>();
// 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)
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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:
Expand All @@ -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)
Expand Down Expand Up @@ -1267,8 +1250,7 @@ internal void StopProcessing()
if (!_runStandAlone)
{
// Stop input writer
if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)
|| !UpstreamIsNativeCommand)
if (!UpstreamIsNativeCommand)
{
_inputWriter.Stop();
}
Expand Down Expand Up @@ -1816,8 +1798,7 @@ public ProcessOutputHandler(
return;
}

if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandPreserveBytePipe)
|| stdOutDestination is null)
if (stdOutDestination is null)
{
_isFirstOutput = true;
_isXmlCliOutput = false;
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 14 additions & 19 deletions src/System.Management.Automation/engine/pipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,31 +261,26 @@ private void LogToEventLog()
/// <exception cref="ObjectDisposedException"></exception>
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down