Fix a casting error when using $PSNativeCommandUsesErrorActionPreference
(#15993)
This commit is contained in:
parent
15836f289c
commit
403767d7f7
|
@ -525,9 +525,7 @@ namespace System.Management.Automation
|
|||
/// </summary>
|
||||
internal object GetVariableValue(VariablePath path, object defaultValue)
|
||||
{
|
||||
CmdletProviderContext context;
|
||||
SessionStateScope scope;
|
||||
return EngineSessionState.GetVariableValue(path, out context, out scope) ?? defaultValue;
|
||||
return EngineSessionState.GetVariableValue(path, out _, out _) ?? defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -612,19 +610,15 @@ namespace System.Management.Automation
|
|||
/// <returns></returns>
|
||||
internal bool GetBooleanPreference(VariablePath preferenceVariablePath, bool defaultPref, out bool defaultUsed)
|
||||
{
|
||||
CmdletProviderContext context = null;
|
||||
SessionStateScope scope = null;
|
||||
object val = EngineSessionState.GetVariableValue(preferenceVariablePath, out context, out scope);
|
||||
if (val == null)
|
||||
object val = EngineSessionState.GetVariableValue(preferenceVariablePath, out _, out _);
|
||||
if (val is null)
|
||||
{
|
||||
defaultUsed = true;
|
||||
return defaultPref;
|
||||
}
|
||||
|
||||
bool converted = defaultPref;
|
||||
defaultUsed = !LanguagePrimitives.TryConvertTo<bool>
|
||||
(val, out converted);
|
||||
return (defaultUsed) ? defaultPref : converted;
|
||||
defaultUsed = !LanguagePrimitives.TryConvertTo(val, out bool converted);
|
||||
return defaultUsed ? defaultPref : converted;
|
||||
}
|
||||
#endregion GetSetVariable methods
|
||||
|
||||
|
@ -1568,23 +1562,6 @@ namespace System.Management.Automation
|
|||
private void InitializeCommon(AutomationEngine engine, PSHost hostInterface)
|
||||
{
|
||||
Engine = engine;
|
||||
#if !CORECLR// System.AppDomain is not in CoreCLR
|
||||
// Set the assembly resolve handler if it isn't already set...
|
||||
if (!_assemblyEventHandlerSet)
|
||||
{
|
||||
// we only want to set the event handler once for the entire app domain...
|
||||
lock (lockObject)
|
||||
{
|
||||
// Need to check again inside the lock due to possibility of a race condition...
|
||||
if (!_assemblyEventHandlerSet)
|
||||
{
|
||||
AppDomain currentAppDomain = AppDomain.CurrentDomain;
|
||||
currentAppDomain.AssemblyResolve += new ResolveEventHandler(PowerShellAssemblyResolveHandler);
|
||||
_assemblyEventHandlerSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Events = new PSLocalEventManager(this);
|
||||
transactionManager = new PSTransactionManager();
|
||||
_debugger = new ScriptDebugger(this);
|
||||
|
@ -1609,35 +1586,6 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
private static readonly object lockObject = new object();
|
||||
|
||||
#if !CORECLR // System.AppDomain is not in CoreCLR
|
||||
private static bool _assemblyEventHandlerSet = false;
|
||||
|
||||
/// <summary>
|
||||
/// AssemblyResolve event handler that will look in the assembly cache to see
|
||||
/// if the named assembly has been loaded. This is necessary so that assemblies loaded
|
||||
/// with LoadFrom, which are in a different loaded context than Load, can still be used to
|
||||
/// resolve types.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender.</param>
|
||||
/// <param name="args">The event args.</param>
|
||||
/// <returns>The resolve assembly or null if not found.</returns>
|
||||
private static Assembly PowerShellAssemblyResolveHandler(object sender, ResolveEventArgs args)
|
||||
{
|
||||
ExecutionContext ecFromTLS = Runspaces.LocalPipeline.GetExecutionContextFromTLS();
|
||||
if (ecFromTLS != null)
|
||||
{
|
||||
if (ecFromTLS.AssemblyCache != null)
|
||||
{
|
||||
Assembly assembly;
|
||||
ecFromTLS.AssemblyCache.TryGetValue(args.Name, out assembly);
|
||||
return assembly;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1308,37 +1308,6 @@ namespace System.Management.Automation.Runspaces
|
|||
}
|
||||
}
|
||||
|
||||
#region VariableHelper
|
||||
/// <summary>
|
||||
/// A helper for adding variables to session state.
|
||||
/// Experimental features can be handled here.
|
||||
/// </summary>
|
||||
/// <param name="variables">The variables to add to session state.</param>
|
||||
private void AddVariables(IEnumerable<SessionStateVariableEntry> variables)
|
||||
{
|
||||
Variables.Add(variables);
|
||||
|
||||
// If the PSNativeCommandArgumentPassing feature is enabled, create the variable which controls the behavior
|
||||
// Since the BuiltInVariables list is static, and this should be done dynamically
|
||||
// we need to do this here. Also, since the defaults are different based on platform we need a
|
||||
// bit more logic.
|
||||
if (ExperimentalFeature.IsEnabled("PSNativeCommandArgumentPassing"))
|
||||
{
|
||||
NativeArgumentPassingStyle style = NativeArgumentPassingStyle.Standard;
|
||||
if (Platform.IsWindows) {
|
||||
style = NativeArgumentPassingStyle.Windows;
|
||||
}
|
||||
Variables.Add(
|
||||
new SessionStateVariableEntry(
|
||||
SpecialVariables.NativeArgumentPassing,
|
||||
style,
|
||||
RunspaceInit.NativeCommandArgumentPassingDescription,
|
||||
ScopedItemOptions.None,
|
||||
new ArgumentTypeConverterAttribute(typeof(NativeArgumentPassingStyle))));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Creates an initial session state from a PSSC configuration file.
|
||||
/// </summary>
|
||||
|
@ -1444,7 +1413,7 @@ namespace System.Management.Automation.Runspaces
|
|||
}
|
||||
|
||||
// Add built-in variables.
|
||||
iss.AddVariables(BuiltInVariables);
|
||||
iss.Variables.Add(BuiltInVariables);
|
||||
|
||||
// wrap some commands in a proxy function to restrict their parameters
|
||||
foreach (KeyValuePair<string, CommandMetadata> proxyFunction in CommandMetadata.GetRestrictedCommands(SessionCapabilities.RemoteServer))
|
||||
|
@ -1531,7 +1500,7 @@ namespace System.Management.Automation.Runspaces
|
|||
|
||||
InitialSessionState ss = new InitialSessionState();
|
||||
|
||||
ss.AddVariables(BuiltInVariables);
|
||||
ss.Variables.Add(BuiltInVariables);
|
||||
ss.Commands.Add(new SessionStateApplicationEntry("*"));
|
||||
ss.Commands.Add(new SessionStateScriptEntry("*"));
|
||||
ss.Commands.Add(BuiltInFunctions);
|
||||
|
@ -1598,7 +1567,7 @@ namespace System.Management.Automation.Runspaces
|
|||
{
|
||||
InitialSessionState ss = new InitialSessionState();
|
||||
|
||||
ss.AddVariables(BuiltInVariables);
|
||||
ss.Variables.Add(BuiltInVariables);
|
||||
ss.Commands.Add(new SessionStateApplicationEntry("*"));
|
||||
ss.Commands.Add(new SessionStateScriptEntry("*"));
|
||||
ss.Commands.Add(BuiltInFunctions);
|
||||
|
@ -1639,7 +1608,7 @@ namespace System.Management.Automation.Runspaces
|
|||
{
|
||||
InitialSessionState ss = new InitialSessionState();
|
||||
|
||||
ss.AddVariables(this.Variables.Clone());
|
||||
ss.Variables.Add(this.Variables.Clone());
|
||||
ss.EnvironmentVariables.Add(this.EnvironmentVariables.Clone());
|
||||
ss.Commands.Add(this.Commands.Clone());
|
||||
ss.Assemblies.Add(this.Assemblies.Clone());
|
||||
|
@ -4471,7 +4440,6 @@ end {
|
|||
internal const ActionPreference DefaultInformationPreference = ActionPreference.SilentlyContinue;
|
||||
|
||||
internal const ErrorView DefaultErrorView = ErrorView.ConciseView;
|
||||
internal const bool DefaultPSNativeCommandUseErrorActionPreference = false;
|
||||
internal const bool DefaultWhatIfPreference = false;
|
||||
internal const ConfirmImpact DefaultConfirmPreference = ConfirmImpact.High;
|
||||
|
||||
|
@ -4628,12 +4596,23 @@ end {
|
|||
builtinVariables.Add(
|
||||
new SessionStateVariableEntry(
|
||||
SpecialVariables.PSNativeCommandUseErrorActionPreference,
|
||||
DefaultPSNativeCommandUseErrorActionPreference,
|
||||
value: false,
|
||||
RunspaceInit.PSNativeCommandUseErrorActionPreferenceDescription,
|
||||
ScopedItemOptions.None,
|
||||
new ArgumentTypeConverterAttribute(typeof(bool))));
|
||||
}
|
||||
|
||||
if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandArgumentPassingFeatureName))
|
||||
{
|
||||
builtinVariables.Add(
|
||||
new SessionStateVariableEntry(
|
||||
SpecialVariables.NativeArgumentPassing,
|
||||
Platform.IsWindows ? NativeArgumentPassingStyle.Windows : NativeArgumentPassingStyle.Standard,
|
||||
RunspaceInit.NativeCommandArgumentPassingDescription,
|
||||
ScopedItemOptions.None,
|
||||
new ArgumentTypeConverterAttribute(typeof(NativeArgumentPassingStyle))));
|
||||
}
|
||||
|
||||
BuiltInVariables = builtinVariables.ToArray();
|
||||
}
|
||||
|
||||
|
|
|
@ -3250,8 +3250,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
if (!IsWhatIfFlagSet && !_isWhatIfPreferenceCached)
|
||||
{
|
||||
bool defaultUsed = false;
|
||||
_whatIfFlag = Context.GetBooleanPreference(SpecialVariables.WhatIfPreferenceVarPath, _whatIfFlag, out defaultUsed);
|
||||
_whatIfFlag = Context.GetBooleanPreference(SpecialVariables.WhatIfPreferenceVarPath, _whatIfFlag, out _);
|
||||
_isWhatIfPreferenceCached = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ namespace System.Management.Automation
|
|||
/// </summary>
|
||||
internal class NativeCommandParameterBinder : ParameterBinderBase
|
||||
{
|
||||
private readonly VariablePath s_nativeArgumentPassingVarPath = new VariablePath(SpecialVariables.NativeArgumentPassing);
|
||||
|
||||
#region ctor
|
||||
|
||||
/// <summary>
|
||||
|
@ -193,13 +191,13 @@ namespace System.Management.Automation
|
|||
{
|
||||
get
|
||||
{
|
||||
if (ExperimentalFeature.IsEnabled("PSNativeCommandArgumentPassing"))
|
||||
if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandArgumentPassingFeatureName))
|
||||
{
|
||||
try
|
||||
{
|
||||
// This will default to the new behavior if it is set to anything other than Legacy
|
||||
var preference = LanguagePrimitives.ConvertTo<NativeArgumentPassingStyle>(
|
||||
Context.GetVariableValue(s_nativeArgumentPassingVarPath, NativeArgumentPassingStyle.Standard));
|
||||
Context.GetVariableValue(SpecialVariables.NativeArgumentPassingVarPath, NativeArgumentPassingStyle.Standard));
|
||||
return preference;
|
||||
}
|
||||
catch
|
||||
|
|
|
@ -865,7 +865,7 @@ namespace System.Management.Automation
|
|||
this.commandRuntime.PipelineProcessor.ExecutionFailed = true;
|
||||
|
||||
if (!ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeCommandErrorActionPreferenceFeatureName)
|
||||
|| !(bool)Command.Context.GetVariableValue(SpecialVariables.PSNativeCommandUseErrorActionPreferenceVarPath, defaultValue: false))
|
||||
|| !Command.Context.GetBooleanPreference(SpecialVariables.PSNativeCommandUseErrorActionPreferenceVarPath, defaultPref: false, out _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -204,6 +204,7 @@ namespace System.Management.Automation
|
|||
internal static readonly VariablePath PSModuleAutoLoadingPreferenceVarPath = new VariablePath("global:" + PSModuleAutoLoading);
|
||||
|
||||
#region Platform Variables
|
||||
|
||||
internal const string IsLinux = "IsLinux";
|
||||
|
||||
internal static readonly VariablePath IsLinuxPath = new VariablePath("IsLinux");
|
||||
|
@ -221,6 +222,7 @@ namespace System.Management.Automation
|
|||
internal static readonly VariablePath IsCoreCLRPath = new VariablePath("IsCoreCLR");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preference Variables
|
||||
|
||||
internal const string DebugPreference = "DebugPreference";
|
||||
|
@ -255,13 +257,13 @@ namespace System.Management.Automation
|
|||
|
||||
internal static readonly VariablePath InformationPreferenceVarPath = new VariablePath(InformationPreference);
|
||||
|
||||
#endregion Preference Variables
|
||||
|
||||
internal const string PSNativeCommandUseErrorActionPreference = nameof(PSNativeCommandUseErrorActionPreference);
|
||||
|
||||
internal static readonly VariablePath PSNativeCommandUseErrorActionPreferenceVarPath =
|
||||
new(PSNativeCommandUseErrorActionPreference);
|
||||
|
||||
#endregion Preference Variables
|
||||
|
||||
// Native command argument passing style
|
||||
internal const string NativeArgumentPassing = "PSNativeCommandArgumentPassing";
|
||||
|
||||
|
|
|
@ -56,6 +56,19 @@ Describe 'Native command error handling tests' -Tags 'CI' {
|
|||
$stderr[1].Exception.Message | Should -BeExactly "Program `"$exeName`" ended with non-zero exit code: 1."
|
||||
}
|
||||
|
||||
It "Non-boolean value should not cause type casting error when the native command exited with non-zero code" {
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
$PSNativeCommandUseErrorActionPreference = 'Yeah'
|
||||
$PSNativeCommandUseErrorActionPreference | Should -BeExactly 'Yeah'
|
||||
|
||||
$stderr = testexe -returncode 1 2>&1
|
||||
|
||||
$error[0].FullyQualifiedErrorId | Should -BeExactly 'ProgramExitedWithNonZeroCode'
|
||||
$error[0].TargetObject | Should -BeExactly $exeName
|
||||
$stderr[1].Exception.Message | Should -BeExactly "Program `"$exeName`" ended with non-zero exit code: 1."
|
||||
}
|
||||
|
||||
It 'Non-zero exit code generates a non-teminating error for $ErrorActionPreference = ''SilentlyContinue''' {
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
|
@ -174,5 +187,18 @@ Describe 'Native command error handling tests' -Tags 'CI' {
|
|||
$LASTEXITCODE | Should -Be 1
|
||||
$Error.Count | Should -Be 0
|
||||
}
|
||||
|
||||
It "Non-boolean value should not cause type casting error when the native command exited with non-zero code" {
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
$PSNativeCommandUseErrorActionPreference = 0
|
||||
$PSNativeCommandUseErrorActionPreference | Should -Be 0
|
||||
$PSNativeCommandUseErrorActionPreference | Should -BeOfType 'System.Int32'
|
||||
|
||||
testexe -returncode 1 > $null
|
||||
|
||||
$LASTEXITCODE | Should -Be 1
|
||||
$Error.Count | Should -Be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue