2009-04-28 41 views

Trả lời

14

Có biến tự động $StackTrace nhưng nó có vẻ là một chút cụ thể hơn đến các chi tiết PS nội bộ hơn là thực sự quan tâm đến kịch bản của bạn, do đó sẽ không giúp được gì nhiều.

Ngoài ra còn có Get-PSCallStack nhưng đã biến mất ngay khi bạn nhấn ngoại lệ, thật không may. Tuy nhiên, bạn có thể đặt Get-PSCallStack trước mỗi lần ném trong tập lệnh của mình. Bằng cách đó bạn nhận được một dấu vết ngăn xếp ngay lập tức trước khi nhấn một ngoại lệ.

Tôi nghĩ rằng người ta có thể viết chức năng như vậy bằng cách sử dụng tính năng gỡ lỗi và truy tìm của Powershell nhưng tôi nghi ngờ nó sẽ dễ dàng.

+4

Chúng tôi phải gửi yêu cầu nâng cao (nếu nó chưa được gửi) để điều này tự động được thêm vào ngoại lệ. – JasonMArcher

+0

Chức năng này đã được thêm vào trong PS 3.0. Tôi đã đăng một câu trả lời với mã ví dụ. – Timbo

+0

Không giúp được gì nếu tôi chưa viết mã thực hiện lệnh ném :-( – bacar

32

Có một function up on the PowerShell Team blog gọi Resolve-Lỗi này sẽ giúp bạn có được tất cả các loại chi tiết

Lưu ý rằng $ lỗi là một mảng của tất cả các lỗi bạn đã gặp phải trong PSSession của bạn. Hàm này sẽ cung cấp cho bạn chi tiết về lỗi cuối cùng bạn gặp phải.

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' là tốt nhất :) –

+0

Tôi tự hỏi nếu $ _. Exception.InnerException.Message có hoạt động không? – Michele

+0

Đó là những gì tôi có trong một tuyên bố bắt với bắt [Ngoại lệ] – Michele

9

Bạn không thể lấy dấu vết ngăn xếp từ ngoại lệ của mã PowerShell của tập lệnh, chỉ từ đối tượng .NET. Để làm điều đó, bạn sẽ cần phải nhận được các đối tượng ngoại lệ như một trong những:

$Error[0].Exception.StackTrace 
$Error[0].Exception.InnerException.StackTrace 
$Error[0].StackTrace 
+1

$ Lỗi [0] .ScriptStackTrace là người duy nhất cung cấp cho tôi bất kỳ thông tin ngăn xếp hữu ích nào. – rob

2

Đây là một cách: Tracing the script stack

Cốt lõi của nó là mã này:

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

Liên kết dường như đã chết. –

+1

@BenThul: Đã sửa lỗi. –

15

Powershell 3.0 thêm một thuộc tính ScriptStackTrace vào đối tượng ErrorRecord. Tôi sử dụng chức năng này để báo cáo lỗi:

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 }) 
    } 
} 

Tham số Bỏ qua cho phép tôi thoát khỏi Chặn cuộc gọi hoặc bất kỳ số khung xử lý lỗi nào trong danh sách Get-PSCallstack.

Lưu ý rằng nếu được gọi từ khối bắt, Get-PSCallstack sẽ bỏ lỡ bất kỳ khung nào giữa vị trí ném và khối đánh bắt. Do đó tôi thích phương pháp PS 3.0 mặc dù chúng tôi có ít chi tiết hơn cho mỗi khung hình.

+0

Lệnh "Dấu vết" làm gì? Tôi nhận được một lỗi mà nó không được tìm thấy, là một cái gì đó bạn đã viết? –

+0

Có, Dấu vết là hàm nội bộ ghi vào tệp nhật ký. Thay thế bằng phương pháp ghi nhật ký bạn chọn, có lẽ là Máy chủ lưu trữ. – Timbo

7

Tôi lấy những gì tôi tìm thấy ở đây là nguồn cảm hứng và tạo ra một chức năng tốt đẹp mà bất cứ ai cũng có thể rơi vào mã của họ.

Đây là cách tôi gọi nó là: Write-Host "Không thể ghi vào file log` n $ (Resolve-Lỗi)" -ForegroundColor Red

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

Bạn cũng có thể thay đổi mặc định định dạng cho đối tượng lỗi để bao gồm dấu vết ngăn xếp. Về cơ bản, hãy tạo tệp định dạng của bạn bằng cách sao chép đoạn mã cho System.Management.Automation.ErrorRecord từ $ PSHOME \ PowerShellCore.format.ps1xml và thêm phần tử của riêng bạn để thêm dấu vết.Sau đó tải nó với Update-FormatData. Để biết thêm chi tiết, tôi vừa viết một bài đăng blog về nó: https://blogs.msdn.microsoft.com/sergey_babkins_blog/2016/12/28/getting-a-stack-trace-in-powershell/

Ồ, một điều nữa: điều này không tự động lan truyền vào các phiên từ xa. Các đối tượng được định dạng thành chuỗi ở phía xa. Đối với các dấu vết ngăn xếp trong các phiên từ xa, bạn sẽ phải tải lên tệp này ở đó và gọi Update-FormatData ở đó một lần nữa.

+1

Bạn phải thay đổi cấu hình trên mỗi máy, chạy tập lệnh. Hành vi ưa thích là có tập lệnh, chạy liên tục, không phải chỉ trên máy của tôi. –

0

Tôi đã tìm ra. $ _ Là ngoại lệ bị bắt trong khối catch.

$errorString= $_ | Out-String 
Các vấn đề liên quan