Skip to content

Commit 86d7804

Browse files
Make sure ErrorRecords go to Error stream (#1201)
* make sure ErrorRecords go to Error stream * add public * add note property for pre-7 * rob feedback * use what PowerShell uses
1 parent 5ffd738 commit 86d7804

File tree

2 files changed

+28
-31
lines changed

2 files changed

+28
-31
lines changed

src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,28 @@ internal class PowerShellContextService : IDisposable, IHostSupportsInteractiveS
4141
"../../Commands/PowerShellEditorServices.Commands.psd1"));
4242

4343
private static readonly Action<Runspace, ApartmentState> s_runspaceApartmentStateSetter;
44+
private static readonly PropertyInfo s_writeStreamProperty;
45+
private static readonly object s_errorStreamValue;
4446

4547
[SuppressMessage("Performance", "CA1810:Initialize reference type static fields inline", Justification = "cctor needed for version specific initialization")]
4648
static PowerShellContextService()
4749
{
48-
// PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection
50+
// PowerShell ApartmentState APIs aren't available in PSStandard, so we need to use reflection.
4951
if (!VersionUtils.IsNetCore || VersionUtils.IsPS7OrGreater)
5052
{
5153
MethodInfo setterInfo = typeof(Runspace).GetProperty("ApartmentState").GetSetMethod();
5254
Delegate setter = Delegate.CreateDelegate(typeof(Action<Runspace, ApartmentState>), firstArgument: null, method: setterInfo);
5355
s_runspaceApartmentStateSetter = (Action<Runspace, ApartmentState>)setter;
5456
}
57+
58+
if (VersionUtils.IsPS7OrGreater)
59+
{
60+
// Used to write ErrorRecords to the Error stream. Using Public and NonPublic because the plan is to make this property
61+
// public in 7.0.1
62+
s_writeStreamProperty = typeof(PSObject).GetProperty("WriteStream", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
63+
Type writeStreamType = typeof(PSObject).Assembly.GetType("System.Management.Automation.WriteStreamType");
64+
s_errorStreamValue = Enum.Parse(writeStreamType, "Error");
65+
}
5566
}
5667

5768
#region Fields
@@ -1924,43 +1935,22 @@ internal void WriteOutput(
19241935
}
19251936
}
19261937

1927-
private void WriteExceptionToHost(Exception e)
1938+
private void WriteExceptionToHost(RuntimeException e)
19281939
{
1929-
const string ExceptionFormat =
1930-
"{0}\r\n{1}\r\n + CategoryInfo : {2}\r\n + FullyQualifiedErrorId : {3}";
1931-
1932-
if (!(e is IContainsErrorRecord containsErrorRecord) ||
1933-
containsErrorRecord.ErrorRecord == null)
1934-
{
1935-
this.WriteError(e.Message, null, 0, 0);
1936-
return;
1937-
}
1940+
var psObject = PSObject.AsPSObject(e.ErrorRecord);
19381941

1939-
ErrorRecord errorRecord = containsErrorRecord.ErrorRecord;
1940-
if (errorRecord.InvocationInfo == null)
1942+
// Used to write ErrorRecords to the Error stream so they are rendered in the console correctly.
1943+
if (VersionUtils.IsPS7OrGreater)
19411944
{
1942-
this.WriteError(errorRecord.ToString(), String.Empty, 0, 0);
1943-
return;
1945+
s_writeStreamProperty.SetValue(psObject, s_errorStreamValue);
19441946
}
1945-
1946-
string errorRecordString = errorRecord.ToString();
1947-
if ((errorRecord.InvocationInfo.PositionMessage != null) &&
1948-
errorRecordString.IndexOf(errorRecord.InvocationInfo.PositionMessage, StringComparison.Ordinal) != -1)
1947+
else
19491948
{
1950-
this.WriteError(errorRecordString);
1951-
return;
1949+
var note = new PSNoteProperty("writeErrorStream", true);
1950+
psObject.Properties.Add(note);
19521951
}
19531952

1954-
string message =
1955-
string.Format(
1956-
CultureInfo.InvariantCulture,
1957-
ExceptionFormat,
1958-
errorRecord.ToString(),
1959-
errorRecord.InvocationInfo.PositionMessage,
1960-
errorRecord.CategoryInfo,
1961-
errorRecord.FullyQualifiedErrorId);
1962-
1963-
this.WriteError(message);
1953+
ExecuteCommandAsync(new PSCommand().AddCommand("Microsoft.PowerShell.Core\\Out-Default").AddParameter("InputObject", psObject));
19641954
}
19651955

19661956
private void WriteError(

src/PowerShellEditorServices/Services/PowerShellContext/Session/Host/EditorServicesPSHostUserInterface.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,13 @@ public override void WriteWarningLine(string message)
573573
/// <param name="value"></param>
574574
public override void WriteErrorLine(string value)
575575
{
576+
// PowerShell's ConsoleHost also skips over empty lines:
577+
// https://github.com/PowerShell/PowerShell/blob/8e683972284a5a7f773ea6d027d9aac14d7e7524/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs#L1334-L1337
578+
if (string.IsNullOrEmpty(value))
579+
{
580+
return;
581+
}
582+
576583
this.WriteOutput(
577584
value,
578585
true,

0 commit comments

Comments
 (0)