3

I have multiple try catch blocks and all of them are using the same catch block.

    try {   
        invoke-command -cn $host -Credential $cred -ScriptBlock {
        param($name)    
        statement...
        } -ArgumentList $name
        
    } catch {
        $formatstring = "{0} : {1}`n{2}`n" +
                    "    + CategoryInfo          : {3}`n" +
                    "    + FullyQualifiedErrorId : {4}`n"
        write-host ($formatstring)
        exit 1
    }

...

    try {   
    another statement...
        
    } catch {
        $formatstring = "{0} : {1}`n{2}`n" +
                    "    + CategoryInfo          : {3}`n" +
                    "    + FullyQualifiedErrorId : {4}`n"
        write-host ($formatstring)
        exit 1
    }

I want to ask if it is possible to create a function which has the catch block so that I can call and use the function instead of writing the same catch block multiple times.

I am using poweshell 5

meallhour
  • 13,921
  • 21
  • 60
  • 117
  • Seems like you're just trying to replicate the `$Error` default formatting output in which case why not just use `$_` in your catch block? – Santiago Squarzon Mar 15 '22 at 03:02

2 Answers2

3

catch requires a literal { ... } block to follow it, but from inside that block you're free to call reusable code, such as a function, or, in the simplest case, a script block:

# Define a script block to use in multiple `catch` blocks.
$sb = {
  "[$_]" # echo the error message
}

# Two simple sample try / catch statements:

try {
  1 / 0
}
catch {
  . $sb # `. <script-block>` invokes the block directly in the current scope
}

try {
  Get-Item -NoSuchParam
}
catch {
  . $sb
}

Note: ., the dot-sourcing operator, is used to invoke the script block directly in the current scope, allowing you to directly modify that scope's variables. This makes the script block behave as if it were used directly as the catch black.

If, by contrast, you want to execute the script block in a child scope, use &, the call operator.

mklement0
  • 382,024
  • 64
  • 607
  • 775
2

You can create a ScriptBlock which can be called using the Invocation (call - &) Operator.

$callMe = {
    $formatstring = "{0} : {1}`n{2}`n" +
    "    + CategoryInfo          : {3}`n" +
    "    + FullyQualifiedErrorId : {4}`n"
    Write-Host -Object $formatstring
    exit 1
}

try {   
    Invoke-Command -ComputerName $host -Credential $cred -ScriptBlock {
        param($name)    
            # statement...
    } -ArgumentList $name -ErrorAction "Stop"
} 
catch {
    & $callMe
}

As a side note, if you ever find yourself repeating code, there is probably something you can do about that. I would suggest either setting $ErrorActionPreference to stop, or add a -ErrorAction "Stop" to your Invoke-Command to ensure a terminating error is thrown.

  • Best practice is to set $ErrorActionPreference back to "Continue" if used.
  • I also believe you're looking to use the -f (format) operator.
Abraham Zinala
  • 4,267
  • 3
  • 9
  • 24