Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ namespace Microsoft.PowerShell.Commands
[Cmdlet(VerbsCommon.Get, "Error",
HelpUri = "https://docs.microsoft.com/powershell/module/microsoft.powershell.utility/get-error?view=powershell-7&WT.mc_id=ps-gethelp",
DefaultParameterSetName = NewestParameterSetName)]
[OutputType("System.Management.Automation.ErrorRecord#PSExtendedError", "System.Exception#PSExtendedError")]
public sealed class GetErrorCommand : PSCmdlet
{
internal const string ErrorParameterSetName = "Error";
internal const string NewestParameterSetName = "Newest";
internal const string AliasNewest = "Last";
internal const string ErrorRecordPSExtendedError = "System.Management.Automation.ErrorRecord#PSExtendedError";
internal const string ExceptionPSExtendedError = "System.Exception#PSExtendedError";

/// <summary>
/// Gets or sets the error object to resolve.
Expand Down Expand Up @@ -75,11 +78,28 @@ protected override void ProcessRecord()
foreach (object errorRecord in errorRecords)
{
PSObject obj = PSObject.AsPSObject(errorRecord);
obj.TypeNames.Insert(0, "PSExtendedError");

// Remove some types so they don't get rendered by those formats
obj.TypeNames.Remove("System.Management.Automation.ErrorRecord");
obj.TypeNames.Remove("System.Exception");
if (obj.TypeNames.Contains("System.Management.Automation.ErrorRecord"))
{
if (!obj.TypeNames.Contains(ErrorRecordPSExtendedError))
{
obj.TypeNames.Insert(0, ErrorRecordPSExtendedError);

// Need to remove so this rendering doesn't take precedence as ErrorRecords is "OutOfBand"
obj.TypeNames.Remove("System.Management.Automation.ErrorRecord");
}
}

if (obj.TypeNames.Contains("System.Exception"))
{
if (!obj.TypeNames.Contains(ExceptionPSExtendedError))
{
obj.TypeNames.Insert(0, ExceptionPSExtendedError);

// Need to remove so this rendering doesn't take precedence as Exception is "OutOfBand"
obj.TypeNames.Remove("System.Exception");
}
}

if (addErrorIdentifier)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,17 @@ internal static IEnumerable<ExtendedTypeDefinition> GetFormatData()
"System.Management.Automation.ScriptBlock",
ViewsOf_System_Management_Automation_ScriptBlock());

yield return new ExtendedTypeDefinition(
"PSExtendedError",
var extendedError = new ExtendedTypeDefinition(
"System.Management.Automation.ErrorRecord#PSExtendedError",
ViewsOf_System_Management_Automation_GetError());
extendedError.TypeNames.Add("System.Exception#PSExtendedError");
yield return extendedError;

yield return new ExtendedTypeDefinition(
var errorRecord_Exception = new ExtendedTypeDefinition(
"System.Management.Automation.ErrorRecord",
ViewsOf_System_Management_Automation_ErrorRecord());
errorRecord_Exception.TypeNames.Add("System.Exception");
yield return errorRecord_Exception;

yield return new ExtendedTypeDefinition(
"System.Management.Automation.WarningRecord",
Expand All @@ -157,10 +161,6 @@ internal static IEnumerable<ExtendedTypeDefinition> GetFormatData()
"System.Management.Automation.InformationRecord",
ViewsOf_System_Management_Automation_InformationRecord());

yield return new ExtendedTypeDefinition(
"System.Exception",
ViewsOf_System_Exception());

yield return new ExtendedTypeDefinition(
"System.Management.Automation.CommandParameterSetInfo",
ViewsOf_System_Management_Automation_CommandParameterSetInfo());
Expand Down Expand Up @@ -913,6 +913,16 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Autom
$output.ToString()
}

# Add back original typename and remove PSExtendedError
if ($_.PSObject.TypeNames.Contains('System.Management.Automation.ErrorRecord#PSExtendedError')) {
$_.PSObject.TypeNames.Add('System.Management.Automation.ErrorRecord')
$null = $_.PSObject.TypeNames.Remove('System.Management.Automation.ErrorRecord#PSExtendedError')
}
elseif ($_.PSObject.TypeNames.Contains('System.Exception#PSExtendedError')) {
$_.PSObject.TypeNames.Add('System.Exception')
$null = $_.PSObject.TypeNames.Remove('System.Exception#PSExtendedError')
}

Show-ErrorRecord $_
")
.EndEntry()
Expand Down Expand Up @@ -1050,7 +1060,7 @@ function Get-ConciseViewPositionMessage {
$prefix = ''
$newline = [Environment]::Newline

if ($myinv -and $myinv.ScriptName -or $myinv.ScriptLineNumber -gt 1 -or $_.CategoryInfo.Category -eq 'ParserError') {
if ($myinv -and $myinv.ScriptName -or $myinv.ScriptLineNumber -gt 1 -or $err.CategoryInfo.Category -eq 'ParserError') {
if ($myinv.ScriptName) {
$posmsg = ""${resetcolor}$($myinv.ScriptName)${newline}""
}
Expand Down Expand Up @@ -1085,22 +1095,22 @@ function Get-ConciseViewPositionMessage {
$message = ""${prefix}${offsetWhitespace}^ ""
}

if (! $_.ErrorDetails -or ! $_.ErrorDetails.Message) {
if (! $err.ErrorDetails -or ! $err.ErrorDetails.Message) {
# we use `n instead of $newline here because that's what is in the message
if ($_.CategoryInfo.Category -eq 'ParserError' -and $_.Exception.Message.Contains(""~`n"")) {
if ($err.CategoryInfo.Category -eq 'ParserError' -and $err.Exception.Message.Contains(""~`n"")) {
# need to parse out the relevant part of the pre-rendered positionmessage
$message += $_.Exception.Message.split(""~`n"")[1].split(""${newline}${newline}"")[0]
$message += $err.Exception.Message.split(""~`n"")[1].split(""${newline}${newline}"")[0]
}
else {
$message += $_.Exception.Message
$message += $err.Exception.Message
}
}
else {
$message += $_.ErrorDetails.Message
$message += $err.ErrorDetails.Message
}

# if rendering line information, break up the message if it's wider than the console
if ($myinv -and $myinv.ScriptName -or $_.CategoryInfo.Category -eq 'ParserError') {
if ($myinv -and $myinv.ScriptName -or $err.CategoryInfo.Category -eq 'ParserError') {
$prefixLength = Get-RawStringLength -string $prefix
$prefixVtLength = $prefix.Length - $prefixLength

Expand Down Expand Up @@ -1129,7 +1139,7 @@ function Get-ConciseViewPositionMessage {
$posmsg += ""${errorColor}"" + $message

$reason = 'Error'
if ($_.Exception -and $_.Exception.WasThrownFromThrowStatement) {
if ($err.Exception -and $err.Exception.WasThrownFromThrowStatement) {
$reason = 'Exception'
}
elseif ($myinv.MyCommand) {
Expand All @@ -1138,28 +1148,35 @@ function Get-ConciseViewPositionMessage {
elseif ($myinv.InvocationName) {
$reason = $myinv.InvocationName
}
elseif ($_.CategoryInfo.Category) {
$reason = $_.CategoryInfo.Category
elseif ($err.CategoryInfo.Category) {
$reason = $err.CategoryInfo.Category
}
elseif ($_.CategoryInfo.Reason) {
$reason = $_.CategoryInfo.Reason
elseif ($err.CategoryInfo.Reason) {
$reason = $err.CategoryInfo.Reason
}

$errorMsg = 'Error'

""${errorColor}${reason}: ${posmsg}${resetcolor}""
}

if ($_.FullyQualifiedErrorId -eq 'NativeCommandErrorMessage' -or $_.FullyQualifiedErrorId -eq 'NativeCommandError') {
$_.Exception.Message
$myinv = $_.InvocationInfo
$err = $_
if (!$myinv -and $_.ErrorRecord -and $_.ErrorRecord.InvocationInfo) {
$err = $_.ErrorRecord
$myinv = $err.InvocationInfo
}

if ($err.FullyQualifiedErrorId -eq 'NativeCommandErrorMessage' -or $err.FullyQualifiedErrorId -eq 'NativeCommandError') {
$err.Exception.Message
}
else
{
$myinv = $_.InvocationInfo
$myinv = $err.InvocationInfo
if ($ErrorView -eq 'ConciseView') {
$posmsg = Get-ConciseViewPositionMessage
}
elseif ($myinv -and ($myinv.MyCommand -or ($_.CategoryInfo.Category -ne 'ParserError'))) {
elseif ($myinv -and ($myinv.MyCommand -or ($err.CategoryInfo.Category -ne 'ParserError'))) {
$posmsg = $myinv.PositionMessage
} else {
$posmsg = ''
Expand All @@ -1170,8 +1187,8 @@ function Get-ConciseViewPositionMessage {
$posmsg = ""`n"" + $posmsg
}

if ( & { Set-StrictMode -Version 1; $_.PSMessageDetails } ) {
$posmsg = ' : ' + $_.PSMessageDetails + $posmsg
if ($err.PSMessageDetails) {
$posmsg = ' : ' + $err.PSMessageDetails + $posmsg
}

if ($ErrorView -eq 'ConciseView') {
Expand All @@ -1180,23 +1197,23 @@ function Get-ConciseViewPositionMessage {

$indent = 4

$errorCategoryMsg = & { Set-StrictMode -Version 1; $_.ErrorCategory_Message }
$errorCategoryMsg = $err.ErrorCategory_Message

if ($null -ne $errorCategoryMsg)
{
$indentString = '+ CategoryInfo : ' + $_.ErrorCategory_Message
$indentString = '+ CategoryInfo : ' + $err.ErrorCategory_Message
}
else
{
$indentString = '+ CategoryInfo : ' + $_.CategoryInfo
$indentString = '+ CategoryInfo : ' + $err.CategoryInfo
}

$posmsg += ""`n"" + $indentString

$indentString = ""+ FullyQualifiedErrorId : "" + $_.FullyQualifiedErrorId
$indentString = ""+ FullyQualifiedErrorId : "" + $err.FullyQualifiedErrorId
$posmsg += ""`n"" + $indentString

$originInfo = & { Set-StrictMode -Version 1; $_.OriginInfo }
$originInfo = $err.OriginInfo

if (($null -ne $originInfo) -and ($null -ne $originInfo.PSComputerName))
{
Expand All @@ -1205,12 +1222,12 @@ function Get-ConciseViewPositionMessage {
}

if ($ErrorView -eq 'CategoryView') {
$_.CategoryInfo.GetMessage()
$err.CategoryInfo.GetMessage()
}
elseif (! $_.ErrorDetails -or ! $_.ErrorDetails.Message) {
$_.Exception.Message + $posmsg + ""`n""
elseif (! $err.ErrorDetails -or ! $err.ErrorDetails.Message) {
$err.Exception.Message + $posmsg + ""`n""
} else {
$_.ErrorDetails.Message + $posmsg
$err.ErrorDetails.Message + $posmsg
}
}
")
Expand Down Expand Up @@ -1248,16 +1265,6 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Autom
.EndControl());
}

private static IEnumerable<FormatViewDefinition> ViewsOf_System_Exception()
{
yield return new FormatViewDefinition("Exception",
CustomControl.Create(outOfBand: true)
.StartEntry()
.AddScriptBlockExpressionBinding(@"$_.Message")
.EndEntry()
.EndControl());
}

private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Automation_CommandParameterSetInfo()
{
var FmtParameterAttributes = CustomControl.Create()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ Describe 'Get-Error tests' -Tag CI {

$out = Get-Error | Out-String
$out | Should -BeLikeExactly '*InnerException*'

$err = Get-Error
$err | Should -BeOfType [System.Management.Automation.ErrorRecord]
$err.PSObject.TypeNames | Should -Not -Contain 'System.Management.Automation.ErrorRecord'
$err.PSObject.TypeNames | Should -Contain 'System.Management.Automation.ErrorRecord#PSExtendedError'

# need to exercise the formatter to validate that the internal types are removed from the error object
$null = $err | Out-String
$err | Should -BeOfType [System.Management.Automation.ErrorRecord]
$err.PSObject.TypeNames | Should -Contain 'System.Management.Automation.ErrorRecord'
$err.PSObject.TypeNames | Should -Not -Contain 'System.Management.Automation.ErrorRecord#PSExtendedError'
}

It 'Get-Error -Newest `<count>` works: <scenario>' -TestCases @(
Expand Down Expand Up @@ -80,14 +91,21 @@ Describe 'Get-Error tests' -Tag CI {
}

It 'Get-Error will handle Exceptions' {
try {
Invoke-Expression '1/d'
}
catch {
}
$e = [Exception]::new('myexception')
$error.Insert(0, $e)

$out = Get-Error | Out-String
$out | Should -BeLikeExactly '*ExpectedValueExpression*'
$out | Should -BeLikeExactly '*UnexpectedToken*'
$out | Should -BeLikeExactly '*myexception*'

$err = Get-Error
$err | Should -BeOfType [System.Exception]
$err.PSObject.TypeNames | Should -Not -Contain 'System.Exception'
$err.PSObject.TypeNames | Should -Contain 'System.Exception#PSExtendedError'

# need to exercise the formatter to validate that the internal types are removed from the error object
$null = $err | Out-String
$err | Should -BeOfType [System.Exception]
$err.PSObject.TypeNames | Should -Contain 'System.Exception'
$err.PSObject.TypeNames | Should -Not -Contain 'System.Exception#PSExtendedError'
}
}