Try/catch, похоже, не имеет эффекта



Я новичок в powershell, и я пытаюсь добавить обработку ошибок с помощью операторов try/catch, но они, похоже, на самом деле не ловят ошибку. Это PowerShell версии 2 СП3.



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

try
{
$colItems = get-wmiobject -class "Win32_PhysicalMemory" -namespace "rootCIMV2" -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
{ }


когда он не может связаться с конкретной машиной, я получаю это в консоли, а не мое сообщение clean catch:




Get-WmiObject : The RPC server is

unavailable. (Exception from HRESULT:

0x800706BA) At Z:.0 Intern

ProgramvarePowershellGet memory of

all computers in AD.ps1:25 char:34

+ $colItems = get-wmiobject <<<< -class "Win32_PhysicalMemory"

-namespace "rootCIMV2" -computername $strComputerName -Credential

$credentials

+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],

COMException

+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand


739   6  

6 ответов:

мне удалось скопировать ваш результат при попытке запустить удаленный запрос WMI. Брошенное исключение не поймано Try/Catch, и ловушка не поймает его, так как это не "завершающая ошибка". В PowerShell существуют завершающие и не завершающие ошибки . Похоже, что Try/Catch / Finally и Trap работают только с завершающими ошибками.

он записывается в автоматическую переменную $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
    }

Если вы хотите, чтобы 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 на случай, если мне нужно проверить, была ли ошибка... но это не обязательно. Кроме того, ведение журнала исключений является необязательным и может быть выполнено в 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";
    }

также можно задать параметр действия ошибки для отдельных командлетов, а не только для всего сценария. Это делается с помощью параметра 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;
}

добавление "- EA Stop " решило это для меня.

Это мое решение. Когда Set-Location терпит неудачу, он выдает непрекращающуюся ошибку, которая не видна блоком catch. Добавление -ErrorAction не остановить это самый простой способ решения этой проблемы.

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

Edit: как указано в комментариях, следующее решение применяется только к 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..."
}

в противном случае вам придется использовать исключения запутывания.

Comments

    Ничего не найдено.