Try / catch似乎没有效果

我是新来的PowerShell,我试图通过try / catch语句添加error handling,但他们似乎并没有捕捉到错误。 这是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 { } 

当它无法联系到特定的机器,我得到了这个在控制台,而不是我干净的catch消息:

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

当试图运行远程WMI查询时,我能够复制结果。 抛出的exception不会被Try / Catch捕获,陷阱也不会捕获它,因为它不是“终止错误”。 在PowerShell中,有终止错误和非终止错误。 看起来Try / Catch / Finally和Trap只能用于终止错误。

它被logging到$ error自动variables,你可以通过查看$?来testing这些types的非终止错误。 自动variables,它会让你知道如果最后一次操作成功($ true)或失败($ false)。

从生成的错误的外观看来,错误被返回并且不包含在可捕获的exception中。 下面是生成的错误的一个痕迹。

 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 } 

如果你想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函数接受scriptblocks,以便您的try catch调用不是kludge。 我有我的返回true / false,以防万一我需要检查是否有错误…但它不必。 另外,exception日志logging是可选的,可以在catch中处理,但是我发现自己总是在catch块中调用日志loggingfunction,所以我将它添加到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"; } 

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

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

添加“-EA Stop”为我解决了这个问题。

这是我的解决scheme。 当Set-Location失败时,它会抛出一个catch块没有看到的非终止错误。 添加-ErrorAction Stop是最简单的方法。

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

编辑:如注释中所述,以下解决scheme仅适用于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..." } 

否则,你将不得不使用exception陷阱 。