2009-04-28 93 views

回答

14

還有就是自動變量$StackTrace,但它似乎是一個小比實際關心你的腳本更具體的內部PS的細節,這樣就不會有很大幫助。

還有Get-PSCallStack但不幸的是,只要您遇到異常,就會消失。但是,您可以在每次投擲腳本之前放置一個Get-PSCallStack。這樣,您在遇到異常之前立即獲取堆棧跟蹤。

我想通過使用Powershell的調試和追蹤功能可以編寫這樣的功能,但我懷疑這很容易。

+4

我們應該提交一個增強請求(如果尚未提交的話)會自動添加到異常中。 – JasonMArcher 2009-04-29 19:50:51

+0

此功能已添加到PS 3.0中。我用示例代碼發佈了一個答案。 – Timbo 2013-03-13 23:49:31

+0

沒有幫助,如果我沒有寫代碼做投擲:-( – bacar 2013-10-29 12:20:37

32

有一種叫做function up on the PowerShell Team blog解決錯誤,這將讓你的各種細節

注意$錯誤是你已經在你的PSSession中遇到的所有錯誤的數組。此功能會爲您提供有關您遇到的最後一個錯誤的詳細信息。

function Resolve-Error ($ErrorRecord=$Error[0]) 
{ 
    $ErrorRecord | Format-List * -Force 
    $ErrorRecord.InvocationInfo |Format-List * 
    $Exception = $ErrorRecord.Exception 
    for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException)) 
    { "$i" * 80 
     $Exception |Format-List * -Force 
    } 
} 
+5

`$ ErrorRecord.InvocationInfo.PositionMessage`是最好的:) – 2012-06-22 10:42:34

+0

我不知道$ _。Exception.InnerException.Message會工作嗎? – Michele 2014-07-11 13:32:06

+0

這就是我在catch語句中catch [Exception] – Michele 2014-07-11 13:49:23

9

不能從PowerShell腳本代碼的異常中獲取堆棧跟蹤,只能從.NET對象中獲取堆棧跟蹤。要做到這一點,你需要得到異常對象,如這一個:

$Error[0].Exception.StackTrace 
$Error[0].Exception.InnerException.StackTrace 
$Error[0].StackTrace 
2

這裏有一個辦法:Tracing the script stack

它的核心是這樣的代碼:

 
    1..100 | %{ $inv = &{ gv -sc $_ myinvocation } 
15

PowerShell的3.0將一個ScriptStackTrace屬性添加到ErrorRecord對象。我使用該功能的錯誤報告:

function Write-Callstack([System.Management.Automation.ErrorRecord]$ErrorRecord=$null, [int]$Skip=1) 
{ 
    Write-Host # blank line 
    if ($ErrorRecord) 
    { 
     Write-Host -ForegroundColor Red "$ErrorRecord $($ErrorRecord.InvocationInfo.PositionMessage)" 

     if ($ErrorRecord.Exception) 
     { 
      Write-Host -ForegroundColor Red $ErrorRecord.Exception 
     } 

     if ((Get-Member -InputObject $ErrorRecord -Name ScriptStackTrace) -ne $null) 
     { 
      #PS 3.0 has a stack trace on the ErrorRecord; if we have it, use it & skip the manual stack trace below 
      Write-Host -ForegroundColor Red $ErrorRecord.ScriptStackTrace 
      return 
     } 
    } 

    Get-PSCallStack | Select -Skip $Skip | % { 
     Write-Host -ForegroundColor Yellow -NoNewLine "! " 
     Write-Host -ForegroundColor Red $_.Command $_.Location $(if ($_.Arguments.Length -le 80) { $_.Arguments }) 
    } 
} 

skip參數讓我留下寫調用堆棧或任意數量的錯誤處理堆棧幀了GET-PSCallstack上市的。

請注意,如果從catch塊調用,Get-PSCallstack將會丟失throw站點和catch塊之間的任何幀。因此,即使我們每幀的細節較少,我也更喜歡PS 3.0方法。

7

我把我在這裏找到的靈感作爲靈感,創造了一個很好的功能,任何人都可以放入他們的代碼中。

這是我怎麼稱呼它: 寫主機「無法寫入日誌文件`N $(解決錯誤)」 -ForegroundColor紅

Function Resolve-Error 
{ 
<# 
.SYNOPSIS 
    Enumerate error record details. 

.DESCRIPTION 
    Enumerate an error record, or a collection of error record, properties. By default, the details 
    for the last error will be enumerated. 

.PARAMETER ErrorRecord 
    The error record to resolve. The default error record is the lastest one: $global:Error[0]. 
    This parameter will also accept an array of error records. 

.PARAMETER Property 
    The list of properties to display from the error record. Use "*" to display all properties. 
    Default list of error properties is: Message, FullyQualifiedErrorId, ScriptStackTrace, PositionMessage, InnerException 

    Below is a list of all of the possible available properties on the error record: 

    Error Record:    Error Invocation:   Error Exception:     Error Inner Exception(s): 
    $_       $_.InvocationInfo   $_.Exception      $_.Exception.InnerException 
    -------------    -----------------   ----------------     --------------------------- 
    writeErrorStream   MyCommand     ErrorRecord       Data 
    PSMessageDetails   BoundParameters    ItemName       HelpLink 
    Exception     UnboundArguments   SessionStateCategory    HResult 
    TargetObject    ScriptLineNumber   StackTrace       InnerException 
    CategoryInfo    OffsetInLine    WasThrownFromThrowStatement   Message 
    FullyQualifiedErrorId  HistoryId     Message        Source 
    ErrorDetails    ScriptName     Data        StackTrace 
    InvocationInfo    Line      InnerException      TargetSite 
    ScriptStackTrace   PositionMessage    TargetSite       
    PipelineIterationInfo  PSScriptRoot    HelpLink        
           PSCommandPath    Source        
           InvocationName    HResult        
           PipelineLength    
           PipelinePosition    
           ExpectingInput    
           CommandOrigin    
           DisplayScriptPosition  

.PARAMETER GetErrorRecord 
    Get error record details as represented by $_ 
    Default is to display details. To skip details, specify -GetErrorRecord:$false 

.PARAMETER GetErrorInvocation 
    Get error record invocation information as represented by $_.InvocationInfo 
    Default is to display details. To skip details, specify -GetErrorInvocation:$false 

.PARAMETER GetErrorException 
    Get error record exception details as represented by $_.Exception 
    Default is to display details. To skip details, specify -GetErrorException:$false 

.PARAMETER GetErrorInnerException 
    Get error record inner exception details as represented by $_.Exception.InnerException. 
    Will retrieve all inner exceptions if there is more then one. 
    Default is to display details. To skip details, specify -GetErrorInnerException:$false 

.EXAMPLE 
    Resolve-Error 

    Get the default error details for the last error 

.EXAMPLE 
    Resolve-Error -ErrorRecord $global:Error[0,1] 

    Get the default error details for the last two errors 

.EXAMPLE 
    Resolve-Error -Property * 

    Get all of the error details for the last error 

.EXAMPLE 
    Resolve-Error -Property InnerException 

    Get the "InnerException" for the last error 

.EXAMPLE 
    Resolve-Error -GetErrorInvocation:$false 

    Get the default error details for the last error but exclude the error invocation information 

.NOTES 
.LINK 
#> 
    [CmdletBinding()] 
    Param 
    (
     [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] 
     [ValidateNotNullorEmpty()] 
     [array]$ErrorRecord, 

     [Parameter(Mandatory=$false, Position=1)] 
     [ValidateNotNullorEmpty()] 
     [string[]]$Property = ('Message','InnerException','FullyQualifiedErrorId','ScriptStackTrace','PositionMessage'), 

     [Parameter(Mandatory=$false, Position=2)] 
     [switch]$GetErrorRecord = $true, 

     [Parameter(Mandatory=$false, Position=3)] 
     [switch]$GetErrorInvocation = $true, 

     [Parameter(Mandatory=$false, Position=4)] 
     [switch]$GetErrorException = $true, 

     [Parameter(Mandatory=$false, Position=5)] 
     [switch]$GetErrorInnerException = $true 
    ) 

    Begin 
    { 
     ## If function was called without specifying an error record, then choose the latest error that occured 
     If (-not $ErrorRecord) 
     { 
      If ($global:Error.Count -eq 0) 
      { 
       # The `$Error collection is empty 
       Return 
      } 
      Else 
      { 
       [array]$ErrorRecord = $global:Error[0] 
      } 
     } 

     ## Define script block for selecting and filtering the properties on the error object 
     [scriptblock]$SelectProperty = { 
      Param 
      (
       [Parameter(Mandatory=$true)] 
       [ValidateNotNullorEmpty()] 
       $InputObject, 

       [Parameter(Mandatory=$true)] 
       [ValidateNotNullorEmpty()] 
       [string[]]$Property 
      ) 
      [string[]]$ObjectProperty = $InputObject | Get-Member -MemberType *Property | Select-Object -ExpandProperty Name 
      ForEach ($Prop in $Property) 
      { 
       If ($Prop -eq '*') 
       { 
        [string[]]$PropertySelection = $ObjectProperty 
        Break 
       } 
       ElseIf ($ObjectProperty -contains $Prop) 
       { 
        [string[]]$PropertySelection += $Prop 
       } 
      } 
      Write-Output $PropertySelection 
     } 

     # Initialize variables to avoid error if 'Set-StrictMode' is set 
     $LogErrorRecordMsg  = $null 
     $LogErrorInvocationMsg = $null 
     $LogErrorExceptionMsg = $null 
     $LogErrorMessageTmp  = $null 
     $LogInnerMessage  = $null 
    } 
    Process 
    { 
     ForEach ($ErrRecord in $ErrorRecord) 
     { 
      ## Capture Error Record 
      If ($GetErrorRecord) 
      { 
       [string[]]$SelectedProperties = &$SelectProperty -InputObject $ErrRecord -Property $Property 
       $LogErrorRecordMsg = $ErrRecord | Select-Object -Property $SelectedProperties 
      } 

      ## Error Invocation Information 
      If ($GetErrorInvocation) 
      { 
       If ($ErrRecord.InvocationInfo) 
       { 
        [string[]]$SelectedProperties = &$SelectProperty -InputObject $ErrRecord.InvocationInfo -Property $Property 
        $LogErrorInvocationMsg = $ErrRecord.InvocationInfo | Select-Object -Property $SelectedProperties 
       } 
      } 

      ## Capture Error Exception 
      If ($GetErrorException) 
      { 
       If ($ErrRecord.Exception) 
       { 
        [string[]]$SelectedProperties = &$SelectProperty -InputObject $ErrRecord.Exception -Property $Property 
        $LogErrorExceptionMsg = $ErrRecord.Exception | Select-Object -Property $SelectedProperties 
       } 
      } 

      ## Display properties in the correct order 
      If ($Property -eq '*') 
      { 
       # If all properties were chosen for display, then arrange them in the order 
       # the error object displays them by default. 
       If ($LogErrorRecordMsg)  {[array]$LogErrorMessageTmp += $LogErrorRecordMsg } 
       If ($LogErrorInvocationMsg) {[array]$LogErrorMessageTmp += $LogErrorInvocationMsg} 
       If ($LogErrorExceptionMsg) {[array]$LogErrorMessageTmp += $LogErrorExceptionMsg } 
      } 
      Else 
      { 
       # Display selected properties in our custom order 
       If ($LogErrorExceptionMsg) {[array]$LogErrorMessageTmp += $LogErrorExceptionMsg } 
       If ($LogErrorRecordMsg)  {[array]$LogErrorMessageTmp += $LogErrorRecordMsg } 
       If ($LogErrorInvocationMsg) {[array]$LogErrorMessageTmp += $LogErrorInvocationMsg} 
      } 

      If ($LogErrorMessageTmp) 
      { 
       $LogErrorMessage = 'Error Record:' 
       $LogErrorMessage += "`n-------------" 
       $LogErrorMsg  = $LogErrorMessageTmp | Format-List | Out-String 
       $LogErrorMessage += $LogErrorMsg 
      } 

      ## Capture Error Inner Exception(s) 
      If ($GetErrorInnerException) 
      { 
       If ($ErrRecord.Exception -and $ErrRecord.Exception.InnerException) 
       { 
        $LogInnerMessage = 'Error Inner Exception(s):' 
        $LogInnerMessage += "`n-------------------------" 

        $ErrorInnerException = $ErrRecord.Exception.InnerException 
        $Count = 0 

        While ($ErrorInnerException) 
        { 
         $InnerExceptionSeperator = '~' * 40 

         [string[]]$SelectedProperties = &$SelectProperty -InputObject $ErrorInnerException -Property $Property 
         $LogErrorInnerExceptionMsg = $ErrorInnerException | Select-Object -Property $SelectedProperties | Format-List | Out-String 

         If ($Count -gt 0) 
         { 
          $LogInnerMessage += $InnerExceptionSeperator 
         } 
         $LogInnerMessage += $LogErrorInnerExceptionMsg 

         $Count++ 
         $ErrorInnerException = $ErrorInnerException.InnerException 
        } 
       } 
      } 

      If ($LogErrorMessage) { $Output += $LogErrorMessage } 
      If ($LogInnerMessage) { $Output += $LogInnerMessage } 

      Write-Output $Output 

      If (Test-Path -Path 'variable:Output'   ) { Clear-Variable -Name Output    } 
      If (Test-Path -Path 'variable:LogErrorMessage' ) { Clear-Variable -Name LogErrorMessage } 
      If (Test-Path -Path 'variable:LogInnerMessage' ) { Clear-Variable -Name LogInnerMessage } 
      If (Test-Path -Path 'variable:LogErrorMessageTmp') { Clear-Variable -Name LogErrorMessageTmp } 
     } 
    } 
    End {} 
} 
0

您也可以更改默認格式錯誤對象包含堆棧跟蹤。基本上,通過從$ PSHOME \ PowerShellCore.format.ps1xml中複製System.Management.Automation.ErrorRecord的塊並添加您自己的添加跟蹤的 元素來製作格式文件。然後使用Update-FormatData加載它。有關更多詳細信息,我剛剛寫了一篇博客文章:https://blogs.msdn.microsoft.com/sergey_babkins_blog/2016/12/28/getting-a-stack-trace-in-powershell/

哦,還有一件事:它不會自動傳播到遠程會話。這些對象被格式化爲遠程端的字符串。對於遠程會話中的堆棧跟蹤,您必須將該文件上傳到那裏,然後再次調用Update-FormatData。

0

我只是想通了。 $ _是捕獲塊中捕獲的異常。

$errorString= $_ | Out-String 
相關問題