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
26 changes: 26 additions & 0 deletions src/System.Management.Automation/engine/MshCommandRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,32 @@ internal void _WriteObjectSkipAllowCheck(object sendToPipeline)
this.OutputPipe.Add(sendToPipeline);
}

// Use this variant to write stderr as string and skip the ThrowIfWriteNotPermitted check
/// <exception cref="System.Management.Automation.PipelineStoppedException">
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
/// </exception>
internal void _WriteErrorSkipAllowCheck(object sendToPipeline)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name this WriteNativeCommandErrorSkipAllowCheck instead?

{
ThrowIfStopping();

if (AutomationNull.Value == sendToPipeline)
return;

sendToPipeline = LanguagePrimitives.AsPSObjectOrNull(sendToPipeline);

if (ErrorMergeTo != MergeDataStream.None)
{
Dbg.Assert(ErrorMergeTo == MergeDataStream.Output, "Only merging to success output is supported.");
this.OutputPipe.Add(sendToPipeline);
}
else
{
this.ErrorOutputPipe.Add(sendToPipeline);
}
}

// NOTICE-2004/06/08-JonN 959638
// Use this variant to skip the ThrowIfWriteNotPermitted check
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1032,10 +1032,8 @@ private void ProcessOutputRecord(ProcessOutputObject outputValue)

if (outputValue.Stream == MinishellStream.Error)
{
ErrorRecord record = outputValue.Data as ErrorRecord;
Dbg.Assert(record != null, "ProcessReader should ensure that data is ErrorRecord");
record.SetInvocationInfo(this.Command.MyInvocation);
this.commandRuntime._WriteErrorSkipAllowCheck(record, isNativeError: true);
// write stderr as string instead of as ErrorRecord
this.commandRuntime._WriteErrorSkipAllowCheck(outputValue.Data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outputValue.Data is still an ErrorRecord - right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, outputValue.Data is still an ErrorRecord. I'll need to rework this.

}
else if (outputValue.Stream == MinishellStream.Output)
{
Expand Down
31 changes: 13 additions & 18 deletions test/powershell/Host/ConsoleHost.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,19 @@ Describe "ConsoleHost unit tests" -tags "Feature" {
}
}

It "Verify Validate Dollar Error Populated should throw exception" {
$origEA = $ErrorActionPreference
$ErrorActionPreference = "Stop"
try
{
$a = 1,2,3
$a | & $powershell -noprofile -command { wgwg-wrwrhqwrhrh35h3h3}
Throw "Test execution should not reach here!"
}
catch
{
$_.ToString() | Should Match "wgwg-wrwrhqwrhrh35h3h3"
$_.FullyQualifiedErrorId | Should Be "CommandNotFoundException"
}
finally
{
$ErrorActionPreference = $origEA
}
It "Verify Validate Dollar Error Populated should be in stderr" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also have a test for stream redirection to output?
$err = & $powershell -noprofile -command { wgwg-wrwrhqwrhrh35h3h3} 2>&1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add that

$stderrFile = "$testdrive\stderr.txt"
& $powershell -noprofile -command { wgwg-wrwrhqwrhrh35h3h3 } 2> $stderrFile
$stderrFile | Should Exist
$stderr = Get-Content $stderrFile -Raw
$stderr | Should Match "wgwg-wrwrhqwrhrh35h3h3"
$stderr | Should Match "CommandNotFoundException"
}

It "Verify Validate Dollar Error Populated should be in stderr redirected to stdout" {
$err = & $powershell -noprofile -command { wgwg-wrwrhqwrhrh35h3h3 } 2>&1
$err.Exception.Message | Should Match "wgwg-wrwrhqwrhrh35h3h3"
$err.FullyQualifiedErrorId | Should BeExactly "CommandNotFoundException"
}

It "Verify Validate Output Format As Text Explicitly Child Single Shell should works" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Describe "Native streams behavior with PowerShell" -Tags 'CI' {
# this check should be the first one, because $error is a global shared variable
It 'should not add records to $error variable' {
# we are keeping existing Windows PS v5.1 behavior for $error variable
$error.Count | Should Be 9
$error.Count | Should Be 0
}

It 'uses ErrorRecord object to return stderr output' {
Expand Down
14 changes: 14 additions & 0 deletions test/tools/TestExe/TestExe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ static void Main(string[] args)
case "-createchildprocess":
CreateChildProcess(args);
break;
case "-echostderr":
EchoStderr(args);
break;
default:
Console.WriteLine("Unknown test {0}", args[0]);
break;
Expand All @@ -40,6 +43,17 @@ static void EchoArgs(string[] args)
}
}

// <Summary>
// Echos back to stderr the arguments passed in
// </Summary>
static void EchoStderr(string[] args)
{
for (int i = 1; i < args.Length; i++)
{
Console.Error.WriteLine("{0}", args[i]);
}
}

// <Summary>
// First argument is the number of child processes to create which are instances of itself
// Processes automatically exit after 100 seconds
Expand Down