У Try/catch нет эффекта
Я новичок в 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
Ответы
Ответ 1
Я смог дублировать ваш результат при попытке запустить удаленный запрос WMI. Исключенное исключение не поймано Try/Catch, и ловушка не поймает его, поскольку это не "завершающая ошибка". В PowerShell есть ошибки завершения и ошибки, не связанные с завершением. Похоже, что Try/Catch/Finally и Trap работают только с завершающими ошибками.
Он записывается в автоматическую переменную $error, и вы можете протестировать для этого типа ошибок без конца, посмотрев на $? автоматическая переменная, которая сообщит вам, была ли последняя операция успешной ($ true) или не выполнена ($ false).
С появлением возникшей ошибки представляется, что ошибка возвращается и не завершается в catchable 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
}
Ответ 2
Если вы хотите, чтобы 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, которая принимает скриптовые блоки, чтобы ваши вызовы catch catch не были как kludge. Я верю 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";
}
Ответ 3
Также возможно установить предпочтительное действие для отдельных командлетов, а не только для всего script. Это делается с помощью параметра 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;
}
Ответ 4
Это мое решение. При сбое Set-Location он выдает ошибку, не зависящую от завершения, которая не рассматривается блоком catch. Добавление -ErrorAction Stop - это самый простой способ.
try {
Set-Location "$YourPath" -ErrorAction Stop;
} catch {
Write-Host "Exception has been caught";
}
Ответ 5
Добавление "-EA Stop" решило это для меня.
Ответ 6
Изменить: Как указано в комментариях, следующее решение относится только к PowerShell V1.
Смотрите этот пост в блоге "Технические приключения Адама Вейгерт" для получения подробной информации о том, как реализовать это.
Пример использования (копирование/вставка из блога Адама Вейгерт):
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..."
}
В противном случае вам придется использовать исключение исключения.
Ответ 7
В моем случае это было потому, что я ловил только определенные типы исключений:
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