diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 45fb2f591..af7856325 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -185,6 +185,8 @@ namespace System.Management.Automation //Create input writer for providing input to the process. _inputWriter = new ProcessInputWriter(Command); + + _isTranscribing = this.Command.Context.EngineHostInterface.UI.IsTranscribing; } /// @@ -373,8 +375,8 @@ namespace System.Management.Automation /// private BlockingCollection _nativeProcessOutputQueue; - private bool _scrapeHostOutput; - + private static bool? s_supportScreenScrape = null; + private bool _isTranscribing; private Host.Coordinates _startPosition; /// @@ -398,11 +400,13 @@ namespace System.Management.Automation // redirecting anything. This is a bit tricky as we always run redirected so // we have to see if the redirection is actually being done at the topmost level or not. - //Calculate if input and output are redirected. + // Calculate if input and output are redirected. bool redirectOutput; bool redirectError; bool redirectInput; + _startPosition = new Host.Coordinates(); + CalculateIORedirection(out redirectOutput, out redirectError, out redirectInput); // Find out if it's the only command in the pipeline. @@ -416,9 +420,6 @@ namespace System.Management.Automation throw new PipelineStoppedException(); } - _startPosition = new Host.Coordinates(); - _scrapeHostOutput = false; - Exception exceptionToRethrow = null; try { @@ -432,19 +433,10 @@ namespace System.Management.Automation // Also, store the Raw UI coordinates so that we can scrape the screen after // if we are transcribing. - try + if (_isTranscribing && (true == s_supportScreenScrape)) { - if (this.Command.Context.EngineHostInterface.UI.IsTranscribing) - { - _scrapeHostOutput = true; - _startPosition = this.Command.Context.EngineHostInterface.UI.RawUI.CursorPosition; - _startPosition.X = 0; - } - } - catch (Host.HostException) - { - // The host doesn't support scraping via its RawUI interface - _scrapeHostOutput = false; + _startPosition = this.Command.Context.EngineHostInterface.UI.RawUI.CursorPosition; + _startPosition.X = 0; } } @@ -697,9 +689,8 @@ namespace System.Management.Automation ConsumeAvailableNativeProcessOutput(blocking: true); _nativeProcess.WaitForExit(); - // Capture screen output if we are transcribing - if (this.Command.Context.EngineHostInterface.UI.IsTranscribing && - _scrapeHostOutput) + // Capture screen output if we are transcribing and running stand alone + if (_isTranscribing && (true == s_supportScreenScrape) && _runStandAlone) { Host.Coordinates endPosition = this.Command.Context.EngineHostInterface.UI.RawUI.CursorPosition; endPosition.X = this.Command.Context.EngineHostInterface.UI.RawUI.BufferSize.Width - 1; @@ -1287,6 +1278,33 @@ namespace System.Management.Automation } _runStandAlone = !redirectInput && !redirectOutput && !redirectError; + + if (_runStandAlone) + { + if (null == s_supportScreenScrape) + { + try + { + _startPosition = this.Command.Context.EngineHostInterface.UI.RawUI.CursorPosition; + Host.BufferCell[,] bufferContents = this.Command.Context.EngineHostInterface.UI.RawUI.GetBufferContents( + new Host.Rectangle(_startPosition, _startPosition)); + s_supportScreenScrape = true; + } + catch (Exception) + { + s_supportScreenScrape = false; + } + } + + // if screen scraping isn't supported, we enable redirection so that the output is still transcribed + // as redirected output is always transcribed + if (_isTranscribing && (false == s_supportScreenScrape)) + { + redirectOutput = true; + redirectError = true; + _runStandAlone = false; + } + } } private bool ValidateExtension(string path) diff --git a/test/powershell/Modules/Microsoft.Powershell.Host/Start-Transcript.Tests.ps1 b/test/powershell/Modules/Microsoft.Powershell.Host/Start-Transcript.Tests.ps1 index cd5907f87..2d3c28aba 100644 --- a/test/powershell/Modules/Microsoft.Powershell.Host/Start-Transcript.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.Powershell.Host/Start-Transcript.Tests.ps1 @@ -107,7 +107,7 @@ Describe "Start-Transcript, Stop-Transcript tests" -tags "CI" { ValidateTranscription -scriptToExecute $script -outputFilePath $null -expectedError $expectedError } It "Transcription should remain active if other runspace in the host get closed" { - try{ + try { $ps = [powershell]::Create() $ps.addscript("Start-Transcript -path $transcriptFilePath").Invoke() $ps.addscript('$rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace()').Invoke() @@ -115,12 +115,11 @@ Describe "Start-Transcript, Stop-Transcript tests" -tags "CI" { $ps.addscript('$rs.Dispose()').Invoke() $ps.addscript('Write-Host "After Dispose"').Invoke() $ps.addscript("Stop-Transcript").Invoke() - } finally { - if ($null -ne $ps) { - $ps.Dispose() - } + } finally { + if ($null -ne $ps) { + $ps.Dispose() } - + } Test-Path $transcriptFilePath | Should be $true $transcriptFilePath | Should contain "After Dispose" @@ -136,4 +135,15 @@ Describe "Start-Transcript, Stop-Transcript tests" -tags "CI" { $transcriptFilePath | Should contain "PowerShell transcript end" } -} \ No newline at end of file + It "Transcription should record native command output" { + $script = { + Start-Transcript -Path $transcriptFilePath + hostname + Stop-Transcript } + & $script + Test-Path $transcriptFilePath | Should be $true + + $machineName = [System.Environment]::MachineName + $transcriptFilePath | Should contain $machineName + } +} diff --git a/test/powershell/engine/Job/Jobs.Tests.ps1 b/test/powershell/engine/Job/Jobs.Tests.ps1 index 789160d6b..dd28559df 100644 --- a/test/powershell/engine/Job/Jobs.Tests.ps1 +++ b/test/powershell/engine/Job/Jobs.Tests.ps1 @@ -17,6 +17,21 @@ Describe 'Basic Job Tests' -Tags 'CI' { Receive-Job $job -wait | should be 1 } + It "Create job with native command" { + try { + $nativeJob = Start-job { powershell -c 1+1 } + $nativeJob | Wait-Job + $nativeJob.State | Should BeExactly "Completed" + $nativeJob.HasMoreData | Should Be $true + Receive-Job $nativeJob | Should BeExactly 2 + Remove-Job $nativeJob + { Get-Job $nativeJob -ErrorAction Stop } | ShouldBeErrorId "JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand" + } + finally { + Remove-Job $nativeJob -Force -ErrorAction SilentlyContinue + } + } + AfterAll { Remove-Job $job -Force }