powershellclasserror-handlingwrite-error

Write-Error doesn't result useful information when used inside class methods | Powershell


I used a method with and without a class and the Write-Error seems to produce different outputs. In case of class, it doesn't specify the function and the line number is always 1,1

function oper1() {
    Try {
        [string] $cmd = ".\some_exe_which_does_not_exist.exe"
        iex $cmd 
    }
    Catch {
        Write-Error $_.Exception.Message
    }
}

oper1

Output for above:

oper1 : The term '.\some_exe_which_does_not_exist.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At F:\debug\encryption_concat_tests\Untitled1.ps1:11 char:1 + oper1 + ~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,oper1

When I enclosed the same function in a class, I got this:

class Operator {
    [void] oper1() {
        Try {
            [string] $cmd = ".\some_exe_which_does_not_exist.exe"
            iex $cmd 
        }
        Catch {
            Write-Error $_.Exception.Message
        }
    }
}

[Operator] $operator = New-Object Operator
$operator.oper1()

The term '.\some_exe_which_does_not_exist.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:1 + F:\debug\encryption_concat_tests\Untitled1.ps1 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

What could be the reason for this behaviour for methods inside classes?


Solution

  • As an aside: Invoke-Expression (iex) should generally be avoided; definitely don't use it to invoke an external program - just invoke it directly, as shown below.


    In PowerShell class methods:

    See this answer for more information about error handling and stream-output behavior in class methods in particular.

    Here's a corrected version of your code.

    class Operator {
        [void] oper1() {
            Try {
                # Try to invoke a non-existent executable.
                & ".\some_exe_which_does_not_exist.exe"
            }
            Catch {
                # Re-throw the error.
                # Alternatively, don't use try / catch, but the error
                # then only aborts the method call, not the entire script.
                Throw
            }
        }
    }
    
    $operator = [Operator]::new()
    $operator.oper1()