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 ( Test-Powershell_ISE ) 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 ( Test-Powershell_RemoteSession ) ) { notepad $logFile if (Test-Path $shortLogFile) { notepad $shortLogFile } } return $ShortInfo } } } function Get-MsiError:::Example{ $logFile = 'C:\logs\App.msi.log' Get-MsiError -logFile $logFile } function Test-Dev_Mode { if ( Test-Powershell_ISE ) { return $true; } if ( Test-Powershell_VsCode ) { return $true; } if ( Get-PSBreakpoint ) { return $true; } } function Stop-OnException ([Switch]$Disable, [string[]]$ignoreMatch = @()) { $bp = Get-PSBreakpoint -Variable StackTrace if ($Disable) { if ($bp) { $bp | Remove-PSBreakpoint } return } if (-not $bp) { $bp = Set-PSBreakpoint -Variable StackTrace -Mode Write -Action { $defaultIgnoreMatches = @( '*at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference*' '*at System.Management.Automation.MshCommandRuntime.ThrowTerminatingError(ErrorRecord errorRecord\)*' '*LoadModuleManifest*' ) $toIgnore = $ignoreMatch + $defaultIgnoreMatches function ConvertFrom_CallStack_To_String { $callStack = Get-PSCallStack $result = $callStack | ForEach-Object { [PSCustomObject]@{ Location = $_.ScriptName + ":" + $_.ScriptLineNumber FunctionName = $_.FunctionName Line = $_.Position } } $result | Out-String #Required in order to force it to convert as string that renders the info } if ($_) { $shouldIgnore = $toIgnore | Where-Object { $StackTrace -like $_ } | Select-Object -First 1 if (-not $shouldIgnore) { write-host $stacktrace write-host "Stop-OnException" -ForegroundColor Red # $errInfoMessage = Get-ErrorStackMessage # Write-Warning $errInfoMessage $stack = ConvertFrom_CallStack_To_String write-host $stack write-host "Stop-OnException Ready" -ForegroundColor Red 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 } |