2009-07-17 7 views
49

Ich bin neu in Powershell, und ich versuche, Fehlerbehandlung über Try/Catch-Anweisungen hinzuzufügen, aber sie scheinen nicht tatsächlich den Fehler zu fangen. Dies ist Powershell v2 CP3.Try/Catch scheint keinen Effekt zu haben

$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 
{ } 

Wenn es eine bestimmte Maschine kontaktieren ausfällt, bekomme ich diese in der Konsole, und nicht meine sauber Fang Nachricht:

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

+0

@EKS Ich aktualisierte meine Antwort mit einer Problemumgehung. –

Antwort

54

Ich konnte Ihr Ergebnis duplizieren, wenn Sie versuchen, eine Remote-WMI-Abfrage auszuführen. Die ausgelöste Ausnahme wird nicht von Try/Catch abgefangen, noch wird sie von einer Trap abgefangen, da es sich nicht um einen "terminierenden Fehler" handelt. In der PowerShell gibt es Terminierungsfehler und nicht terminierende Fehler. Scheinbar funktioniert Try/Catch/Finally und Trap nur mit Abbruchfehlern.

Es wird in der automatischen Variable $ error protokolliert und Sie können diese Art von nicht terminierenden Fehlern testen, indem Sie die $? Automatische Variable, die Sie darüber informiert, ob die letzte Operation erfolgreich war ($ true) oder fehlgeschlagen ist ($ false).

Von dem Auftreten des Fehlers scheint, dass der Fehler zurückgegeben wird und nicht in einer abfangbaren Ausnahme umbrochen wird. Im Folgenden finden Sie eine Ablaufverfolgung des generierten Fehlers.

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 

Eine Arbeit um könnten für Ihren Code sein:

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 
    } 
+0

Aktualisiert mit einer Problemumgehung. –

+45

Sie können veranlassen, dass nicht terminierende Fehler ausgelöst werden, indem Sie Folgendes verwenden: -ErrorAction "Stop" (oder -EA "Stop" kurz) – JasonMArcher

+4

@JasonMArcher - Richtig Sie sind! Setzen Sie $ ErrorActionPreference auf 'Stop', was ebenfalls funktionieren würde, hätte aber globale Auswirkungen. –

1

Edit: Wie in der angegebenen Kommentare, die folgende Lösung gilt nur für PowerShell V1.

Einzelheiten zur Implementierung finden Sie unter this blog post on "Technical Adventures of Adam Weigert".

Beispiel der Verwendung (Kopieren/Einfügen von Adam Weigert Blog):

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..." 
} 

Sonst wirst du exception trapping verwenden.

+2

http://blogs.msdn.com/powershell/archive/2009/06/17/traps-vs-try-catch.aspx Pr dieses sollte es in V2 existieren. – EKS

+1

Try/Catch/Endlich existiert es nicht in V1 von PowerShell, aber es ist in V2. –

+1

Ah, natürlich, mein Fehler. – bernhof

48

Wenn Sie versuchen wollen/catch für alle Fehler zu arbeiten (und nicht nur die Abschlussfehler) Sie manuell alle Fehler beendet, indem machen kann die 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 
} 

Alternative ... Sie können Ihre eigene TryCatch Funktion machen die scriptblocks, so dass Ihre Try-Catch-Anrufe sind nicht so kludge akzeptiert. Ich habe meine Rückgabe wahr/falsch, nur für den Fall, dass ich prüfen muss, ob ein Fehler aufgetreten ist ... aber das muss nicht sein. Außerdem ist die Protokollierung von Ausnahmen optional und kann im catch erledigt werden, aber ich habe immer die Logging-Funktion im catch-Block aufgerufen, also habe ich sie zur try catch-Funktion hinzugefügt.

+0

Probieren Sie ":: Versuchen Sie Division durch Null: $ (0/0)" (und nicht get-item filethatdoesntexist;). Dann fängt es diese Ausnahme nicht ein – Kiquenet

12

Es ist auch möglich, die Fehleraktionseinstellung für einzelne Cmdlets festzulegen, nicht nur für das gesamte Skript. Dies geschieht über den Parameter ErrorAction (alisa EA), der auf allen Cmdlets zur Verfügung steht.

Beispiel

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

hinzufügen "-EA Stop" löste dies für mich.

2

Das ist meine Lösung. Wenn Set-Location fehlschlägt, wird ein nicht abschließender Fehler ausgegeben, der vom catch-Block nicht erkannt wird. Das Hinzufügen von -ErrorAction Stop ist der einfachste Weg.

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