Is it possible to build a trap method in a module that then reacts to errors in the father scope?
My goal would be to include the trap construction for the script in the module. Something like the non functioning example below. Traps a very picky about the scope they are running in and I dont know, if or how to manipulate that.
myLogModule.psm1
# This only works in its own Scope, how to "expand" it to other scopes?
function MyVerySpecificLog{
** Code **
}
trap{
MyVerySpecificLog ("Error: $_")
break
}
RunningCode.ps1
Import-Module myLogModule
**Code Stuff**
nonsensCode # Hopefully trapped by the trap in myLogModule.psm1
** Code Stuff **
CodePudding user response:
I've read through Microsoft "about_Trap", and its looking like the answer is no. https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_trap?view=powershell-5.1
Read the blue "Important" boxes on the page. "trap statements may be defined anywhere within a given scope, but always apply to all statements in that scope" and "A Trap statement is scoped to where it compiles. If you have a trap statement inside a function or dot sourced script, when the function or dot sourced script exits, all trap statements inside are removed."
The "Trapping errors and scope" section of this page shows an example where a trap is set before function2 is called and the trap catches the error that happened inside function2. But technically, the call to function2 is in the same scope as the trap, so I believe even that was a same scope situation.
I did an experiment where I set a trap in a function in a module:
function Set-Trap {
trap { "An error: " }
Write-Host "InSetTrap"
}
and then called the function with a . in front of it followed by an error causing line:
. Set-Trap
errorCausingGarbageLine
The Write-Host in the Set-Trap did get called, but even though the dot in front of Set-Trap should have called it in the same scope as the error causing line, the trap was no longer set and the error was not caught.
Also tried this, it too failed:
. ([ScriptBlock]::Create('trap { "An error: " }'))
AnotherErrorCausingLine
This last one kind of surprised me. You can build "Using Module" lines and call them as a scriptblock anywhere in your code and load modules that way, yet trap fails!
Would love to hear from anyone with better insight, but from what I'm seeing, I think trap is not really a statement that PowerShell executes such as "Using Module" or "Import-Module", but really more of a scope control definition. My key reason for saying this is this line from one of the blue boxes: "For example, defining a trap at the end of a script and throwing an error in the first statement still triggers that trap."
So it doesn't matter where in a scope you placed a trap, it only matters that the trap is in the scope. And with that, it is modifying only the code that is compiled in that scope.
Wish I could give you a "yes" as an answer, I think what you are trying to do is a great idea.
CodePudding user response:
Still haven't had success with trap, but here is an interesting try/catch.
This was in a module:
function Watch-Errors {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$Text,
[Parameter(Mandatory = $true, Position = 1)]
[scriptblock]$ScriptBlock
)
Write-Host -ForegroundColor Cyan "Caller line: $((Get-PSCallStack)[1].ScriptLineNumber)"
Write-Host -ForegroundColor Green "Text: $Text"
try {
& $ScriptBlock
} catch {
$Line = $_.InvocationInfo.ScriptLineNumber
Write-Host -ForegroundColor Red "Caught exception at line " -NoNewline
Write-Host -ForegroundColor Yellow "$Line" -NoNewline
Write-Host -ForegroundColor Red "."
}
}
This is the code with the line numbers. (Starts at line 20 due to commented out past experments.)
20> Watch-Errors 'Test string' {
21> Write-Host "In ScriptBlock"
22> ImAnError
23> }
And this is the results
Caller line: 20
Text: Test string
In ScriptBlock
Caught exception at line 22.