pf-errorhandling.ps1

function Get-ErrorStackMessage {
    $currentErrors = $global:Error | 
        Where-Object Exception -IsNot [System.Management.Automation.ActionPreferenceStopException]
    # [System.Management.Automation.RemoteException]
    $rootScriptName = Get-ScriptPath -rootScript
    [string[]]$errInfo = @("Root Script '$rootScriptName'")
    $errInfo += '======='

    foreach ($err in $currentErrors) {
        if ($null -ne $err.Exception) {
            $errInfo += $err.Exception.GetType().Fullname
            $errInfo += $err.Exception.Message
        }
        $errInfo += $err.InvocationInfo
        $errInfo += $err.ScriptStackTrace
        $errInfo += $err.PSMessageDetails 
        $errInfo += '---------'
    }

    $errInfoMessage = $errInfo -join "`n"
    return $errInfoMessage
}

function Export-Error([switch]$open) {
    if ($global:Error.Count -eq 0 ) { return }

    $errInfoMessage = Get-ErrorStackMessage
    Write-Warning $errInfoMessage
    
    $rootScriptName = Get-ScriptPath -rootScript
    $filename = Split-Path $rootScriptName -Leaf | Update-Path_ReplaceFileSpecialChars
    $filename = Initialize-ExportFile "Error_$filename.xml"
    $errInfoMessage >> $filename
    
    $show = $true # $open -or ( IsISE )
    if ( $show ) {
        Show-File $filename
    }
    Export-Context -filenamePrefix "Error_" -open:$show
}

function Get-MsiError ($logFile) {
   if (test-path $logFile ) {
      $msiLogLines =  Get-Content $logFile 
      $errorMark = $msiLogLines | Select-String -SimpleMatch 'Return value 3.'
      
      if ($errorMark) {
          $errLineNumber = $errorMark[0].LineNumber - 1
          
          $actionStartHeader = 'Executing op: ActionStart('
          $actionStart = $msiLogLines | Select-String -SimpleMatch $actionStartHeader
          if ($actionStart) {
              [Array]::Reverse($actionStart)
              $lastActionStarted = $actionStart | skip-until { $_.LineNumber -lt $errLineNumber } | 
                Select-Object -first 1

              $ShortInfo = @("=== START EXTRACT OF '$logFile' ===")
              if ( $lastActionStarted ) {
                $ShortInfo += $msiLogLines[$lastActionStarted[0].LineNumber .. $errLineNumber]
              }
              else {
                $ShortInfo += $msiLogLines[ ($errLineNumber - 50 ) .. $errLineNumber]
              }
              $ShortInfo += "=== END EXTRACT OF '$logFile' ==="
              $shortLogFile = $logFile | Add-FilenameSuffix '.min'
              $Encoding = Get-FileEncoding -FullName $logFile
              Set-Content -Path $shortLogFile -Value $ShortInfo -Encoding $Encoding
          }
          
          if (-not ( IsRemoteSession ) ) {
              notepad $logFile
              if (Test-Path $shortLogFile) {
                 notepad $shortLogFile
              }
          }

          return $ShortInfo
      }
   }
}
function Get-MsiError:::Example{
    $logFile = 'C:\logs\CORP.LG.Customisation.msi.log'
    Get-MsiError -logFile $logFile
}

function Test-Dev_Mode {
    if ( IsISE ) { return $true; }
    if ( Get-PSBreakpoint ) { return $true; }

}

function Stop-OnException ([Switch]$Disable) {
    $bp = Get-PSBreakpoint -Variable StackTrace
    if ($Disable) {
        if ($bp) {
            $bp | Remove-PSBreakpoint
        } 
        return
    }
    
    if (-not $bp) {
        $bp = Set-PSBreakpoint -Variable StackTrace -Mode Write -Action { 
            Get-PSCallStack
            break
        }

    }
    else {
        $bp | Enable-PSBreakpoint
    }
}

function Disable-BreakPoint_StackTrace{
    Param (
        [ScriptBlock]$script
    )
    Get-PSBreakpoint -Variable StackTrace | Disable-PSBreakpoint
    if ( $script ) {
        try {
            . $script
        }
        finally {
            Enable-BreakPoint_StackTrace
        }
    }
}
function Disable-BreakPoint_StackTrace:::Example {
    Disable-BreakPoint_StackTrace -script { return 'a' } | assert 'a'
}

function Enable-BreakPoint_StackTrace {
    Get-PSBreakpoint -Variable StackTrace | Enable-PSBreakpoint
}