From cbd7beded0e0e43e1d4a0973ff75946e194db351 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Wed, 19 Feb 2020 16:22:58 -0800 Subject: [PATCH 1/5] make sure ErrorRecords go to Error stream --- .../PowerShellContextService.cs | 47 +++++-------------- .../Host/EditorServicesPSHostUserInterface.cs | 7 +++ 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index b75a588ff..b746ae134 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -41,6 +41,8 @@ public class PowerShellContextService : IDisposable, IHostSupportsInteractiveSes "../../Commands/PowerShellEditorServices.Commands.psd1")); private static readonly Action s_runspaceApartmentStateSetter; + private static readonly PropertyInfo s_writeStreamProperty; + private static readonly object s_errorStreamValue; [SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline", Justification = "cctor needed for version specific initialization")] static PowerShellContextService() @@ -51,6 +53,11 @@ static PowerShellContextService() MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); Delegate setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); s_runspaceApartmentStateSetter = (Action)setter; + + // Used to write Error Views to + s_writeStreamProperty = typeof(PSObject).GetProperty("WriteStream", BindingFlags.Instance | BindingFlags.NonPublic); + Type writeStreamType = typeof(PSObject).Assembly.GetType("System.Management.Automation.WriteStreamType"); + s_errorStreamValue = Enum.Parse(writeStreamType, "Error"); } } @@ -1924,43 +1931,11 @@ internal void WriteOutput( } } - private void WriteExceptionToHost(Exception e) + private void WriteExceptionToHost(RuntimeException e) { - const string ExceptionFormat = - "{0}\r\n{1}\r\n + CategoryInfo : {2}\r\n + FullyQualifiedErrorId : {3}"; - - if (!(e is IContainsErrorRecord containsErrorRecord) || - containsErrorRecord.ErrorRecord == null) - { - this.WriteError(e.Message, null, 0, 0); - return; - } - - ErrorRecord errorRecord = containsErrorRecord.ErrorRecord; - if (errorRecord.InvocationInfo == null) - { - this.WriteError(errorRecord.ToString(), String.Empty, 0, 0); - return; - } - - string errorRecordString = errorRecord.ToString(); - if ((errorRecord.InvocationInfo.PositionMessage != null) && - errorRecordString.IndexOf(errorRecord.InvocationInfo.PositionMessage, StringComparison.Ordinal) != -1) - { - this.WriteError(errorRecordString); - return; - } - - string message = - string.Format( - CultureInfo.InvariantCulture, - ExceptionFormat, - errorRecord.ToString(), - errorRecord.InvocationInfo.PositionMessage, - errorRecord.CategoryInfo, - errorRecord.FullyQualifiedErrorId); - - this.WriteError(message); + var psObject = PSObject.AsPSObject(e.ErrorRecord); + s_writeStreamProperty.SetValue(psObject, s_errorStreamValue); + ExecuteCommandAsync(new PSCommand().AddCommand("Microsoft.PowerShell.Core\\Out-Default").AddParameter("InputObject", psObject)); } private void WriteError( diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHostUserInterface.cs b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHostUserInterface.cs index 843de0bff..3767043c4 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHostUserInterface.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHostUserInterface.cs @@ -573,6 +573,13 @@ public override void WriteWarningLine(string message) /// public override void WriteErrorLine(string value) { + // PowerShell's ConsoleHost also skips over empty lines: + // https://github.com/PowerShell/PowerShell/blob/8e683972284a5a7f773ea6d027d9aac14d7e7524/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs#L1334-L1337 + if (string.IsNullOrEmpty(value)) + { + return; + } + this.WriteOutput( value, true, From 6639bb6e9963d6dd0bfbf87406316c8a408084f7 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 20 Feb 2020 08:41:55 -0800 Subject: [PATCH 2/5] add public --- .../Services/PowerShellContext/PowerShellContextService.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index b746ae134..0f87506d2 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -47,15 +47,16 @@ public class PowerShellContextService : IDisposable, IHostSupportsInteractiveSes [SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline", Justification = "cctor needed for version specific initialization")] static PowerShellContextService() { - // PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection + // PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection. if (!VersionUtils.IsNetCore || VersionUtils.IsPS7OrGreater) { MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); Delegate setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); s_runspaceApartmentStateSetter = (Action)setter; - // Used to write Error Views to - s_writeStreamProperty = typeof(PSObject).GetProperty("WriteStream", BindingFlags.Instance | BindingFlags.NonPublic); + // Used to write ErrorRecords to the Error stream. Using Public and NonPublic because the plan is to make this property + // public in 7.0.1 + s_writeStreamProperty = typeof(PSObject).GetProperty("WriteStream", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); Type writeStreamType = typeof(PSObject).Assembly.GetType("System.Management.Automation.WriteStreamType"); s_errorStreamValue = Enum.Parse(writeStreamType, "Error"); } From cf4f7984d869b1ca34e953be4bf2dd300c387c63 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 20 Feb 2020 10:01:46 -0800 Subject: [PATCH 3/5] add note property for pre-7 --- .../PowerShellContextService.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 0f87506d2..da35dd48e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -53,7 +53,10 @@ static PowerShellContextService() MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod(); Delegate setter = Delegate.CreateDelegate(typeof(Action), firstArgument: null, method: setterInfo); s_runspaceApartmentStateSetter = (Action)setter; + } + if (VersionUtils.IsPS7OrGreater) + { // Used to write ErrorRecords to the Error stream. Using Public and NonPublic because the plan is to make this property // public in 7.0.1 s_writeStreamProperty = typeof(PSObject).GetProperty("WriteStream", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); @@ -1935,7 +1938,18 @@ internal void WriteOutput( private void WriteExceptionToHost(RuntimeException e) { var psObject = PSObject.AsPSObject(e.ErrorRecord); - s_writeStreamProperty.SetValue(psObject, s_errorStreamValue); + + // Used to write ErrorRecords to the Error stream so they are rendered in the console correctly. + if (VersionUtils.IsPS7OrGreater) + { + s_writeStreamProperty.SetValue(psObject, s_errorStreamValue); + } + else + { + var note = new PSNoteProperty("writeErrorStream", true); + psObject.Properties.Add(note); + } + ExecuteCommandAsync(new PSCommand().AddCommand("Microsoft.PowerShell.Core\\Out-Default").AddParameter("InputObject", psObject)); } From 78614319e98425e3684a1bea31d525bffa1f80d8 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 20 Feb 2020 10:24:48 -0800 Subject: [PATCH 4/5] rob feedback --- .../Services/PowerShellContext/PowerShellContextService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index da35dd48e..50600965c 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -1946,7 +1946,7 @@ private void WriteExceptionToHost(RuntimeException e) } else { - var note = new PSNoteProperty("writeErrorStream", true); + var note = new PSNoteProperty("WriteErrorStream", true); psObject.Properties.Add(note); } From afdcddfb8198a2f16961dcf50ffe4e831cf27881 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Thu, 20 Feb 2020 10:27:36 -0800 Subject: [PATCH 5/5] use what PowerShell uses --- .../Services/PowerShellContext/PowerShellContextService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs index 50600965c..da35dd48e 100644 --- a/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs +++ b/src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs @@ -1946,7 +1946,7 @@ private void WriteExceptionToHost(RuntimeException e) } else { - var note = new PSNoteProperty("WriteErrorStream", true); + var note = new PSNoteProperty("writeErrorStream", true); psObject.Properties.Add(note); }