none
Errorhandling within PowerShell-Modules

    Question

  • Hi all,

    when working with "traditional" CmdLets (written in C# and compiled) i'm used to handling errors in the following way inside a ps1-file:

    $ErrorActionPreference = "Stop"
    trap {
      "error occurred"
    }
    get-childitem "C:\nosuchdirectory"

    so when $ErrorActionPreference is set to stop all non-terminatig errors from called CmdLets are converted to terminating ones and i can handle this errors with trap {} or a try/catch block. fine

    We want to shift to PowerShell-CmdLets in PS 2.0.

    What i found out is that the behavior has changed? So i have to specifiy -ErrorAction to each and every PowerShell written CmdLet, otherwise the preference-variable is not set and a non-terminating error will not be transformed into a terminating one:

    Import-Module MyModule
    #the following line has no effect to My-CmdLet1
    $ErrorActionPreference = "Stop"
    trap {
    	"trap entered: $_"
    	exit -1
    }
    
    My-CmdLet1 -ErrorAction "Stop"
    #the following call doesn't catch the error
    #My-CmdLet1
    

    Inside the Module i'm working with Write-Error or $PSCmdlet.WriteError() to bring the exception to the next level. Of course, i'm using the [CmdletBinding] attribute after the .Synopsis comment-block.

     

     

    Does anybody know what i can do to give my PS-CmdLets the same behavior as the other ones?

    From a user-perspective it's not that easy to distinguish how and when should the erroractionpreference be set and what is a ps-cmdlet and what not.

    Maybe there's a mistake on my side or a missing peace in this puzzle... so please, let me know.

    Thanks,

    Markus

    Wednesday, September 8, 2010 1:48 PM

Answers

  • The reason is that the Module has its own scope and you cannot access it directly from the caller's scope but you can access it from a function imported to the caller's scope.

    One way to work around this is to define a function in the module that resets the Module's $ErrorActionPreference. You would call this function at the top of your script.

    In this sample I'm using New-Module Cmdlet – hence the Continue keyword in the Trap – but the technique should be effective from a Module imported from disk.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    New-Module -Name MyMod -ScriptBlock {
     $ErrorActionPreference = 'Continue'

     function Reset-MyModEA {
      # Requires -Version 2.0
      [CmdletBinding()]
      param (
       [Parameter(Mandatory = $true, Position = 0)]
       [Management.Automation.ActionPreference]
       $Action
      )
      end {
       Set-Variable ErrorActionPreference $Action -Scope 1
      }
     }

     function MyAdvFunc {
      # Requires -Version 2.0
      [CmdletBinding()]
      param(
       [Parameter(Mandatory = $true, Position = 0, ValueFromPipeLine = $true)]
       [String]
       $Path
      )
      begin {
       # just info
       Write-Warning $ErrorActionPreference
      }
      process {
       trap {
        "trap entered: $_"
        # exit -1
        continue
       }
       $Path = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Path)
       Get-Item -Path $Path
      }
      end {
      }
     }

     Export-ModuleMember -Function Reset-MyModEA, MyAdvFunc
    }

    # mimic a script call
    &{Reset-MyModEA Stop; MyAdvFunc nodice}
    # mimic a script call and set the error variable
    &{Reset-MyModEA Stop; MyAdvFunc nodice -ev err; $err}

      Robert Robelo  
    • Marked as answer by haui77 Wednesday, September 15, 2010 6:23 AM
    Wednesday, September 8, 2010 6:03 PM

All replies

  • The reason is that the Module has its own scope and you cannot access it directly from the caller's scope but you can access it from a function imported to the caller's scope.

    One way to work around this is to define a function in the module that resets the Module's $ErrorActionPreference. You would call this function at the top of your script.

    In this sample I'm using New-Module Cmdlet – hence the Continue keyword in the Trap – but the technique should be effective from a Module imported from disk.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    New-Module -Name MyMod -ScriptBlock {
     $ErrorActionPreference = 'Continue'

     function Reset-MyModEA {
      # Requires -Version 2.0
      [CmdletBinding()]
      param (
       [Parameter(Mandatory = $true, Position = 0)]
       [Management.Automation.ActionPreference]
       $Action
      )
      end {
       Set-Variable ErrorActionPreference $Action -Scope 1
      }
     }

     function MyAdvFunc {
      # Requires -Version 2.0
      [CmdletBinding()]
      param(
       [Parameter(Mandatory = $true, Position = 0, ValueFromPipeLine = $true)]
       [String]
       $Path
      )
      begin {
       # just info
       Write-Warning $ErrorActionPreference
      }
      process {
       trap {
        "trap entered: $_"
        # exit -1
        continue
       }
       $Path = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Path)
       Get-Item -Path $Path
      }
      end {
      }
     }

     Export-ModuleMember -Function Reset-MyModEA, MyAdvFunc
    }

    # mimic a script call
    &{Reset-MyModEA Stop; MyAdvFunc nodice}
    # mimic a script call and set the error variable
    &{Reset-MyModEA Stop; MyAdvFunc nodice -ev err; $err}

      Robert Robelo  
    • Marked as answer by haui77 Wednesday, September 15, 2010 6:23 AM
    Wednesday, September 8, 2010 6:03 PM
  • Hi,

    Do you need any other assistance? If there is anything we can do for you, please let us know.

    Thanks.


    This posting is provided "AS IS" with no warranties, and confers no rights. Please remember to click "Mark as Answer" on the post that helps you, and to click "Unmark as Answer" if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Wednesday, September 15, 2010 2:14 AM
  • hi robert,

    thanks for the explanation!

    markus

    Wednesday, September 15, 2010 6:24 AM
  • Glad to help Markus.
      Robert Robelo  
    Wednesday, September 15, 2010 8:20 AM