@@ -79,30 +79,102 @@ function TerminateWithError {
7979 Play- Sound - Action Error
8080 }
8181
82+ # Repeats the character 50 times to create a separator line
83+ $Line = ' -' * 50
84+
8285 if ($ErrorRecord ) {
83- Write-Host " `n $ErrorMessage `n " - BackgroundColor DarkRed - ForegroundColor White
86+ Write-Host " `n $Line " - ForegroundColor Red
87+ Write-Host " `t ❌ $ErrorMessage ❌" - ForegroundColor Red
88+ Write-Host " $Line " - ForegroundColor Red
89+
8490
85- # Step 1: Display primary exception
91+ # Step 1: Display primary exception with target command name if available
8692 $currentException = $ErrorRecord.Exception
8793 $primaryLine = $ErrorRecord.InvocationInfo.ScriptLineNumber
8894
95+ $invocationName = $null
96+ if ($ErrorRecord.InvocationInfo ) {
97+ if ($ErrorRecord.InvocationInfo.InvocationName ) {
98+ $invocationName = $ErrorRecord.InvocationInfo.InvocationName
99+ }
100+ elseif ($ErrorRecord.InvocationInfo.MyCommand ) {
101+ $invocationName = $ErrorRecord.InvocationInfo.MyCommand.Name
102+ }
103+ }
104+
105+ # Fallback for primary ActionPreferenceStopException to catch the root cmdlet name
106+ if (-not $invocationName -and $ErrorRecord.Exception -and $ErrorRecord.Exception.PSObject.Properties [' ErrorRecord' ]) {
107+ $nestedRecord = $ErrorRecord.Exception.ErrorRecord
108+ if ($nestedRecord -and $nestedRecord.InvocationInfo ) {
109+ if ($nestedRecord.InvocationInfo.MyCommand ) {
110+ $invocationName = $nestedRecord.InvocationInfo.MyCommand.Name
111+ }
112+ elseif ($nestedRecord.InvocationInfo.InvocationName ) {
113+ $invocationName = $nestedRecord.InvocationInfo.InvocationName
114+ }
115+ }
116+ }
117+
89118 if ($primaryLine ) {
90119 Write-Host " Error at line: $primaryLine " - ForegroundColor Red
91120 }
92121
93122 $lastMessage = $null
94123 if ($currentException ) {
95- Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
124+ # Prefix the command name to match native PowerShell behavior
125+ if ($invocationName ) {
126+ Write-Host " ${invocationName} : " - NoNewline
127+ Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
128+ }
129+ else {
130+ Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
131+ }
96132 $lastMessage = $currentException.Message
97133 }
98134
99135 # Step 2: Traverse inner exceptions with deduplication logic
100136 while ($currentException.InnerException ) {
137+ $parentException = $currentException
101138 $currentException = $currentException.InnerException
102139
103140 $innerLine = $null
104- if ($currentException.ErrorRecord -and $currentException.ErrorRecord.InvocationInfo ) {
105- $innerLine = $currentException.ErrorRecord.InvocationInfo.ScriptLineNumber
141+ $innerTargetCommand = $null
142+
143+ # Prioritize custom attached PSErrorRecord because it contains the rich catch-block context
144+ $targetRecord = $null
145+ if ($parentException -and $parentException.PSObject.Properties [' PSErrorRecord' ]) {
146+ $targetRecord = $parentException.PSErrorRecord
147+ }
148+ elseif ($currentException.PSObject.Properties [' PSErrorRecord' ]) {
149+ $targetRecord = $currentException.PSErrorRecord
150+ }
151+ elseif ($currentException.ErrorRecord ) {
152+ $targetRecord = $currentException.ErrorRecord
153+ }
154+
155+ if ($targetRecord ) {
156+ if ($targetRecord.InvocationInfo ) {
157+ $innerLine = $targetRecord.InvocationInfo.ScriptLineNumber
158+ if ($targetRecord.InvocationInfo.MyCommand ) {
159+ $innerTargetCommand = $targetRecord.InvocationInfo.MyCommand.Name
160+ }
161+ elseif ($targetRecord.InvocationInfo.InvocationName ) {
162+ $innerTargetCommand = $targetRecord.InvocationInfo.InvocationName
163+ }
164+ }
165+
166+ # Fallback for ActionPreferenceStopException where the actual cmdlet name is inside the exception's own ErrorRecord
167+ if (-not $innerTargetCommand -and $targetRecord.Exception -and $targetRecord.Exception.PSObject.Properties [' ErrorRecord' ]) {
168+ $nestedRecord = $targetRecord.Exception.ErrorRecord
169+ if ($nestedRecord -and $nestedRecord.InvocationInfo ) {
170+ if ($nestedRecord.InvocationInfo.MyCommand ) {
171+ $innerTargetCommand = $nestedRecord.InvocationInfo.MyCommand.Name
172+ }
173+ elseif ($nestedRecord.InvocationInfo.InvocationName ) {
174+ $innerTargetCommand = $nestedRecord.InvocationInfo.InvocationName
175+ }
176+ }
177+ }
106178 }
107179
108180 # Deduplicate: skip if the message is identical and provides no new line context
@@ -115,21 +187,37 @@ function TerminateWithError {
115187 Write-Host " Error at line: $innerLine " - ForegroundColor Red
116188 }
117189
118- Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
190+ if ($innerTargetCommand ) {
191+ Write-Host " ${innerTargetCommand} : " - NoNewline
192+ Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
193+ }
194+ else {
195+ Write-Host " $ ( $currentException.Message ) " - ForegroundColor Yellow
196+ }
119197 $lastMessage = $currentException.Message
120198 }
121199
122- Write-Host " `n EXIT " - BackgroundColor DarkRed - ForegroundColor White
200+ # Step 3: Display the script call stack to expose the calling function context
201+ if ($ErrorRecord.ScriptStackTrace ) {
202+ Write-Host " `n Script Call Stack:" - ForegroundColor DarkGray
203+ $ErrorRecord.ScriptStackTrace -split " `r ?`n " | Where-Object { $_.Trim () } | ForEach-Object {
204+ Write-Host " $_ " - ForegroundColor Gray
205+ }
206+ }
207+
208+ Write-Host " `n EXIT " - ForegroundColor Red
123209 }
124210 else {
125- Write-Host " `n ERROR `n " - BackgroundColor DarkRed - ForegroundColor White
211+ Write-Host " `n $Line " - ForegroundColor Red
212+ Write-Host " `t ❌ ERROR ❌" - ForegroundColor Red
213+ Write-Host " $Line " - ForegroundColor Red
214+
126215 Write-Host " $ErrorMessage " - ForegroundColor Yellow
127- Write-Host " `n EXIT " - BackgroundColor DarkRed - ForegroundColor White
216+ Write-Host " `n EXIT " - ForegroundColor Red
128217 }
129218
130219 exit 1
131220}
132-
133221<# *==========================================================================
134222* ℹ PARAMETERS
135223
@@ -772,15 +860,13 @@ public static extern void CoTaskMemFree(IntPtr pv);
772860 }
773861 catch {
774862 # Pass $_.Exception as the InnerException to preserve the original root cause
775- $exception = [System.Management.Automation.RuntimeException ]::new(" File manager failed to open." , $_.Exception )
776- $errorRecord = [System.Management.Automation.ErrorRecord ]::new(
777- $exception ,
778- " FileManagerError" ,
779- [System.Management.Automation.ErrorCategory ]::NotSpecified,
780- $null
781- )
782-
783- $PSCmdlet.ThrowTerminatingError ($errorRecord )
863+ $innerException = $_.Exception
864+ $outerException = New-Object System.Reflection.TargetInvocationException(" File manager failed to open." , $innerException )
865+
866+ # Attach the original ErrorRecord to the exception to preserve PowerShell context
867+ Add-Member - InputObject $outerException - NotePropertyName " PSErrorRecord" - NotePropertyValue $_
868+
869+ throw $outerException
784870 }
785871 }
786872
0 commit comments