diff --git a/src/System.Management.Automation/engine/remoting/client/Job.cs b/src/System.Management.Automation/engine/remoting/client/Job.cs index d01e555d71e..6ed148a68a2 100644 --- a/src/System.Management.Automation/engine/remoting/client/Job.cs +++ b/src/System.Management.Automation/engine/remoting/client/Job.cs @@ -3382,8 +3382,11 @@ protected void ProcessJobFailure(ExecutionCmdletHelper helper, out Exception fai fullyQualifiedErrorId, ErrorCategory.OpenError, null, null, null, null, null, errorDetails, null); } - else if (pipeline.PipelineStateInfo.State == PipelineState.Failed) + else if ((pipeline.PipelineStateInfo.State == PipelineState.Failed) || + ((pipeline.PipelineStateInfo.State == PipelineState.Stopped) && + (pipeline.PipelineStateInfo.Reason != null && !(pipeline.PipelineStateInfo.Reason is PipelineStoppedException)))) { + // Pipeline stopped state is also an error condition if the associated exception is not 'PipelineStoppedException'. object targetObject = runspace.ConnectionInfo.ComputerName; failureException = pipeline.PipelineStateInfo.Reason; if (failureException != null) @@ -3394,6 +3397,15 @@ protected void ProcessJobFailure(ExecutionCmdletHelper helper, out Exception fai if (rException != null) { errorRecord = rException.ErrorRecord; + + // A RemoteException will hide a PipelineStoppedException, which should be ignored. + if (errorRecord != null && + errorRecord.FullyQualifiedErrorId.Equals("PipelineStopped", StringComparison.OrdinalIgnoreCase)) + { + // PipelineStoppedException should not be reported as error. + failureException = null; + return; + } } else { diff --git a/test/powershell/engine/Job/Jobs.Tests.ps1 b/test/powershell/engine/Job/Jobs.Tests.ps1 index df7363b5cd3..52e1f545386 100644 --- a/test/powershell/engine/Job/Jobs.Tests.ps1 +++ b/test/powershell/engine/Job/Jobs.Tests.ps1 @@ -311,8 +311,24 @@ Describe 'Basic Job Tests' -Tags 'Feature' { @{ property = 'InstanceId'} @{ property = 'State'} ) - # '-Seconds 100' is chosen to be substantially large, so that the job is in running state when Stop-Job is called. - $jobToStop = Start-Job -ScriptBlock { Start-Sleep -Seconds 100 } -Name 'JobToStop' + } + + BeforeEach { + # 20 seconds is chosen to be large, so that the job is in running state when Stop-Job is called. + $jobToStop = Start-Job -ScriptBlock { + 1..80 | ForEach-Object { + Write-Output $_ + Start-Sleep -Milliseconds 250 + } + } -Name 'JobToStop' + # Wait until the job is actually running and executing the script + do { + $data = Receive-Job -Job $jobToStop + } while (($data.Count -eq 0) -and ($jobToStop.State -eq 'Running')) + } + + AfterEach { + Remove-Job $jobToStop -Force -ErrorAction SilentlyContinue } It 'Can Stop-Job with ' -TestCases $stopJobTestCases { @@ -321,9 +337,5 @@ Describe 'Basic Job Tests' -Tags 'Feature' { Stop-Job @splat ValidateJobInfo -job $jobToStop -state 'Stopped' -hasMoreData $false } - - AfterAll { - Remove-Job $jobToStop -Force -ErrorAction SilentlyContinue - } } }