尝试/捕获似乎没有效果


73

我是PowerShell的新手,我正尝试通过try / catch语句添加错误处理,但它们似乎并未真正捕获错误。这是Powershell v2 CP3。

$objComputer = $objResult.Properties;
$strComputerName = $objComputer.name
write-host "Checking machine: " $strComputerName

try
{
    $colItems = get-wmiobject -class "Win32_PhysicalMemory" -namespace "root\CIMV2" -computername $strComputerName -Credential $credentials
    foreach ($objItem in $colItems) 
    {
        write-host "Bank Label: " $objItem.BankLabel
        write-host "Capacity: " ($objItem.Capacity / 1024 / 1024)
        write-host "Caption: " $objItem.Caption
        write-host "Creation Class Name: " $objItem.CreationClassName      
        write-host
    }
}
Catch 
{
    write-host "Failed to get data from machine (Error:"  $_.Exception.Message ")"
    write-host
}
finally 
{ }  

当它无法与特定计算机联系时,我会在控制台中收到此消息,而不是我的干净捕获消息:

Get-WmiObject : The RPC server is
unavailable. (Exception from HRESULT:
0x800706BA) At Z:\7.0 Intern
Programvare\Powershell\Get memory of
all computers in AD.ps1:25 char:34
+ $colItems = get-wmiobject <<<< -class "Win32_PhysicalMemory"
-namespace "root\CIMV2" -computername $strComputerName -Credential
$credentials
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],
COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Answers:


77

尝试运行远程WMI查询时,我能够复制您的结果。引发的异常不会被“尝试/捕获”捕获,陷阱也不会捕获,因为它不是“终止错误”。在PowerShell中,存在终止错误和非终止错误。似乎“尝试/捕获/最终和陷阱”仅在出现终止错误时起作用。

它被记录到$ error自动变量中,您可以通过查看$?来测试这些类型的非终止错误。自动变量,它将使您知道上一次操作是成功($ true)还是失败($ false)。

从生成的错误的外观来看,似乎返回了错误并且未将其包装在可捕获的异常中。下面是生成的错误的痕迹。

PS C:\scripts\PowerShell> Trace-Command -Name errorrecord  -Expression {Get-WmiObject win32_bios -ComputerName HostThatIsNotThere}  -PSHost
DEBUG: InternalCommand Information: 0 :  Constructor Enter Ctor
Microsoft.PowerShell.Commands.GetWmiObjectCommand: 25857563
DEBUG: InternalCommand Information: 0 :  Constructor Leave Ctor
Microsoft.PowerShell.Commands.GetWmiObjectCommand: 25857563
DEBUG: ErrorRecord Information: 0 :  Constructor Enter Ctor
System.Management.Automation.ErrorRecord: 19621801 exception =
System.Runtime.InteropServices.COMException (0x800706BA): The RPC
server is unavailable. (Exception from HRESULT: 0x800706BA)
   at
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Management.ManagementScope.InitializeGuts(Object o)
   at System.Management.ManagementScope.Initialize()
   at System.Management.ManagementObjectSearcher.Initialize()
   at System.Management.ManagementObjectSearcher.Get()
   at Microsoft.PowerShell.Commands.GetWmiObjectCommand.BeginProcessing()
errorId = GetWMICOMException errorCategory = InvalidOperation
targetObject =
DEBUG: ErrorRecord Information: 0 :  Constructor Leave Ctor
System.Management.Automation.ErrorRecord: 19621801

解决您的代码的方法可能是:

try
{
    $colItems = get-wmiobject -class "Win32_PhysicalMemory" -namespace "root\CIMV2" -computername $strComputerName -Credential $credentials
    if ($?)
    {
      foreach ($objItem in $colItems) 
      {
          write-host "Bank Label: " $objItem.BankLabel
          write-host "Capacity: " ($objItem.Capacity / 1024 / 1024)
          write-host "Caption: " $objItem.Caption
          write-host "Creation Class Name: " $objItem.CreationClassName      
          write-host
      }
    }
    else
    {
       throw $error[0].Exception
    }

70
您可以使用以下命令来引发非终止错误:-ErrorAction“ Stop”(或简称为-EA“ Stop”)
JasonMArcher

7
@JasonMArcher-正确!将$ ErrorActionPreference设置为'Stop'也可以,但会产生全局影响。
史蒂芬·穆拉夫斯基

2
@Steven Murawski-除非您在FInally块中取消设置。
Yevgeniy

@JasonMArcher不知道这是否可以与引发异常的.net方法调用一起工作
Andrew Savinykh

3
执行关键行之前,请不要忘记清除错误集合。$error.Clear()
Erno

63

如果希望try / catch处理所有错误(而不仅仅是终止错误),则可以通过设置ErrorActionPreference来手动终止所有错误。

try {

   $ErrorActionPreference = "Stop"; #Make all errors terminating
   get-item filethatdoesntexist; # normally non-terminating
   write-host "You won't hit me";  
} catch{
   Write-Host "Caught the exception";
   Write-Host $Error[0].Exception;
}finally{
   $ErrorActionPreference = "Continue"; #Reset the error action pref to default
}

或者...您可以制作自己的trycatch函数,该函数接受脚本块,这样您的try catch调用就不会那么麻烦了。我有我的返回true / false,以防万一我需要检查是否有错误...但是不必这样做。另外,异常日志记录是可选的,可以在catch中进行处理,但是我发现自己总是在catch块中调用日志记录功能,因此我将其添加到try catch函数中。

function log([System.String] $text){write-host $text;}

function logException{
    log "Logging current exception.";
    log $Error[0].Exception;
}


function mytrycatch ([System.Management.Automation.ScriptBlock] $try,
                    [System.Management.Automation.ScriptBlock] $catch,
                    [System.Management.Automation.ScriptBlock]  $finally = $({})){



# Make all errors terminating exceptions.
    $ErrorActionPreference = "Stop";

    # Set the trap
    trap [System.Exception]{
        # Log the exception.
        logException;

        # Execute the catch statement
        & $catch;

        # Execute the finally statement
        & $finally

        # There was an exception, return false
        return $false;
    }

    # Execute the scriptblock
    & $try;

    # Execute the finally statement
    & $finally

    # The following statement was hit.. so there were no errors with the scriptblock
    return $true;
}


#execute your own try catch
mytrycatch {
        gi filethatdoesnotexist; #normally non-terminating
        write-host "You won't hit me."
    } {
        Write-Host "Caught the exception";
    }

尝试使用“ ::尝试除以零:$(0/0)”(而不使用get-item filethatdoesntexist;)。然后,它不会捕获该异常
Kiquenet 2012年

16

还可以在单​​个cmdlet上设置错误操作首选项,而不仅仅是对整个脚本。使用所有cmdlet上可用的参数ErrorAction(alisa EA)完成此操作。

try 
{
 Write-Host $ErrorActionPreference; #Check setting for ErrorAction - the default is normally Continue
 get-item filethatdoesntexist; # Normally generates non-terminating exception so not caught
 write-host "You will hit me as exception from line above is non-terminating";  
 get-item filethatdoesntexist -ErrorAction Stop; #Now ErrorAction parameter with value Stop causes exception to be caught 
 write-host "you won't reach me as exception is now caught";
}
catch
{
 Write-Host "Caught the exception";
 Write-Host $Error[0].Exception;
}

10

这是我的解决方案。当Set-Location失败时,它将引发一个非终止错误,catch块不会看到该错误。添加-ErrorAction Stop是解决此问题的最简单方法。

try {
    Set-Location "$YourPath" -ErrorAction Stop;
} catch {
    Write-Host "Exception has been caught";
}


1

编辑:如评论所述,以下解决方案仅适用于PowerShell V1。

有关如何实现此功能的详细信息,请参见此博客文章“ Adam Weigert的技术历险记”

用法示例(从Adam Weigert的博客复制/粘贴):

Try {
    echo " ::Do some work..."
    echo " ::Try divide by zero: $(0/0)"
} -Catch {
    echo "  ::Cannot handle the error (will rethrow): $_"
    #throw $_
} -Finally {
    echo " ::Cleanup resources..."
}

否则,您将不得不使用异常捕获



1
Try / Catch / Finally在PowerShell的V1中不存在,但在V2中存在。
史蒂芬·穆拉夫斯基

0

就我而言,这是因为我仅捕获特定类型的异常:

try
  {
    get-item -Force -LiteralPath $Path -ErrorAction Stop

    #if file exists
    if ($Path -like '\\*') {$fileType = 'n'}  #Network
    elseif ($Path -like '?:\*') {$fileType = 'l'} #Local
    else {$fileType = 'u'} #Unknown File Type

  }
catch [System.UnauthorizedAccessException] {$fileType = 'i'} #Inaccessible
catch [System.Management.Automation.ItemNotFoundException]{$fileType = 'x'} #Doesn't Exist

添加了这些功能以处理导致终止错误的其他异常以及意外异常

catch [System.Management.Automation.DriveNotFoundException]{$fileType = 'x'} #Doesn't Exist
catch {$fileType='u'} #Unknown
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.