【问题标题】:Can I get detailed exception stacktrace in PowerShell?我可以在 PowerShell 中获得详细的异常堆栈跟踪吗?
【发布时间】:2009-04-28 00:07:46
【问题描述】:

运行这样的脚本:

 1: function foo()
 2: {
 3:    bar
 4: }
 5: 
 6: function bar()
 7: {
 8:     throw "test"
 9: }
10: 
11: foo

我明白了

test
At C:\test.ps1:8 char:10

我可以获取详细的堆栈跟踪吗?

At bar() in C:\test.ps1:8
At foo() in C:\test.ps1:3 
At C:\test.ps1:11

【问题讨论】:

    标签: exception powershell stack-trace


    【解决方案1】:

    有一个名为 Resolve-Error 的 function up on the PowerShell Team blog 可以为您提供各种详细信息

    请注意,$error 是您在 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
       }
    }
    

    【讨论】:

    • $ErrorRecord.InvocationInfo.PositionMessage 是最好的:)
    • 这就是我在带有 catch [Exception] 的 catch 语句中所拥有的内容
    【解决方案2】:

    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 参数让我可以将 Write-Callstack 或任意数量的错误处理堆栈帧排除在 Get-PSCallstack 列表之外。

    请注意,如果从 catch 块调用,Get-PSCallstack 将错过 throw 站点和 catch 块之间的任何帧。因此,我更喜欢 PS 3.0 方法,即使我们每帧的细节更少。

    【讨论】:

    • “Trace”命令有什么作用?我收到一个找不到的错误,这是你写的吗?
    • 是的,Trace 是一个写入日志文件的内部函数。替换为您选择的日志记录方法,也许是 Write-Host。
    【解决方案3】:

    有自动变量$StackTrace,但它似乎更具体地关注内部 PS 细节,而不是真正关心你的脚本,所以这不会有太大帮助。

    还有Get-PSCallStack,但不幸的是,一旦你遇到异常,它就消失了。但是,您可以在脚本中的每次抛出之前添加 Get-PSCallStack。这样您就可以在遇到异常之前立即获得堆栈跟踪。

    我认为可以通过使用 Powershell 的调试和跟踪功能来编写这样的功能,但我怀疑这很容易。

    【讨论】:

    • 我们应该提交增强请求(如果尚未提交)以自动将其添加到例外中。
    • 此功能已在 PS 3.0 中添加。我用示例代码发布了一个答案。
    • 如果我还没有编写进行投掷的代码,这将无济于事:-(
    【解决方案4】:

    您无法从脚本的 PowerShell 代码异常中获取堆栈跟踪,只能从 .NET 对象中获取。为此,您需要获取 Exception 对象,如下所示:

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

    【讨论】:

    • $Error[0].ScriptStackTrace 是唯一给我有用的堆栈信息的。
    【解决方案5】:

    我将这里的发现作为灵感,并创建了一个很好的函数,任何人都可以将其放入他们的代码中。

    我是这样称呼它的: Write-Host "无法写入日志文件`n$(Resolve-Error)" -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 {}
    }
    

    【讨论】:

      【解决方案6】:

      这段代码:

      try {
          ...
      }
      catch {
          Write-Host $_.Exception.Message -Foreground "Red"
          Write-Host $_.ScriptStackTrace -Foreground "DarkGray"
          exit 1
      }
      

      将以下列格式回显错误:

      No match was found for the specified search criteria and module names 'psake'.
      at Get-InstalledModule<Process>, ...\PSModule.psm1: line 9251
      at Import-ModuleThirdparty, ...\Import-ModuleThirdparty.psm1: line 3
      at <ScriptBlock>, ...\index.ps1: line 13
      

      【讨论】:

        【解决方案7】:

        这里有一个方法:Tracing the script stack

        它的核心是这段代码:

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

        【讨论】:

          【解决方案8】:

          我刚刚想通了。 $_ 是在 catch 块中捕获的异常。

          $errorString= $_ | Out-String 
          

          【讨论】:

            【解决方案9】:

            您还可以更改错误对象的默认格式以包含堆栈跟踪。基本上,通过从 $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。

            【讨论】:

            • 您必须更改每台机器上的配置,即运行脚本。首选行为是让脚本始终运行,而不仅仅是“在我的机器上”。
            【解决方案10】:

            偶然发现这个正在寻找一个内置的解决方案。我将采用简单的解决方案。只需在使用任何 powershell 之前添加跟踪块。这将确保显示调用堆栈。不利的一面是堆栈将显示在错误消息之前。

            Trace {
               $_.ScriptStackTrace
            }
            

            【讨论】:

              【解决方案11】:

              也许我误解了一些东西,但我的问题是我没有看到内部异常的 powershell 脚本堆栈跟踪。

              最后,我在 $Global:Error 中搜索异常的 Error Eecord 对象以检索脚本堆栈跟踪。

              <#
              .SYNOPSIS
                 Expands all inner exceptions and provides Script Stack Traces where available by mapping Exceptions to ErrorRecords
              
              .NOTES
                 Aggregate exceptions aren't full supported, and their child exceptions won't be traversed like regular inner exceptions
                 
              #>
              function Get-InnerErrors ([Parameter(ValueFrompipeline)] $ErrorObject=$Global:Error[0])
              {
                 # Get the first exception object from the input error
                 $ex = $null
                 if( $ErrorObject -is [System.Management.Automation.ErrorRecord] ){
                     $ex = $ErrorObject.Exception 
                 }
                 elseif( $ErrorObject -is [System.Exception] ){
                     $ex = $ErrorObject
                 } 
                 else
                 {
                     throw "Unexpected error type for Get-InnerErrors: $($ErrorObject.GetType()):`n $ErrorObject"
                 }
              
                 Write-Debug "Walking inner exceptions from exception"
                 for ($i = 0; $ex; $i++, ($ex = $ex.InnerException))
                 {  
                     $ErrorRecord = $null
              
                     if( $ex -is [System.Management.Automation.IContainsErrorRecord] ){ 
              
                         Write-Debug "Inner Exception $i : Skipping search for ErrorRecord in `$Global:Error, exception type implements IContainsErrorRecord" 
                         $ErrorRecord = ([System.Management.Automation.IContainsErrorRecord]$ex).ErrorRecord
                     }
                     else {
              
                         # Find ErrorRecord for exception by mapping exception to ErrorRecrods in $Global:Error
              
                         ForEach( $err in $Global:Error ){# Need to use Global scope when referring from a module
                             if( $err -is [System.Management.Automation.ErrorRecord] ){
                                if( $err.Exception -eq $ex ){
                                     $ErrorRecord = $err 
                                     Write-Debug "Inner Exception $i : Found ErrorRecord in `$Global:Error" 
                                     break
                                 }
                             } 
                             elseif( $err -is [System.Management.Automation.IContainsErrorRecord] ) {
                                 if( $err -eq $ex -or $err.ErrorRecord.Exception -eq $ex ){
                                     $ErrorRecord = $err.ErrorRecord
                                     Write-Debug "Inner Exception $i : Found ErrorRecord in `$Global:Error" 
                                     break
                                 }
                             } 
                             else {
                                 Write-Warning "Unexpected type in `$Global:Error[]. Expected `$Global:Error to always be an ErrorRecrod OR exception implementing IContainsErrorRecord but found type: $($err.GetType())"
                             }
                         }
                     }
              
                     if( -not($ErrorRecord) ){
                         Write-Debug "Inner Exception $i : No ErrorRecord could be found for exception of type: $($ex.GetType())" 
                     }
                     
                    
                     # Return details as custom object
              
                     [PSCustomObject] @{
                         ExceptionDepth      = $i
                         Message             = $ex.Message
                         ScriptStackTrace    = $ErrorRecord.ScriptStackTrace  # Note ErrorRecord will be null if exception was not from Powershell
                         ExceptionType       = $ex.GetType().FullName
                         ExceptionStackTrace = $ex.StackTrace
                     }
                 }
              }
              

              示例用法:

              function Test-SqlConnection
              {
                  $ConnectionString = "ThisConnectionStringWillFail"
                  try{
                      $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $ConnectionString;
                      $sqlConnection.Open();
                  }
                  catch
                  {
                      throw [System.Exception]::new("Sql connection failed with connection string: '$ConnectionString'", $_.Exception)
                  }
                  finally
                  {
                      if($sqlConnection){
                          $sqlConnection.Close();
                      }
                  }
              }
              
              
              try{
                  Test-SqlConnection
              }
              catch {
                  Get-InnerErrors $_
              }
              

              示例输出:

              
              
              ExceptionDepth      : 0
              Message             : Sql connection failed with connection string: 'ThisConnectionStringWillFail'
              ScriptStackTrace    : at Test-SqlConnection, <No file>: line 11
                                    at <ScriptBlock>, <No file>: line 23
              ExceptionType       : System.Exception
              ExceptionStackTrace : 
              
              ExceptionDepth      : 1
              Message             : Exception calling ".ctor" with "1" argument(s): "Format of the initialization string does not conform to specification starting at index 0."
              ScriptStackTrace    : 
              ExceptionType       : System.Management.Automation.MethodInvocationException
              ExceptionStackTrace :    at System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArguments)
                                       at System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
                                       at Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)
              
              ExceptionDepth      : 2
              Message             : Format of the initialization string does not conform to specification starting at index 0.
              ScriptStackTrace    : 
              ExceptionType       : System.ArgumentException
              ExceptionStackTrace :    at System.Data.Common.DbConnectionOptions.GetKeyValuePair(String connectionString, Int32 currentPosition, StringBuilder buffer, Boolean useOdbcRules, String& keyname, String& 
                                    keyvalue)
                                       at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
                                       at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
                                       at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
                                       at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
                                       at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
                                       at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
                                       at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
                                       at System.Data.SqlClient.SqlConnection..ctor(String connectionString, SqlCredential credential)
              

              【讨论】:

                【解决方案12】:

                在某些情况下,PowerShell 似乎不保留回溯,例如调用方法或使用 .Invoke() 调用函数。为此,Set-PSDebug -Trace 2 可能会派上用场。它将打印运行脚本的每一行。

                尝试在 (1) 和 (2) 上翻转 # 并运行 WrapStackTraceLog({ function f{ 1/0 } ; &amp; f }) # let's divide by zero

                Function WrapStackTraceLog($func) {
                    try {
                        # return $func.Invoke($args)  # (1)
                        return (& $func $args)  # (2)
                    } catch {
                        Write-Host ('=' * 70)
                        Write-Host $_.Exception.Message
                        Write-Host ('-' * 70)
                        Write-Host $_.ScriptStackTrace
                        Write-Host ('-' * 70)
                        Write-Host "$StackTrace"
                        Write-Host ('=' * 70)
                    }
                }
                

                捕捉到分支 (1) 异常:

                Exception calling "Invoke" with "1" argument(s): "Attempted to divide by zero."
                

                分支 (2) 提供更多信息:

                at f, <No file>: line 1
                at <ScriptBlock>, <No file>: line 1
                at global:WrapStackTraceLog, <No file>: line 4
                at <ScriptBlock>, <No file>: line 1
                

                但是,您仍然可以在分支 (1) 上跟踪您的调用:

                DEBUG:     ! CALL function 'f'
                DEBUG:    1+ WrapStackTraceLog({ function f{  >>>> 1/0 } ; & f })
                DEBUG:    6+          >>>> Write-Host ('=' * 70)
                ======================================================================
                DEBUG:    7+          >>>> Write-Host $_.Exception.Message
                Exception calling "Invoke" with "1" argument(s): "Attempted to divide by zero."
                

                【讨论】:

                  猜你喜欢
                  • 2019-11-05
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-03-30
                  • 1970-01-01
                  • 2014-03-04
                  • 2011-01-05
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多