diff --git a/ErrorView.code-workspace b/ErrorView.code-workspace
new file mode 100644
index 0000000..0f707bf
--- /dev/null
+++ b/ErrorView.code-workspace
@@ -0,0 +1,14 @@
+{
+ "folders": [
+ {
+ "name": "ErrorView",
+ "path": "."
+ },
+ {
+ "path": "../../Tasks"
+ }
+ ],
+ "settings": {
+ "powershell.cwd": "."
+ }
+}
\ No newline at end of file
diff --git a/Reference/default.ps1 b/Reference/default.ps1
new file mode 100644
index 0000000..d4f6ac8
--- /dev/null
+++ b/Reference/default.ps1
@@ -0,0 +1,335 @@
+<#
+if (@('NativeCommandErrorMessage','NativeCommandError') -notcontains $_.FullyQualifiedErrorId -and @('CategoryView','ConciseView','DetailedView') -notcontains $ErrorView)
+{
+ $myinv = $_.InvocationInfo
+ if ($myinv -and $myinv.MyCommand)
+ {
+ switch -regex ( $myinv.MyCommand.CommandType )
+ {
+ ([System.Management.Automation.CommandTypes]::ExternalScript)
+ {
+ if ($myinv.MyCommand.Path)
+ {
+ $myinv.MyCommand.Path + ' : '
+ }
+
+ break
+ }
+
+ ([System.Management.Automation.CommandTypes]::Script)
+ {
+ if ($myinv.MyCommand.ScriptBlock)
+ {
+ $myinv.MyCommand.ScriptBlock.ToString() + ' : '
+ }
+
+ break
+ }
+ default
+ {
+ if ($myinv.InvocationName -match '^[&\.]?$')
+ {
+ if ($myinv.MyCommand.Name)
+ {
+ $myinv.MyCommand.Name + ' : '
+ }
+ }
+ else
+ {
+ $myinv.InvocationName + ' : '
+ }
+
+ break
+ }
+ }
+ }
+ elseif ($myinv -and $myinv.InvocationName)
+ {
+ $myinv.InvocationName + ' : '
+ }
+}
+
+
+Set-StrictMode -Off
+$ErrorActionPreference = 'Stop'
+trap { 'Error found in error view definition: ' + $_.Exception.Message }
+$newline = [Environment]::Newline
+
+$resetColor = ''
+$errorColor = ''
+$accentColor = ''
+
+if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
+ $resetColor = $PSStyle.Reset
+ $errorColor = $PSStyle.Formatting.Error
+ $accentColor = $PSStyle.Formatting.ErrorAccent
+}
+function Get-ConciseViewPositionMessage {
+
+ # returns a string cut to last whitespace
+ function Get-TruncatedString($string, [int]$length) {
+
+ if ($string.Length -le $length) {
+ return $string
+ }
+
+ return ($string.Substring(0,$length) -split '\s',-2)[0]
+ }
+
+ $posmsg = ''
+ $headerWhitespace = ''
+ $offsetWhitespace = ''
+ $message = ''
+ $prefix = ''
+
+ # The checks here determine if we show line detailed error information:
+ # - check if `ParserError` and comes from PowerShell which eventually results in a ParseException, but during this execution it's an ErrorRecord
+ # - check if invocation is a script or multiple lines in the console
+ # - check that it's not a script module as expectation is that users don't want to see the line of error within a module
+ if ((($err.CategoryInfo.Category -eq 'ParserError' -and $err.Exception -is 'System.Management.Automation.ParentContainsErrorRecordException') -or $myinv.ScriptName -or $myinv.ScriptLineNumber -gt 1) -and $myinv.ScriptName -notmatch '\.psm1$') {
+ $useTargetObject = $false
+
+ # Handle case where there is a TargetObject and we can show the error at the target rather than the script source
+ if ($_.TargetObject.Line -and $_.TargetObject.LineText) {
+ $posmsg = "${resetcolor}$($_.TargetObject.File)${newline}"
+ $useTargetObject = $true
+ }
+ elseif ($myinv.ScriptName) {
+ if ($env:TERM_PROGRAM -eq 'vscode') {
+ # If we are running in vscode, we know the file:line:col links are clickable so we use this format
+ $posmsg = "${resetcolor}$($myinv.ScriptName):$($myinv.ScriptLineNumber):$($myinv.OffsetInLine)${newline}"
+ }
+ else {
+ $posmsg = "${resetcolor}$($myinv.ScriptName):$($myinv.ScriptLineNumber)${newline}"
+ }
+ }
+ else {
+ $posmsg = "${newline}"
+ }
+
+ if ($useTargetObject) {
+ $scriptLineNumber = $_.TargetObject.Line
+ $scriptLineNumberLength = $_.TargetObject.Line.ToString().Length
+ }
+ else {
+ $scriptLineNumber = $myinv.ScriptLineNumber
+ $scriptLineNumberLength = $myinv.ScriptLineNumber.ToString().Length
+ }
+
+ if ($scriptLineNumberLength -gt 4) {
+ $headerWhitespace = ' ' * ($scriptLineNumberLength - 4)
+ }
+
+ $lineWhitespace = ''
+ if ($scriptLineNumberLength -lt 4) {
+ $lineWhitespace = ' ' * (4 - $scriptLineNumberLength)
+ }
+
+ $verticalBar = '|'
+ $posmsg += "${accentColor}${headerWhitespace}Line ${verticalBar}${newline}"
+
+ $highlightLine = ''
+ if ($useTargetObject) {
+ $line = $_.TargetObject.LineText.Trim()
+ $offsetLength = 0
+ $offsetInLine = 0
+ }
+ else {
+ $positionMessage = $myinv.PositionMessage.Split($newline)
+ $line = $positionMessage[1].Substring(1) # skip the '+' at the start
+ $highlightLine = $positionMessage[$positionMessage.Count - 1].Substring(1)
+ $offsetLength = $highlightLine.Trim().Length
+ $offsetInLine = $highlightLine.IndexOf('~')
+ }
+
+ if (-not $line.EndsWith($newline)) {
+ $line += $newline
+ }
+
+ # don't color the whole line
+ if ($offsetLength -lt $line.Length - 1) {
+ $line = $line.Insert($offsetInLine + $offsetLength, $resetColor).Insert($offsetInLine, $accentColor)
+ }
+
+ $posmsg += "${accentColor}${lineWhitespace}${ScriptLineNumber} ${verticalBar} ${resetcolor}${line}"
+ $offsetWhitespace = ' ' * $offsetInLine
+ $prefix = "${accentColor}${headerWhitespace} ${verticalBar} ${errorColor}"
+ if ($highlightLine -ne '') {
+ $posMsg += "${prefix}${highlightLine}${newline}"
+ }
+ $message = "${prefix}"
+ }
+
+ if (! $err.ErrorDetails -or ! $err.ErrorDetails.Message) {
+ if ($err.CategoryInfo.Category -eq 'ParserError' -and $err.Exception.Message.Contains("~$newline")) {
+ # need to parse out the relevant part of the pre-rendered positionmessage
+ $message += $err.Exception.Message.split("~$newline")[1].split("${newline}${newline}")[0]
+ }
+ elseif ($err.Exception) {
+ $message += $err.Exception.Message
+ }
+ elseif ($err.Message) {
+ $message += $err.Message
+ }
+ else {
+ $message += $err.ToString()
+ }
+ }
+ else {
+ $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 $err.CategoryInfo.Category -eq 'ParserError') {
+ $prefixLength = "$([char]27)]8;;{0}`a{1}$([char]27)]8;;`a" -f $pwd, $pwd::new($prefix).ContentLength
+ $prefixVtLength = $prefix.Length - $prefixLength
+
+ # replace newlines in message so it lines up correct
+ $message = $message.Replace($newline, ' ').Replace("`n", ' ').Replace("`t", ' ')
+
+ $windowWidth = 120
+ if ($Host.UI.RawUI -ne $null) {
+ $windowWidth = $Host.UI.RawUI.WindowSize.Width
+ }
+
+ if ($windowWidth -gt 0 -and ($message.Length - $prefixVTLength) -gt $windowWidth) {
+ $sb = [Text.StringBuilder]::new()
+ $substring = Get-TruncatedString -string $message -length ($windowWidth + $prefixVTLength)
+ $null = $sb.Append($substring)
+ $remainingMessage = $message.Substring($substring.Length).Trim()
+ $null = $sb.Append($newline)
+ while (($remainingMessage.Length + $prefixLength) -gt $windowWidth) {
+ $subMessage = $prefix + $remainingMessage
+ $substring = Get-TruncatedString -string $subMessage -length ($windowWidth + $prefixVtLength)
+
+ if ($substring.Length - $prefix.Length -gt 0)
+ {
+ $null = $sb.Append($substring)
+ $null = $sb.Append($newline)
+ $remainingMessage = $remainingMessage.Substring($substring.Length - $prefix.Length).Trim()
+ }
+ else
+ {
+ break
+ }
+ }
+ $null = $sb.Append($prefix + $remainingMessage.Trim())
+ $message = $sb.ToString()
+ }
+
+ $message += $newline
+ }
+
+ $posmsg += "${errorColor}" + $message
+
+ $reason = 'Error'
+ if ($err.Exception -and $err.Exception.WasThrownFromThrowStatement) {
+ $reason = 'Exception'
+ }
+ # MyCommand can be the script block, so we don't want to show that so check if it's an actual command
+ elseif ($myinv.MyCommand -and $myinv.MyCommand.Name -and (Get-Command -Name $myinv.MyCommand -ErrorAction Ignore))
+ {
+ $reason = $myinv.MyCommand
+ }
+ # If it's a scriptblock, better to show the command in the scriptblock that had the error
+ elseif ($_.CategoryInfo.Activity) {
+ $reason = $_.CategoryInfo.Activity
+ }
+ elseif ($myinv.MyCommand) {
+ $reason = $myinv.MyCommand
+ }
+ elseif ($myinv.InvocationName) {
+ $reason = $myinv.InvocationName
+ }
+ elseif ($err.CategoryInfo.Category) {
+ $reason = $err.CategoryInfo.Category
+ }
+ elseif ($err.CategoryInfo.Reason) {
+ $reason = $err.CategoryInfo.Reason
+ }
+
+ $errorMsg = 'Error'
+
+ "${errorColor}${reason}: ${posmsg}${resetcolor}"
+}
+
+$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') {
+ return "${errorColor}$($err.Exception.Message)${resetcolor}"
+}
+
+$myinv = $err.InvocationInfo
+if ($ErrorView -eq 'DetailedView') {
+ $message = Get-Error
+ return "${errorColor}${message}${resetcolor}"
+}
+
+if ($ErrorView -eq 'CategoryView') {
+ $message = $err.CategoryInfo.GetMessage()
+ return "${errorColor}${message}${resetcolor}"
+}
+
+$posmsg = ''
+if ($ErrorView -eq 'ConciseView') {
+ $posmsg = Get-ConciseViewPositionMessage
+}
+elseif ($myinv -and ($myinv.MyCommand -or ($err.CategoryInfo.Category -ne 'ParserError'))) {
+ $posmsg = $myinv.PositionMessage
+}
+
+if ($posmsg -ne '') {
+ $posmsg = $newline + $posmsg
+}
+
+if ($err.PSMessageDetails) {
+ $posmsg = ' : ' + $err.PSMessageDetails + $posmsg
+}
+
+if ($ErrorView -eq 'ConciseView') {
+ if ($err.PSMessageDetails) {
+ $posmsg = "${errorColor}${posmsg}"
+ }
+ return $posmsg
+}
+
+$indent = 4
+
+$errorCategoryMsg = $err.ErrorCategory_Message
+
+if ($null -ne $errorCategoryMsg)
+{
+ $indentString = '+ CategoryInfo : ' + $err.ErrorCategory_Message
+}
+else
+{
+ $indentString = '+ CategoryInfo : ' + $err.CategoryInfo
+}
+
+$posmsg += $newline + $indentString
+
+$indentString = "+ FullyQualifiedErrorId : " + $err.FullyQualifiedErrorId
+$posmsg += $newline + $indentString
+
+$originInfo = $err.OriginInfo
+
+if (($null -ne $originInfo) -and ($null -ne $originInfo.PSComputerName))
+{
+ $indentString = "+ PSComputerName : " + $originInfo.PSComputerName
+ $posmsg += $newline + $indentString
+}
+
+$finalMsg = if ($err.ErrorDetails.Message) {
+ $err.ErrorDetails.Message + $posmsg
+} else {
+ $err.Exception.Message + $posmsg
+}
+
+"${errorColor}${finalMsg}${resetcolor}"
+
+#>
\ No newline at end of file
diff --git a/Reference/detail copy.ps1 b/Reference/detail copy.ps1
new file mode 100644
index 0000000..79e9c36
--- /dev/null
+++ b/Reference/detail copy.ps1
@@ -0,0 +1,183 @@
+<#
+[int]$maxDepth = 10
+Set-StrictMode -Off
+
+$ellipsis = "`u{2026}"
+$resetColor = ''
+$errorColor = ''
+$accentColor = ''
+
+if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
+ $resetColor = $PSStyle.Reset
+ $errorColor = $psstyle.Formatting.Error
+ $accentColor = $PSStyle.Formatting.FormatAccent
+}
+
+function Show-ErrorRecord($obj, [int]$indent = 0, [int]$depth = 1) {
+ $newline = [Environment]::Newline
+ $output = [System.Text.StringBuilder]::new()
+ $prefix = ' ' * $indent
+
+ $expandTypes = @(
+ 'Microsoft.Rest.HttpRequestMessageWrapper'
+ 'Microsoft.Rest.HttpResponseMessageWrapper'
+ 'System.Management.Automation.InvocationInfo'
+ )
+
+ # if object is an Exception, add an ExceptionType property
+ if ($obj -is [Exception]) {
+ $obj | Add-Member -NotePropertyName Type -NotePropertyValue $obj.GetType().FullName -ErrorAction Ignore
+ }
+
+ # first find the longest property so we can indent properly
+ $propLength = 0
+ foreach ($prop in $obj.PSObject.Properties) {
+ if ($prop.Value -ne $null -and $prop.Value -ne [string]::Empty -and $prop.Name.Length -gt $propLength) {
+ $propLength = $prop.Name.Length
+ }
+ }
+
+ $addedProperty = $false
+ foreach ($prop in $obj.PSObject.Properties) {
+
+ # don't show empty properties or our added property for $error[index]
+ if ($prop.Value -ne $null -and $prop.Value -ne [string]::Empty -and $prop.Value.count -gt 0 -and $prop.Name -ne 'PSErrorIndex') {
+ $addedProperty = $true
+ $null = $output.Append($prefix)
+ $null = $output.Append($accentColor)
+ $null = $output.Append($prop.Name)
+ $propNameIndent = ' ' * ($propLength - $prop.Name.Length)
+ $null = $output.Append($propNameIndent)
+ $null = $output.Append(' : ')
+ $null = $output.Append($resetColor)
+
+ $newIndent = $indent + 4
+
+ # only show nested objects that are Exceptions, ErrorRecords, or types defined in $expandTypes and types not in $ignoreTypes
+ if ($prop.Value -is [Exception] -or $prop.Value -is [System.Management.Automation.ErrorRecord] -or
+ $expandTypes -contains $prop.TypeNameOfValue -or ($prop.TypeNames -ne $null -and $expandTypes -contains $prop.TypeNames[0])) {
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $null = $output.Append($newline)
+ $null = $output.Append((Show-ErrorRecord $prop.Value $newIndent ($depth + 1)))
+ }
+ }
+ # `TargetSite` has many members that are not useful visually, so we have a reduced view of the relevant members
+ elseif ($prop.Name -eq 'TargetSite' -and $prop.Value.GetType().Name -eq 'RuntimeMethodInfo') {
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $targetSite = [PSCustomObject]@{
+ Name = $prop.Value.Name
+ DeclaringType = $prop.Value.DeclaringType
+ MemberType = $prop.Value.MemberType
+ Module = $prop.Value.Module
+ }
+
+ $null = $output.Append($newline)
+ $null = $output.Append((Show-ErrorRecord $targetSite $newIndent ($depth + 1)))
+ }
+ }
+ # `StackTrace` is handled specifically because the lines are typically long but necessary so they are left justified without additional indentation
+ elseif ($prop.Name -eq 'StackTrace') {
+ # for a stacktrace which is usually quite wide with info, we left justify it
+ $null = $output.Append($newline)
+ $null = $output.Append($prop.Value)
+ }
+ # Dictionary and Hashtable we want to show as Key/Value pairs, we don't do the extra whitespace alignment here
+ elseif ($prop.Value.GetType().Name.StartsWith('Dictionary') -or $prop.Value.GetType().Name -eq 'Hashtable') {
+ $isFirstElement = $true
+ foreach ($key in $prop.Value.Keys) {
+ if ($isFirstElement) {
+ $null = $output.Append($newline)
+ }
+
+ if ($key -eq 'Authorization') {
+ $null = $output.Append("${prefix} ${accentColor}${key} : ${resetColor}${ellipsis}${newline}")
+ }
+ else {
+ $null = $output.Append("${prefix} ${accentColor}${key} : ${resetColor}$($prop.Value[$key])${newline}")
+ }
+
+ $isFirstElement = $false
+ }
+ }
+ # if the object implements IEnumerable and not a string, we try to show each object
+ # We ignore the `Data` property as it can contain lots of type information by the interpreter that isn't useful here
+ elseif (!($prop.Value -is [System.String]) -and $prop.Value.GetType().GetInterface('IEnumerable') -ne $null -and $prop.Name -ne 'Data') {
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $isFirstElement = $true
+ foreach ($value in $prop.Value) {
+ $null = $output.Append($newline)
+ if (!$isFirstElement) {
+ $null = $output.Append($newline)
+ }
+ $null = $output.Append((Show-ErrorRecord $value $newIndent ($depth + 1)))
+ $isFirstElement = $false
+ }
+ }
+ }
+ # Anything else, we convert to string.
+ # ToString() can throw so we use LanguagePrimitives.TryConvertTo() to hide a convert error
+ else {
+ $value = $null
+ if ([System.Management.Automation.LanguagePrimitives]::TryConvertTo($prop.Value, [string], [ref]$value) -and $value -ne $null)
+ {
+ if ($prop.Name -eq 'PositionMessage') {
+ $value = $value.Insert($value.IndexOf('~'), $errorColor)
+ }
+ elseif ($prop.Name -eq 'Message') {
+ $value = $errorColor + $value
+ }
+
+ $isFirstLine = $true
+ if ($value.Contains($newline)) {
+ # the 3 is to account for ' : '
+ $valueIndent = ' ' * ($propLength + 3)
+ # need to trim any extra whitespace already in the text
+ foreach ($line in $value.Split($newline)) {
+ if (!$isFirstLine) {
+ $null = $output.Append("${newline}${prefix}${valueIndent}")
+ }
+ $null = $output.Append($line.Trim())
+ $isFirstLine = $false
+ }
+ }
+ else {
+ $null = $output.Append($value)
+ }
+ }
+ }
+
+ $null = $output.Append($newline)
+ }
+ }
+
+ # if we had added nested properties, we need to remove the last newline
+ if ($addedProperty) {
+ $null = $output.Remove($output.Length - $newline.Length, $newline.Length)
+ }
+
+ $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 $_
+#>
\ No newline at end of file
diff --git a/Reference/detail.ps1 b/Reference/detail.ps1
new file mode 100644
index 0000000..79e9c36
--- /dev/null
+++ b/Reference/detail.ps1
@@ -0,0 +1,183 @@
+<#
+[int]$maxDepth = 10
+Set-StrictMode -Off
+
+$ellipsis = "`u{2026}"
+$resetColor = ''
+$errorColor = ''
+$accentColor = ''
+
+if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
+ $resetColor = $PSStyle.Reset
+ $errorColor = $psstyle.Formatting.Error
+ $accentColor = $PSStyle.Formatting.FormatAccent
+}
+
+function Show-ErrorRecord($obj, [int]$indent = 0, [int]$depth = 1) {
+ $newline = [Environment]::Newline
+ $output = [System.Text.StringBuilder]::new()
+ $prefix = ' ' * $indent
+
+ $expandTypes = @(
+ 'Microsoft.Rest.HttpRequestMessageWrapper'
+ 'Microsoft.Rest.HttpResponseMessageWrapper'
+ 'System.Management.Automation.InvocationInfo'
+ )
+
+ # if object is an Exception, add an ExceptionType property
+ if ($obj -is [Exception]) {
+ $obj | Add-Member -NotePropertyName Type -NotePropertyValue $obj.GetType().FullName -ErrorAction Ignore
+ }
+
+ # first find the longest property so we can indent properly
+ $propLength = 0
+ foreach ($prop in $obj.PSObject.Properties) {
+ if ($prop.Value -ne $null -and $prop.Value -ne [string]::Empty -and $prop.Name.Length -gt $propLength) {
+ $propLength = $prop.Name.Length
+ }
+ }
+
+ $addedProperty = $false
+ foreach ($prop in $obj.PSObject.Properties) {
+
+ # don't show empty properties or our added property for $error[index]
+ if ($prop.Value -ne $null -and $prop.Value -ne [string]::Empty -and $prop.Value.count -gt 0 -and $prop.Name -ne 'PSErrorIndex') {
+ $addedProperty = $true
+ $null = $output.Append($prefix)
+ $null = $output.Append($accentColor)
+ $null = $output.Append($prop.Name)
+ $propNameIndent = ' ' * ($propLength - $prop.Name.Length)
+ $null = $output.Append($propNameIndent)
+ $null = $output.Append(' : ')
+ $null = $output.Append($resetColor)
+
+ $newIndent = $indent + 4
+
+ # only show nested objects that are Exceptions, ErrorRecords, or types defined in $expandTypes and types not in $ignoreTypes
+ if ($prop.Value -is [Exception] -or $prop.Value -is [System.Management.Automation.ErrorRecord] -or
+ $expandTypes -contains $prop.TypeNameOfValue -or ($prop.TypeNames -ne $null -and $expandTypes -contains $prop.TypeNames[0])) {
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $null = $output.Append($newline)
+ $null = $output.Append((Show-ErrorRecord $prop.Value $newIndent ($depth + 1)))
+ }
+ }
+ # `TargetSite` has many members that are not useful visually, so we have a reduced view of the relevant members
+ elseif ($prop.Name -eq 'TargetSite' -and $prop.Value.GetType().Name -eq 'RuntimeMethodInfo') {
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $targetSite = [PSCustomObject]@{
+ Name = $prop.Value.Name
+ DeclaringType = $prop.Value.DeclaringType
+ MemberType = $prop.Value.MemberType
+ Module = $prop.Value.Module
+ }
+
+ $null = $output.Append($newline)
+ $null = $output.Append((Show-ErrorRecord $targetSite $newIndent ($depth + 1)))
+ }
+ }
+ # `StackTrace` is handled specifically because the lines are typically long but necessary so they are left justified without additional indentation
+ elseif ($prop.Name -eq 'StackTrace') {
+ # for a stacktrace which is usually quite wide with info, we left justify it
+ $null = $output.Append($newline)
+ $null = $output.Append($prop.Value)
+ }
+ # Dictionary and Hashtable we want to show as Key/Value pairs, we don't do the extra whitespace alignment here
+ elseif ($prop.Value.GetType().Name.StartsWith('Dictionary') -or $prop.Value.GetType().Name -eq 'Hashtable') {
+ $isFirstElement = $true
+ foreach ($key in $prop.Value.Keys) {
+ if ($isFirstElement) {
+ $null = $output.Append($newline)
+ }
+
+ if ($key -eq 'Authorization') {
+ $null = $output.Append("${prefix} ${accentColor}${key} : ${resetColor}${ellipsis}${newline}")
+ }
+ else {
+ $null = $output.Append("${prefix} ${accentColor}${key} : ${resetColor}$($prop.Value[$key])${newline}")
+ }
+
+ $isFirstElement = $false
+ }
+ }
+ # if the object implements IEnumerable and not a string, we try to show each object
+ # We ignore the `Data` property as it can contain lots of type information by the interpreter that isn't useful here
+ elseif (!($prop.Value -is [System.String]) -and $prop.Value.GetType().GetInterface('IEnumerable') -ne $null -and $prop.Name -ne 'Data') {
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ }
+ else {
+ $isFirstElement = $true
+ foreach ($value in $prop.Value) {
+ $null = $output.Append($newline)
+ if (!$isFirstElement) {
+ $null = $output.Append($newline)
+ }
+ $null = $output.Append((Show-ErrorRecord $value $newIndent ($depth + 1)))
+ $isFirstElement = $false
+ }
+ }
+ }
+ # Anything else, we convert to string.
+ # ToString() can throw so we use LanguagePrimitives.TryConvertTo() to hide a convert error
+ else {
+ $value = $null
+ if ([System.Management.Automation.LanguagePrimitives]::TryConvertTo($prop.Value, [string], [ref]$value) -and $value -ne $null)
+ {
+ if ($prop.Name -eq 'PositionMessage') {
+ $value = $value.Insert($value.IndexOf('~'), $errorColor)
+ }
+ elseif ($prop.Name -eq 'Message') {
+ $value = $errorColor + $value
+ }
+
+ $isFirstLine = $true
+ if ($value.Contains($newline)) {
+ # the 3 is to account for ' : '
+ $valueIndent = ' ' * ($propLength + 3)
+ # need to trim any extra whitespace already in the text
+ foreach ($line in $value.Split($newline)) {
+ if (!$isFirstLine) {
+ $null = $output.Append("${newline}${prefix}${valueIndent}")
+ }
+ $null = $output.Append($line.Trim())
+ $isFirstLine = $false
+ }
+ }
+ else {
+ $null = $output.Append($value)
+ }
+ }
+ }
+
+ $null = $output.Append($newline)
+ }
+ }
+
+ # if we had added nested properties, we need to remove the last newline
+ if ($addedProperty) {
+ $null = $output.Remove($output.Length - $newline.Length, $newline.Length)
+ }
+
+ $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 $_
+#>
\ No newline at end of file
diff --git a/source/ErrorView.format.ps1xml b/source/ErrorView.format.ps1xml
index 443e23a..028b7b5 100644
--- a/source/ErrorView.format.ps1xml
+++ b/source/ErrorView.format.ps1xml
@@ -68,5 +68,35 @@
+
+ InformationRecord
+
+
+ System.Management.Automation.InformationRecord
+
+
+
+
+
+
+
+ $_.MessageData | Format-List * | Out-String
+
+
+
+
+ "Tags: " + @($_.Tags -join ", ")
+
+
+
+
+ $_ | Select-Object * -ExcludeProperty Tags, MessageData | Format-List * -Force | Out-String
+
+
+
+
+
+
+
diff --git a/source/prefix.ps1 b/source/prefix.ps1
index 9f73337..aef18c4 100644
--- a/source/prefix.ps1
+++ b/source/prefix.ps1
@@ -1,8 +1,53 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'ErrorView is all about the ErrorView global variable')]
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Seriously. Stop complaining about ErrorView')]
param(
$global:ErrorView = "Simple"
)
# We need to _overwrite_ the ErrorView
# So -PrependPath, instead of FormatsToProcess
-Update-FormatData -PrependPath $PSScriptRoot\ErrorView.format.ps1xml
\ No newline at end of file
+Update-FormatData -PrependPath $PSScriptRoot\ErrorView.format.ps1xml
+
+Set-StrictMode -Off
+
+# Borrowed this one from https://github.com/chalk/ansi-regex
+$script:AnsiEscapes = [Regex]::new("([\u001b\u009b][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?(?:\u001b\u005c|\u0007))|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~])))", "Compiled");
+
+# starting with an escape character and then...
+# ESC ] - where ST is either 1B 5C or 7 (BEL, aka `a)
+# ESC [ non-letters letter (or ~, =, @, >)
+# ESC (
+# ESC O P
+# ESC O Q
+# ESC O R
+# ESC O S
+# $script:AnsiEscapes = [Regex]::new("\x1b[\(\)%`"&\.\/*+.-][@-Z]|\x1b\].*?(?:\u001b\u005c|\u0007|^)|\x1b\[\P{L}*[@-_A-Za-z^`\{\|\}~]|\x1b#\d|\x1b[!-~]", [System.Text.RegularExpressions.RegexOptions]::Compiled);
+
+
+
+
+
+$script:ellipsis = [char]0x2026
+$script:newline = [Environment]::Newline
+$script:resetColor = ''
+$script:errorColor = ''
+$script:accentColor = ''
+$script:errorAccentColor = ''
+$script:LineColors = @(
+ "`e[38;2;255;255;255m"
+ "`e[38;2;179;179;179m"
+)
+
+if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
+ if ($PSStyle) {
+ $script:resetColor = $PSStyle.Reset
+ $script:errorColor = $PSStyle.Formatting.Error
+ $script:accentColor = $PSStyle.Formatting.FormatAccent
+ $script:errorAccentColor = $PSStyle.Formatting.ErrorAccent
+ } else {
+ $script:resetColor = "$([char]27)[0m"
+ $script:errorColor = "$([char]27)[31m"
+ $script:accentColor = "$([char]27)[32;1m"
+ $script:errorAccentColor = "$([char]27)[31;1m"
+ }
+}
\ No newline at end of file
diff --git a/source/private/GetListRecursive.ps1 b/source/private/GetListRecursive.ps1
new file mode 100644
index 0000000..a6cdd05
--- /dev/null
+++ b/source/private/GetListRecursive.ps1
@@ -0,0 +1,160 @@
+function GetListRecursive {
+ <#
+ .SYNOPSIS
+ Internal implementation of the Detailed error view to support recursion and indentation
+ #>
+ [CmdletBinding()]
+ param(
+ $InputObject,
+ [int]$indent = 0,
+ [int]$depth = 1
+ )
+ Write-Information "ENTER GetListRecursive END $($InputObject.GetType().FullName) $indent $depth" -Tags 'Trace', 'Enter', 'GetListRecursive'
+ Write-Information (Get-PSCallStack) -Tags 'Trace', 'StackTrace', 'GetListRecursive'
+ $output = [System.Text.StringBuilder]::new()
+ $prefix = ' ' * $indent
+
+ $expandTypes = @(
+ 'Microsoft.Rest.HttpRequestMessageWrapper'
+ 'Microsoft.Rest.HttpResponseMessageWrapper'
+ 'System.Management.Automation.InvocationInfo'
+ )
+
+ # The built-in DetailedView aligns all the ":" characters, so we need to find the longest property name
+ $propLength = 0
+ foreach ($prop in $InputObject.PSObject.Properties) {
+ if ($null -ne $prop.Value -and $prop.Value -ne [string]::Empty -and $prop.Name.Length -gt $propLength) {
+ $propLength = $prop.Name.Length
+ }
+ }
+
+ $addedProperty = $false
+ foreach ($prop in $InputObject.PSObject.Properties) {
+ # don't show empty properties or our added property for $error[index]
+ if ($null -ne $prop.Value -and $prop.Value -ne [string]::Empty -and $prop.Value.count -gt 0 -and $prop.Name -ne 'PSErrorIndex') {
+ $addedProperty = $true
+ $null = $output.Append($prefix)
+ $null = $output.Append($accentColor)
+ $null = $output.Append($prop.Name)
+ $null = $output.Append(' ',($propLength - $prop.Name.Length))
+ $null = $output.Append(' : ')
+ $null = $output.Append($resetColor)
+
+ $newIndent = $indent + 2
+
+ # only show nested objects that are Exceptions, ErrorRecords, or types defined in $expandTypes and types not in $ignoreTypes
+ if ($prop.Value -is [Exception] -or
+ $prop.Value -is [System.Management.Automation.ErrorRecord] -or
+ $expandTypes -contains $prop.TypeNameOfValue -or
+ ($null -ne $prop.TypeNames -and $expandTypes -contains $prop.TypeNames[0])) {
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ } else {
+ if ($prop.Value -is [Exception]) {
+ $null = $output.Append($newline)
+ $null = $output.Append((
+ GetListRecursive ([PSCustomObject]@{
+ "Type" = $errorAccentColor + $prop.Value.GetType().FullName + $resetColor
+ }) $newIndent ($depth + 1)
+ ))
+ }
+ $null = $output.Append($newline)
+ $null = $output.Append((GetListRecursive $prop.Value $newIndent ($depth + 1)))
+ }
+ } elseif ($prop.Name -eq 'TargetSite' -and $prop.Value.GetType().Name -eq 'RuntimeMethodInfo') {
+ # `TargetSite` has many members that are not useful visually, so we have a reduced view of the relevant members
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ } else {
+ $targetSite = [PSCustomObject]@{
+ Name = $prop.Value.Name
+ DeclaringType = $prop.Value.DeclaringType
+ MemberType = $prop.Value.MemberType
+ Module = $prop.Value.Module
+ }
+
+ $null = $output.Append($newline)
+ $null = $output.Append((GetListRecursive $targetSite $newIndent ($depth + 1)))
+ }
+ } elseif ($prop.Name -eq 'StackTrace') {
+ # `StackTrace` is handled specifically because the lines are typically long but necessary so they are left justified without additional indentation
+ # for a stacktrace which is usually quite wide with info, we left justify it
+ $null = $output.Append($newline)
+ $null = $output.Append($prop.Value)
+ } elseif ($prop.Value.GetType().Name.StartsWith('Dictionary') -or $prop.Value.GetType().Name -eq 'Hashtable') {
+ # Dictionary and Hashtable we want to show as Key/Value pairs, we don't do the extra whitespace alignment here
+ $isFirstElement = $true
+ foreach ($key in $prop.Value.Keys) {
+ if ($isFirstElement) {
+ $null = $output.Append($newline)
+ }
+
+ if ($key -eq 'Authorization') {
+ $null = $output.Append("${prefix} ${accentColor}${key}: ${resetColor}${ellipsis}${newline}")
+ } else {
+ $null = $output.Append("${prefix} ${accentColor}${key}: ${resetColor}$($prop.Value[$key])${newline}")
+ }
+
+ $isFirstElement = $false
+ }
+ } elseif (!($prop.Value -is [System.String]) -and $null -ne $prop.Value.GetType().GetInterface('IEnumerable') -and $prop.Name -ne 'Data') {
+ # if the object implements IEnumerable and not a string, we try to show each object
+ # We ignore the `Data` property as it can contain lots of type information by the interpreter that isn't useful here
+
+ if ($depth -ge $maxDepth) {
+ $null = $output.Append($ellipsis)
+ } else {
+ $isFirstElement = $true
+ foreach ($value in $prop.Value) {
+ $null = $output.Append($newline)
+ if (!$isFirstElement) {
+ $null = $output.Append($newline)
+ }
+ $null = $output.Append((GetListRecursive $value $newIndent ($depth + 1)))
+ $isFirstElement = $false
+ }
+ }
+ } else {
+ # Anything else, we convert to string.
+ # ToString() can throw so we use LanguagePrimitives.TryConvertTo() to hide a convert error
+ $value = $null
+ if ([System.Management.Automation.LanguagePrimitives]::TryConvertTo($prop.Value, [string], [ref]$value) -and $null -ne $value) {
+ $value = $value.Trim()
+ if ($prop.Name -eq 'PositionMessage') {
+ $value = $value.Insert($value.IndexOf('~'), $errorColor)
+ } elseif ($prop.Name -eq 'Message') {
+ $value = $errorColor + $value
+ }
+
+ $isFirstLine = $true
+ if ($value.Contains($newline)) {
+ # the 3 is to account for ' : '
+ # $valueIndent = ' ' * ($prop.Name.Length + 2)
+ $valueIndent = ' ' * ($propLength + 3)
+ # need to trim any extra whitespace already in the text
+ foreach ($line in $value.Split($newline)) {
+ if (!$isFirstLine) {
+ $null = $output.Append("${newline}${prefix}${valueIndent}")
+ }
+ $null = $output.Append($line.Trim())
+ $isFirstLine = $false
+ }
+ } else {
+ $null = $output.Append($value)
+ }
+ }
+ }
+
+ $null = $output.Append($newline)
+ }
+ }
+
+ # if we had added nested properties, we need to remove the last newline
+ if ($addedProperty) {
+ $null = $output.Remove($output.Length - $newline.Length, $newline.Length)
+ }
+
+ $output.ToString()
+ Write-Information "EXIT GetListRecursive END $($InputObject.GetType().FullName) $indent $depth (of $maxDepth)" -Tags 'Trace', 'Enter', 'GetListRecursive'
+}
diff --git a/source/private/GetYamlRecursive.ps1 b/source/private/GetYamlRecursive.ps1
new file mode 100644
index 0000000..ac3880e
--- /dev/null
+++ b/source/private/GetYamlRecursive.ps1
@@ -0,0 +1,169 @@
+function GetYamlRecursive {
+ <#
+ .SYNOPSIS
+ Creates a description of an ErrorRecord that looks like valid Yaml
+ .DESCRIPTION
+ This produces valid Yaml output from ErrorRecord you pass to it, recursively.
+ #>
+ [CmdletBinding()]
+ param(
+ # The object that you want to convert to YAML
+ [Parameter(Mandatory, ValueFromPipeline)]
+ $InputObject,
+
+ # Optionally, a limit on the depth to recurse properties (defaults to 16)
+ [parameter()]
+ [int]$depth = 16,
+
+ # If set, include empty and null properties in the output
+ [switch]$IncludeEmpty,
+
+ # Recursive use only. Handles indentation for formatting
+ [parameter(DontShow)]
+ [int]$NestingLevel = 0,
+
+ # use OuterXml instead of treating XmlDocuments like objects
+ [parameter(DontShow)]
+ [switch]$XmlAsXml
+ )
+ process {
+ $wrap = [Console]::BufferWidth - 1 - ($NestingLevel * 2)
+ @(
+ if ($Null -eq $InputObject) { return 'null' } # if it is null return null
+ if ($NestingLevel -eq 0 -and $local:__hasoutput) { '---' } # if we have output before, add a yaml separator
+ $__hasoutput = $true
+ $padding = "`n$(' ' * $NestingLevel)" # lets just create our left-padding for the block
+ $Recurse = @{
+ 'Depth' = $depth - 1
+ 'NestingLevel' = $NestingLevel + 1
+ 'XmlAsXml' = $XmlAsXml
+ }
+ $Wrap =
+
+ try {
+ switch ($InputObject) {
+ # prevent these values being expanded
+ <# if ($Type -in @( 'guid',
+ , 'datatable', 'List`1','SqlDataReader', 'datarow', 'type',
+ 'MemberTypes', 'RuntimeModule', 'RuntimeType', 'ErrorCategoryInfo', 'CommandInfo', 'CmdletInfo' )) {
+ #>
+ { $InputObject -is [scriptblock] } {
+ "{$($InputObject.ToString())}"
+ break
+ }
+ { $InputObject -is [type] } {
+ "'[$($InputObject.FullName)]'"
+ break
+ }
+ { $InputObject -is [System.Xml.XmlDocument] -or $InputObject -is [System.Xml.XmlElement] } {
+ "|"
+ $InputObject.OuterXml | WrapString $Wrap $padding -Colors:$LineColors
+ break
+ }
+ { $InputObject -is [datetime] -or $InputObject -is [datetimeoffset] } {
+ # s=SortableDateTimePattern (based on ISO 8601) using local time
+ $InputObject.ToString('s')
+ break
+ }
+ { $InputObject -is [timespan] -or $InputObject -is [version] -or $InputObject -is [uri] } {
+ # s=SortableDateTimePattern (based on ISO 8601) using local time
+ "'$InputObject'"
+ break
+ }
+ # yaml case for booleans
+ { $InputObject -is [bool] } {
+ if ($InputObject) { 'true' } else { 'false' }
+ break
+ }
+ # If we're going to go over our depth, just output like it's a value type
+ # ValueTypes are just output with no possibility of wrapping or recursion
+ { $InputObject -is [Enum] -or $InputObject.GetType().BaseType -eq [ValueType] -or $depth -eq 1 } {
+ "$InputObject"
+ break
+ }
+ # 'PSNoteProperty' {
+ # # Write-Verbose "$($padding)Show $($property.Name)"
+ # GetYamlRecursive -InputObject $InputObject.Value @Recurse }
+ { $InputObject -is [System.Collections.IDictionary] } {
+ foreach ($kvp in $InputObject.GetEnumerator()) {
+ # Write-Verbose "$($padding)Enumerate $($property.Name)"
+ "$padding$accentColor$($kvp.Name):$resetColor " +
+ (GetYamlRecursive -InputObject $kvp.Value @Recurse)
+ }
+ break
+ }
+
+ { $InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string] } {
+ foreach ($item in $InputObject) {
+ # Write-Verbose "$($padding)Enumerate $($property.Name)"
+ $Value = GetYamlRecursive -InputObject $item @Recurse
+ # if ($Value -ne 'null' -or $IncludeEmpty) {
+ "$accentColor$padding$resetColor- $Value"
+ # }
+ }
+ break
+ }
+
+ # Limit recursive enumeration to specific types:
+ { $InputObject -is [Exception] -or $InputObject -is [System.Management.Automation.ErrorRecord] -or
+ $InputObject.PSTypeNames[0] -in @(
+ 'System.Exception'
+ 'System.Management.Automation.ErrorRecord'
+ 'Microsoft.Rest.HttpRequestMessageWrapper'
+ 'Microsoft.Rest.HttpResponseMessageWrapper'
+ 'System.Management.Automation.InvocationInfo'
+ ) } {
+ # For exceptions, output a fake property for the exception type
+ if ($InputObject -is [Exception]) {
+ "$padding${accentColor}#Type:$resetColor ${errorAccentColor}" + $InputObject.GetType().FullName + $resetColor
+ }
+ foreach ($property in $InputObject.PSObject.Properties) {
+ if ($property.Value) {
+ $Value = GetYamlRecursive -InputObject $property.Value @Recurse
+ # For special cases, add some color:
+ if ($property.Name -eq "PositionMessage") {
+ $Value = $Value -replace "(\+\s+)(~+)", "`$1$errorColor`$2$resetColor"
+ }
+ if ($InputObject -is [Exception] -and $property.Name -eq "Message") {
+ $Value = "$errorColor$Value$resetColor"
+ }
+ if ((-not [string]::IsNullOrEmpty($Value) -and $Value -ne 'null' -and $Value.Count -gt 0) -or $IncludeEmpty) {
+ "$padding$accentColor$($property.Name):$resetColor " + $Value
+ }
+ }
+ }
+ break
+ }
+ # 'generic' {
+ # foreach($key in $InputObject.Keys) {
+ # # Write-Verbose "$($padding)Enumerate $($key)"
+ # $Value = GetYamlRecursive -InputObject $InputObject.$key @Recurse
+ # if ((-not [string]::IsNullOrEmpty($Value) -and $Value -ne 'null') -or $IncludeEmpty) {
+ # "$padding$accentColor$($key):$resetColor " + $Value
+ # }
+ # }
+ # }
+ default {
+ # Treat anything else as a string
+ $StringValue = $null
+ if ([System.Management.Automation.LanguagePrimitives]::TryConvertTo($InputObject, [string], [ref]$StringValue) -and $null -ne $StringValue) {
+ $StringValue = $StringValue.Trim()
+ if ($StringValue -match '[\r\n]' -or $StringValue.Length -gt $wrap) {
+ ">" # signal that we are going to use the readable 'newlines-folded' format
+ $StringValue | WrapString $Wrap $padding -Colors:$LineColors
+ } elseif ($StringValue.Contains(":")) {
+ "'$($StringValue -replace '''', '''''')'" # single quote it
+ } else {
+ "$($StringValue -replace '''', '''''')"
+ }
+ } else {
+ Write-Warning "Unable to convert $($InputObject.GetType().FullName) to string"
+ }
+ }
+ }
+ } catch {
+ Write-Error "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) "
+ }
+ ) -join ""
+ }
+}
\ No newline at end of file
diff --git a/source/private/WrapString.ps1 b/source/private/WrapString.ps1
new file mode 100644
index 0000000..4d3fbfa
--- /dev/null
+++ b/source/private/WrapString.ps1
@@ -0,0 +1,119 @@
+$script:AnsiPattern = "[\u001b\u009b][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?(?:\u001b\u005c|\u0007))|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))"
+$script:AnsiRegex = [Regex]::new($AnsiPattern, "Compiled");
+function MeasureString {
+ [CmdletBinding()]
+ param(
+ [string]$InputObject
+ )
+ $AnsiRegex.Replace($InputObject, '').Length
+}
+
+
+filter WrapString {
+ [CmdletBinding()]
+ param(
+ # The input string will be wrapped to a certain length, with optional padding on the front
+ [Parameter(ValueFromPipeline)]
+ [string]$InputObject,
+
+ # The maximum length of a line. Defaults to [Console]::BufferWidth - 1
+ [Parameter(Position=0)]
+ [int]$Width = ($Host.UI.RawUI.BufferSize.Width),
+
+ # The padding to add to the front of each line to cause indenting. Defaults to empty string.
+ [Parameter(Position=1)]
+ [string]$IndentPadding = ([string]::Empty),
+
+ # If set, colors to use for alternating lines
+ [string[]]$Colors = @(''),
+
+ # If set, will output empty lines for each original new line
+ [switch]$EmphasizeOriginalNewlines
+ )
+ begin {
+ $color = 0;
+ Write-Debug "Colors: $($Colors -replace "`e(.+)", "`e`$1``e`$1")"
+ # $wrappableChars = [char[]]" ,.?!:;-`n`r`t"
+ # $maxLength = $width - $IndentPadding.Length -1
+ $wrapper = [Regex]::new("((?:$AnsiPattern)*[^-=,.?!:;\s\r\n\t\\\/\|]+(?:$AnsiPattern)*)", "Compiled")
+ $output = [System.Text.StringBuilder]::new($Colors[$color] + $IndentPadding)
+ }
+ process {
+ foreach($line in $InputObject -split "(\r?\n)") {
+ # Don't bother trying to split empty lines
+ if ([String]::IsNullOrWhiteSpace($AnsiRegex.Replace($line, ''))) {
+ Write-Debug "Empty String ($($line.Length))"
+ if ($EmphasizeOriginalNewlines) { [string]::Empty }
+ continue
+ }
+
+ $slices = $line -split $wrapper | ForEach-Object { @{ Text = $_; Length = MeasureString $_ } }
+ Write-Debug "$($line.Length) words in line. $($AnsiRegex.Replace($line, ''))"
+ $lineLength = $IndentPadding.Length
+ foreach($slice in $slices) {
+ $lineLength += $slice.Length
+ if ($lineLength -le $Width) {
+ Write-Verbose "+ $($slice.Length) = $lineLength < $Width"
+ $null = $output.Append($slice.Text)
+ } else {
+ Write-Verbose "Output $($lineLength - $slice.Length)"
+ Write-Verbose "+ $($slice.Length) = $($slice.Length)"
+ $color = ($color + 1) % $Colors.Length
+ $output.ToString().Trim()
+ $null = $output.Clear().Append($Colors[$color]).Append($IndentPadding).Append($slice.Text)
+ $lineLength = $IndentPadding.Length + $slice.Length
+ }
+ }
+ $output.ToString().Trim()
+ $null = $output.Clear().Append($Colors[$color]).Append($IndentPadding)
+ }
+
+ # $currentIndex = 0;
+ # $lastWrap = 0;
+ # do {
+ # $lastWrap = $currentIndex;
+ # #Write-Verbose "m: $Width, l: $($line.Length), c: $color $($Colors[$color] -replace "`e","``e")"
+
+
+
+ # if ($AnsiEscapes.Replace($first, '').Length -gt $maxLength + 1) {
+ # # If we couldn't find a good place to wrap, just wrap at the end of the line
+ # $first = $line.Substring(0, $maxLength+1)
+ # $line = $line.Substring($maxLength+1)
+ # }
+ # $Colors[$color] + $IndentPadding + $first.TrimEnd()
+
+<# $currentIndex = $(
+ if ($lastWrap + $Width -gt $line.Length) {
+ $line.Length
+ } else {
+ $line.LastIndexOfAny($wrappableChars, ([Math]::Min(($line.Length - 1), ($lastWrap + $Width)))) + 1
+ }
+ )
+
+ $slice = $line.Substring($lastWrap, ($currentIndex - $lastWrap))
+ if (($slice.Length - $script:AnsiEscapes.Replace($slice,'').Length) -gt 0) {
+ $currentIndex = $(
+ if ($lastWrap + $Width -gt $line.Length) {
+ $line.Length
+ } else {
+ $line.LastIndexOfAny($wrappableChars, ([Math]::Min(($line.Length - 1), ($lastWrap + $Width)))) + 1
+ }
+ )
+ }
+
+ # If we couldn't find a good place to wrap, just wrap at the end of the line
+ if ($currentIndex -le $lastWrap) {
+ $currentIndex = [Math]::Min(($lastWrap + $Width), $line.Length )
+ }
+ # Output the line, with the appropriate color and padding
+ $Colors[$color] + $IndentPadding + $line.Substring($lastWrap, ($currentIndex - $lastWrap)).TrimEnd()
+#>
+<# } while($line);
+
+ if ($line -ne "`n") {
+ $color = ($color + 1) % $Colors.Length
+ }
+ } #>
+ }
+}
\ No newline at end of file
diff --git a/source/public/ConvertTo-ConciseErrorView.ps1 b/source/public/ConvertTo-ConciseErrorView.ps1
new file mode 100644
index 0000000..391014f
--- /dev/null
+++ b/source/public/ConvertTo-ConciseErrorView.ps1
@@ -0,0 +1,62 @@
+function ConvertTo-ConciseErrorView {
+ [CmdletBinding()]
+ param(
+ [System.Management.Automation.ErrorRecord]
+ $InputObject
+ )
+ if ("$accentColor".Length) {
+ $local:accentColor = $script:errorAccentColor
+ $local:resetColor = $script:resetColor
+ } else {
+ $local:accentColor = ">>>"
+ $local:resetColor = "<<<"
+ }
+
+
+ if ($InputObject.FullyQualifiedErrorId -in 'NativeCommandErrorMessage','NativeCommandError') {
+ $errorColor + $InputObject.Exception.Message + $resetColor
+ } else {
+ $myinv = $InputObject.InvocationInfo
+ if ($myinv -and ($myinv.MyCommand -or ($InputObject.CategoryInfo.Category -ne 'ParserError'))) {
+ # rip off lines that say "At line:1 char:1" (hopefully, in a language agnostic way)
+ $posmsg = $myinv.PositionMessage -replace "^At line:1 char:1[\r\n]+"
+
+ # rip off the underline and use the accentcolor instead
+ $pattern = $posmsg -split "[\r\n]+" -match "\+( +~+)\s*" -replace '(~+)', '($1)' -replace '( +)','($1)' -replace '~| ','.'
+ $posmsg = $posmsg -replace '[\r\n]+\+ +~+'
+ if ($pattern) {
+ $posmsg = $posmsg -replace "\+$pattern", "+`$1$accentColor`$2$resetColor"
+ }
+ } else {
+ $posmsg = ""
+ }
+
+ if ($posmsg -ne "") {
+ $posmsg = "`n" + $posmsg
+ }
+
+ if ( & { Set-StrictMode -Version 1; $InputObject.PSMessageDetails } ) {
+ $posmsg = " : " + $InputObject.PSMessageDetails + $posmsg
+ }
+
+ $indent = 4
+ $width = $host.UI.RawUI.BufferSize.Width - $indent - 2
+
+ $originInfo = & { Set-StrictMode -Version 1; $InputObject.OriginInfo }
+ if (($null -ne $originInfo) -and ($null -ne $originInfo.PSComputerName)) {
+ $indentString = "+ PSComputerName : " + $originInfo.PSComputerName
+ $posmsg += "`n"
+ foreach ($line in @($indentString -split "(.{$width})")) {
+ if ($line) {
+ $posmsg += (" " * $indent + $line)
+ }
+ }
+ }
+
+ if (!$InputObject.ErrorDetails -or !$InputObject.ErrorDetails.Message) {
+ $errorColor + $InputObject.Exception.Message + $resetColor + $posmsg + "`n "
+ } else {
+ $errorColor + $InputObject.ErrorDetails.Message + $resetColor + $posmsg
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/public/ConvertTo-DetailedErrorView.ps1 b/source/public/ConvertTo-DetailedErrorView.ps1
index fbc1c58..210520c 100644
--- a/source/public/ConvertTo-DetailedErrorView.ps1
+++ b/source/public/ConvertTo-DetailedErrorView.ps1
@@ -21,186 +21,13 @@ function ConvertTo-DetailedErrorView {
)
begin {
+ Write-Information "ENTER ConvertTo-DetailedErrorView BEGIN " -Tags 'Trace', 'Enter', 'ConvertTo-DetailedErrorView'
- Set-StrictMode -Off
-
- $ellipsis = "`u{2026}"
- $resetColor = ''
- $errorColor = ''
- $accentColor = ''
- $newline = [Environment]::Newline
- $OutputRoot = [System.Text.StringBuilder]::new()
-
- if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
- $resetColor = "$([char]0x1b)[0m"
- $errorColor = if ($PSStyle.Formatting.Error) { $PSStyle.Formatting.Error } else { "`e[1;31m" }
- $accentColor = if ($PSStyle.Formatting.ErrorAccent) { $PSStyle.Formatting.ErrorAccent } else { "`e[1;36m" }
- }
-
- function DetailedErrorView {
- <#
- .SYNOPSIS
- Internal implementation of the Detailed error view to support recursion and indentation
- #>
- [CmdletBinding()]
- param(
- $InputObject,
- [int]$indent = 0,
- [int]$depth = 1
- )
- $prefix = ' ' * $indent
-
- $expandTypes = @(
- 'Microsoft.Rest.HttpRequestMessageWrapper'
- 'Microsoft.Rest.HttpResponseMessageWrapper'
- 'System.Management.Automation.InvocationInfo'
- )
-
- # if object is an Exception, add an ExceptionType property
- if ($InputObject -is [Exception]) {
- $InputObject | Add-Member -NotePropertyName Type -NotePropertyValue $InputObject.GetType().FullName -ErrorAction Ignore
- }
-
- # first find the longest property so we can indent properly
- $propLength = 0
- foreach ($prop in $InputObject.PSObject.Properties) {
- if ($null -ne $prop.Value -and $prop.Value -ne [string]::Empty -and $prop.Name.Length -gt $propLength) {
- $propLength = $prop.Name.Length
- }
- }
-
- $addedProperty = $false
- foreach ($prop in $InputObject.PSObject.Properties) {
-
- # don't show empty properties or our added property for $error[index]
- if ($null -ne $prop.Value -and $prop.Value -ne [string]::Empty -and $prop.Value.count -gt 0 -and $prop.Name -ne 'PSErrorIndex') {
- $addedProperty = $true
- $null = $OutputRoot.Append($prefix)
- $null = $OutputRoot.Append($accentColor)
- $null = $OutputRoot.Append($prop.Name)
- $null = $OutputRoot.Append(' ',($propLength - $prop.Name.Length))
- $null = $OutputRoot.Append(' : ')
- $null = $OutputRoot.Append($resetColor)
-
- $newIndent = $indent + 4
-
- # only show nested objects that are Exceptions, ErrorRecords, or types defined in $expandTypes and types not in $ignoreTypes
- if ($prop.Value -is [Exception] -or $prop.Value -is [System.Management.Automation.ErrorRecord] -or
- $expandTypes -contains $prop.TypeNameOfValue -or ($null -ne $prop.TypeNames -and $expandTypes -contains $prop.TypeNames[0])) {
-
- if ($depth -ge $maxDepth) {
- $null = $OutputRoot.Append($ellipsis)
- }
- else {
- $null = $OutputRoot.Append($newline)
- $null = $OutputRoot.Append((DetailedErrorView $prop.Value $newIndent ($depth + 1)))
- }
- }
- # `TargetSite` has many members that are not useful visually, so we have a reduced view of the relevant members
- elseif ($prop.Name -eq 'TargetSite' -and $prop.Value.GetType().Name -eq 'RuntimeMethodInfo') {
- if ($depth -ge $maxDepth) {
- $null = $OutputRoot.Append($ellipsis)
- }
- else {
- $targetSite = [PSCustomObject]@{
- Name = $prop.Value.Name
- DeclaringType = $prop.Value.DeclaringType
- MemberType = $prop.Value.MemberType
- Module = $prop.Value.Module
- }
-
- $null = $OutputRoot.Append($newline)
- $null = $OutputRoot.Append((DetailedErrorView $targetSite $newIndent ($depth + 1)))
- }
- }
- # `StackTrace` is handled specifically because the lines are typically long but necessary so they are left justified without additional indentation
- elseif ($prop.Name -eq 'StackTrace') {
- # for a stacktrace which is usually quite wide with info, we left justify it
- $null = $OutputRoot.Append($newline)
- $null = $OutputRoot.Append($prop.Value)
- }
- # Dictionary and Hashtable we want to show as Key/Value pairs, we don't do the extra whitespace alignment here
- elseif ($prop.Value.GetType().Name.StartsWith('Dictionary') -or $prop.Value.GetType().Name -eq 'Hashtable') {
- $isFirstElement = $true
- foreach ($key in $prop.Value.Keys) {
- if ($isFirstElement) {
- $null = $OutputRoot.Append($newline)
- }
-
- if ($key -eq 'Authorization') {
- $null = $OutputRoot.Append("${prefix} ${accentColor}${key} : ${resetColor}${ellipsis}${newline}")
- }
- else {
- $null = $OutputRoot.Append("${prefix} ${accentColor}${key} : ${resetColor}$($prop.Value[$key])${newline}")
- }
-
- $isFirstElement = $false
- }
- }
- # if the object implements IEnumerable and not a string, we try to show each object
- # We ignore the `Data` property as it can contain lots of type information by the interpreter that isn't useful here
- elseif (!($prop.Value -is [System.String]) -and $null -ne $prop.Value.GetType().GetInterface('IEnumerable') -and $prop.Name -ne 'Data') {
-
- if ($depth -ge $maxDepth) {
- $null = $OutputRoot.Append($ellipsis)
- }
- else {
- $isFirstElement = $true
- foreach ($value in $prop.Value) {
- $null = $OutputRoot.Append($newline)
- if (!$isFirstElement) {
- $null = $OutputRoot.Append($newline)
- }
- $null = $OutputRoot.Append((DetailedErrorView $value $newIndent ($depth + 1)))
- $isFirstElement = $false
- }
- }
- }
- # Anything else, we convert to string.
- # ToString() can throw so we use LanguagePrimitives.TryConvertTo() to hide a convert error
- else {
- $value = $null
- if ([System.Management.Automation.LanguagePrimitives]::TryConvertTo($prop.Value, [string], [ref]$value) -and $null -ne $value)
- {
- if ($prop.Name -eq 'PositionMessage') {
- $value = $value.Insert($value.IndexOf('~'), $errorColor)
- }
- elseif ($prop.Name -eq 'Message') {
- $value = $errorColor + $value
- }
-
- $isFirstLine = $true
- if ($value.Contains($newline)) {
- # the 3 is to account for ' : '
- $valueIndent = ' ' * ($propLength + 3)
- # need to trim any extra whitespace already in the text
- foreach ($line in $value.Split($newline)) {
- if (!$isFirstLine) {
- $null = $OutputRoot.Append("${newline}${prefix}${valueIndent}")
- }
- $null = $OutputRoot.Append($line.Trim())
- $isFirstLine = $false
- }
- }
- else {
- $null = $OutputRoot.Append($value)
- }
- }
- }
-
- $null = $OutputRoot.Append($newline)
- }
- }
-
- # if we had added nested properties, we need to remove the last newline
- if ($addedProperty) {
- $null = $OutputRoot.Remove($OutputRoot.Length - $newline.Length, $newline.Length)
- }
-
- $OutputRoot.ToString()
- }
+ Write-Information "EXIT ConvertTo-DetailedErrorView BEGIN" -Tags 'Trace', 'Enter', 'ConvertTo-DetailedErrorView'
}
process {
- DetailedErrorView $InputObject
+ Write-Information "ENTER ConvertTo-DetailedErrorView PROCESS $($InputObject.GetType().FullName)" -Tags 'Trace', 'Enter', 'ConvertTo-DetailedErrorView'
+ GetListRecursive $InputObject
+ Write-Information "EXIT ConvertTo-DetailedErrorView PROCESS $($InputObject.GetType().FullName)" -Tags 'Trace', 'Enter', 'ConvertTo-DetailedErrorView'
}
}
diff --git a/source/public/ConvertTo-FullErrorView.ps1 b/source/public/ConvertTo-FullErrorView.ps1
index 5377ef8..c13705e 100644
--- a/source/public/ConvertTo-FullErrorView.ps1
+++ b/source/public/ConvertTo-FullErrorView.ps1
@@ -22,13 +22,10 @@ filter ConvertTo-FullErrorView {
$resetColor = "$([char]0x1b)[0m"
$errorColor = if ($PSStyle.Formatting.Error) { $PSStyle.Formatting.Error } else { "`e[1;31m" }
- #$accentColor = if ($PSStyle.Formatting.ErrorAccent) { $PSStyle.Formatting.ErrorAccent } else { "`e[1;36m" }
- $Detail = $InputObject | Format-List * -Force | Out-String -Width 120
- $Detail = $Detail -replace "((?:Exception|FullyQualifiedErrorId).*`e\[0m)(.*)", "$($PSStyle.Formatting.ErrorAccent)`$1$($PSStyle.Formatting.Error)`$2$($PSStyle.Reset)"
- } else {
- $Detail = $InputObject | Format-List * -Force | Out-String -Width 120
}
+ $Detail = $InputObject | Format-List * -Force | Out-String -Width 120
+
# NOTE: ErrorViewRecurse is normally false, and only set temporarily by Format-Error -Recurse
if ($ErrorViewRecurse) {
$Count = 1
diff --git a/source/public/ConvertTo-NormalErrorView.ps1 b/source/public/ConvertTo-NormalErrorView.ps1
index cdcd820..a33dc72 100644
--- a/source/public/ConvertTo-NormalErrorView.ps1
+++ b/source/public/ConvertTo-NormalErrorView.ps1
@@ -11,17 +11,8 @@ filter ConvertTo-NormalErrorView {
[System.Management.Automation.ErrorRecord]
$InputObject
)
- $resetColor = ''
- $errorColor = ''
- #$accentColor = ''
- if ($Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {
- $resetColor = "$([char]0x1b)[0m"
- $errorColor = if ($PSStyle.Formatting.Error) { $PSStyle.Formatting.Error } else { "`e[1;31m" }
- #$accentColor = if ($PSStyle.Formatting.ErrorAccent) { $PSStyle.Formatting.ErrorAccent } else { "`e[1;36m" }
- }
-
- if ($InputObject.FullyQualifiedErrorId -eq "NativeCommandErrorMessage") {
+ if ($InputObject.FullyQualifiedErrorId -in 'NativeCommandErrorMessage','NativeCommandError') {
$errorColor + $InputObject.Exception.Message + $resetColor
} else {
$myinv = $InputObject.InvocationInfo
@@ -44,9 +35,9 @@ filter ConvertTo-NormalErrorView {
$errorCategoryMsg = &{ Set-StrictMode -Version 1; $InputObject.ErrorCategory_Message }
if ($null -ne $errorCategoryMsg) {
- $indentString = "+ CategoryInfo : " + $InputObject.ErrorCategory_Message
+ $indentString = $accentColor + "+ CategoryInfo : " + $resetColor + $InputObject.ErrorCategory_Message
} else {
- $indentString = "+ CategoryInfo : " + $InputObject.CategoryInfo
+ $indentString = $accentColor + "+ CategoryInfo : " + $resetColor + $InputObject.CategoryInfo
}
$posmsg += "`n"
foreach ($line in @($indentString -split "(.{$width})")) {
@@ -55,7 +46,7 @@ filter ConvertTo-NormalErrorView {
}
}
- $indentString = "+ FullyQualifiedErrorId : " + $InputObject.FullyQualifiedErrorId
+ $indentString = $accentColor + "+ FullyQualifiedErrorId: " + $resetColor + $InputObject.FullyQualifiedErrorId
$posmsg += "`n"
foreach ($line in @($indentString -split "(.{$width})")) {
if ($line) {
@@ -65,7 +56,7 @@ filter ConvertTo-NormalErrorView {
$originInfo = &{ Set-StrictMode -Version 1; $InputObject.OriginInfo }
if (($null -ne $originInfo) -and ($null -ne $originInfo.PSComputerName)) {
- $indentString = "+ PSComputerName : " + $originInfo.PSComputerName
+ $indentString = "+ PSComputerName : " + $originInfo.PSComputerName
$posmsg += "`n"
foreach ($line in @($indentString -split "(.{$width})")) {
if ($line) {
@@ -75,9 +66,9 @@ filter ConvertTo-NormalErrorView {
}
if (!$InputObject.ErrorDetails -or !$InputObject.ErrorDetails.Message) {
- $errorColor + $InputObject.Exception.Message + $posmsg + $resetColor + "`n "
+ $errorColor + $InputObject.Exception.Message + $resetColor + $posmsg + "`n "
} else {
- $errorColor + $InputObject.ErrorDetails.Message + $posmsg + $resetColor
+ $errorColor + $InputObject.ErrorDetails.Message + $resetColor + $posmsg
}
}
}
\ No newline at end of file
diff --git a/source/public/ConvertTo-NormalExceptionView.ps1 b/source/public/ConvertTo-NormalExceptionView.ps1
index fea1db0..929b040 100644
--- a/source/public/ConvertTo-NormalExceptionView.ps1
+++ b/source/public/ConvertTo-NormalExceptionView.ps1
@@ -21,6 +21,6 @@ filter ConvertTo-NormalExceptionView {
#$accentColor = if ($PSStyle.Formatting.ErrorAccent) { $PSStyle.Formatting.ErrorAccent } else { "`e[1;36m" }
}
- $errorColor + $InputObject.Exception.Message + $resetColor
+ $errorColor + $InputObject.Message + $resetColor
}
\ No newline at end of file
diff --git a/source/public/ConvertTo-SimpleErrorView.ps1 b/source/public/ConvertTo-SimpleErrorView.ps1
index 97197ff..c8b836b 100644
--- a/source/public/ConvertTo-SimpleErrorView.ps1
+++ b/source/public/ConvertTo-SimpleErrorView.ps1
@@ -14,28 +14,17 @@ function ConvertTo-SimpleErrorView {
#$accentColor = if ($PSStyle.Formatting.ErrorAccent) { $PSStyle.Formatting.ErrorAccent } else { "`e[1;36m" }
}
- if ($InputObject.FullyQualifiedErrorId -eq "NativeCommandErrorMessage") {
+ if ($InputObject.FullyQualifiedErrorId -in 'NativeCommandErrorMessage','NativeCommandError') {
$InputObject.Exception.Message
} else {
$myinv = $InputObject.InvocationInfo
if ($myinv -and ($myinv.MyCommand -or ($InputObject.CategoryInfo.Category -ne 'ParserError'))) {
# rip off lines that say "At line:1 char:1" (hopefully, in a language agnostic way)
- $posmsg = $myinv.PositionMessage -replace "^At line:1 .*[\r\n]+"
- # rip off the underline and instead, put >>>markers<<< around the important bit
- # we could, instead, set the background to a highlight color?
- $pattern = $posmsg -split "[\r\n]+" -match "\+( +~+)\s*" -replace '(~+)', '($1)' -replace '( +)','($1)' -replace '~| ','.'
- $posmsg = $posmsg -replace '[\r\n]+\+ +~+'
- if ($pattern) {
- $posmsg = $posmsg -replace "\+$pattern", '+ $1>>>$2<<<'
- }
+ $posmsg = "`n" + $myinv.PositionMessage -replace "^At line:1 .*[\r\n]+"
} else {
$posmsg = ""
}
- if ($posmsg -ne "") {
- $posmsg = "`n" + $posmsg
- }
-
if ( & { Set-StrictMode -Version 1; $InputObject.PSMessageDetails } ) {
$posmsg = " : " + $InputObject.PSMessageDetails + $posmsg
}
diff --git a/source/public/ConvertTo-YamlErrorView.ps1 b/source/public/ConvertTo-YamlErrorView.ps1
new file mode 100644
index 0000000..704bc2d
--- /dev/null
+++ b/source/public/ConvertTo-YamlErrorView.ps1
@@ -0,0 +1,33 @@
+function ConvertTo-YamlErrorView {
+ <#
+ .SYNOPSIS
+ Creates a description of an ErrorRecord that looks like valid Yaml
+ .DESCRIPTION
+ This produces valid Yaml output from ErrorRecord you pass to it, recursively.
+ #>
+ [CmdletBinding()]
+ param(
+ # The object that you want to convert to YAML
+ [Parameter(Mandatory, ValueFromPipeline)]
+ [System.Management.Automation.ErrorRecord]
+ $InputObject,
+
+ # Optionally, a limit on the depth to recurse properties (defaults to 16)
+ [parameter()]
+ [int]$depth = 16,
+
+ # If set, include empty and null properties in the output
+ [switch]$IncludeEmpty,
+
+ # Recursive use only. Handles indentation for formatting
+ [parameter(DontShow)]
+ [int]$NestingLevel = 0,
+
+ # use OuterXml instead of treating XmlDocuments like objects
+ [parameter(DontShow)]
+ [switch]$XmlAsXml
+ )
+ process {
+ GetYamlRecursive $InputObject
+ }
+}
\ No newline at end of file
diff --git a/source/public/Format-Error.ps1 b/source/public/Format-Error.ps1
index 2e7edf2..6a28a37 100644
--- a/source/public/Format-Error.ps1
+++ b/source/public/Format-Error.ps1
@@ -1,13 +1,13 @@
function Format-Error {
<#
.SYNOPSIS
- Formats an error for the screen using a specified error view
+ Formats an error (or exception) for the screen using a specified error view
.DESCRIPTION
Temporarily switches the error view and outputs the errors
.EXAMPLE
Format-Error
- Shows the Normal error view for the most recent error
+ Shows the Detailed error view for the most recent error (changed to be compatible with Get-Error)
.EXAMPLE
$error[0..4] | Format-Error Full
@@ -17,8 +17,8 @@ function Format-Error {
Shows the full error view of the specific error, recursing into the inner exceptions (if that's supported by the view)
#>
- [CmdletBinding(DefaultParameterSetName="Count")]
- [Alias("fe", "Get-Error")]
+ [CmdletBinding(DefaultParameterSetName = "InputObject")]
+ [Alias("fe"<#, "Get-Error"#>)]
[OutputType([System.Management.Automation.ErrorRecord])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'The ArgumentCompleter parameters are the required method signature')]
@@ -28,7 +28,7 @@ function Format-Error {
[ArgumentCompleter({
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
[System.Management.Automation.CompletionResult[]]((
- Get-Command ConvertTo-*ErrorView -ListImported -ParameterName InputObject -ParameterType [System.Management.Automation.ErrorRecord]
+ Get-Command ConvertTo-*ErrorView -ListImported -ParameterName InputObject -ParameterType [System.Management.Automation.ErrorRecord], [System.Exception]
).Name -replace "ConvertTo-(.*)ErrorView",'$1' -like "*$($wordToComplete)*")
})]
$View = "Detailed",
@@ -47,19 +47,22 @@ function Format-Error {
}
),
- # Allows ErrorView functions to recurse to InnerException
+ # Encourages ErrorView functions to recurse InnerException properties
[switch]$Recurse
)
begin {
$ErrorActionPreference = "Continue"
- $ErrorView, $View = $View, $ErrorView
- [bool]$Recurse, [bool]$ErrorViewRecurse = [bool]$ErrorViewRecurse, $Recurse
+
+ $local:_ErrorView, $global:ErrorView = $global:ErrorView, $View
+ $local:_ErrorViewRecurse, [bool]$global:ErrorViewRecurse = [bool]$global:ErrorViewRecurse, $Recurse
}
process {
$InputObject
}
end {
- [bool]$ErrorViewRecurse = $Recurse
- $ErrorView = $View
+ $global:ErrorView = $local:_ErrorView
+ if ($null -ne $local:_ErrorViewRecurse) {
+ [bool]$global:ErrorViewRecurse = $local:_ErrorViewRecurse
+ }
}
}
diff --git a/source/public/Set-ErrorView.ps1 b/source/public/Set-ErrorView.ps1
index 8041415..340394a 100644
--- a/source/public/Set-ErrorView.ps1
+++ b/source/public/Set-ErrorView.ps1
@@ -27,6 +27,7 @@ filter Set-ErrorView {
).Name -replace "ConvertTo-(\w+)ErrorView", '$1View' | Select-Object -Unique
$ofs = ';'
- .([ScriptBlock]::Create("enum ErrorView { $Names }"))
+ . ([ScriptBlock]::Create("enum ErrorView { $Names }"))
+
[ErrorView]$global:ErrorView = $View
}
diff --git a/source/public/Write-NativeCommandError.ps1 b/source/public/Write-NativeCommandError.ps1
index 85d98d1..5ab8889 100644
--- a/source/public/Write-NativeCommandError.ps1
+++ b/source/public/Write-NativeCommandError.ps1
@@ -12,36 +12,40 @@ function Write-NativeCommandError {
$errorColor = if ($PSStyle.Formatting.Error) { $PSStyle.Formatting.Error } else { "`e[1;31m" }
$accentColor = $PSStyle.Formatting.ErrorAccent
}
+ if ($InputObject -is [System.Exception]) {
+ $errorColor + $InputObject.GetType().FullName + " : " + $resetColor
+ }
- if ($InputObject.FullyQualifiedErrorId -eq "NativeCommandErrorMessage") { return }
-
- $invoc = $InputObject.InvocationInfo
- if ($invoc -and $invoc.MyCommand) {
- switch -regex ( $invoc.MyCommand.CommandType ) {
- ([System.Management.Automation.CommandTypes]::ExternalScript) {
- if ($invoc.MyCommand.Path) {
- $accentColor + $invoc.MyCommand.Path + " : " + $resetColor
+ # @('NativeCommandErrorMessage', 'NativeCommandError') -notcontains $_.FullyQualifiedErrorId -and @('CategoryView', 'ConciseView', 'DetailedView') -notcontains $ErrorView
+ if (@('NativeCommandErrorMessage', 'NativeCommandError') -notcontains $_.FullyQualifiedErrorId -and @('CategoryView', 'ConciseView', 'DetailedView') -notcontains $ErrorView) {
+ $invoc = $InputObject.InvocationInfo
+ if ($invoc -and $invoc.MyCommand) {
+ switch -regex ( $invoc.MyCommand.CommandType ) {
+ ([System.Management.Automation.CommandTypes]::ExternalScript) {
+ if ($invoc.MyCommand.Path) {
+ $errorColor + $invoc.MyCommand.Path + " : " + $resetColor
+ }
+ break
}
- break
- }
- ([System.Management.Automation.CommandTypes]::Script) {
- if ($invoc.MyCommand.ScriptBlock) {
- $accentColor + $invoc.MyCommand.ScriptBlock.ToString() + " : " + $resetColor
+ ([System.Management.Automation.CommandTypes]::Script) {
+ if ($invoc.MyCommand.ScriptBlock) {
+ $errorColor + $invoc.MyCommand.ScriptBlock.ToString() + " : " + $resetColor
+ }
+ break
}
- break
- }
- default {
- if ($invoc.InvocationName -match '^[&\.]?$') {
- if ($invoc.MyCommand.Name) {
- $accentColor + $invoc.MyCommand.Name + " : " + $resetColor
+ default {
+ if ($invoc.InvocationName -match '^[&\.]?$') {
+ if ($invoc.MyCommand.Name) {
+ $errorColor + $invoc.MyCommand.Name + " : " + $resetColor
+ }
+ } else {
+ $errorColor + $invoc.InvocationName + " : " + $resetColor
}
- } else {
- $accentColor + $invoc.InvocationName + " : " + $resetColor
+ break
}
- break
}
+ } elseif ($invoc -and $invoc.InvocationName) {
+ $errorColor + $invoc.InvocationName + " : " + $resetColor
}
- } elseif ($invoc -and $invoc.InvocationName) {
- $accentColor + $invoc.InvocationName + " : " + $resetColor
}
}
\ No newline at end of file