none
Errorhandling Try-Catch RRS feed

  • Frage

  • Hi Leute,

    ich schreibe gerade an einem Eingabe/Ändern Formular für Benutzer Objekte. Für die Abfrage verwende ich GetADUserResult mit den dazu gehörigen Parametern. Wenn ein Benutzer Objekt nicht vorhanden ist, soll es angelegt werden. Dies habe ich mit Hilfe der Try-Catch Methode gelöst.

    Nun habe ich gelesen, dass die Try-Catch Methode nur angewandt werden soll, wenn ein unerwarteter Fehler auftritt. Bei mir wird dieser Fehler aber erwartet bzw. ein Fehler erwartet. Wie kann ich es lösen, dass ich auf den Fehler reagiere, z.B. abfrangen und interpretieren des Fehler Codes und so gezielt ein nicht vorhanden sein eines Benutzer Objektes von anderen Fehlern unterscheide?

    Try { #Fehler abfangen, wenn der Anmeldename nicht gefunden wird. $Script:GetADUserResult = Get-ADUser -Identity $TB_Anmeldename.Text -Properties Title,Initials,telephoneNumber,otherTelephone,mobile,otherMobile,mail,description,physicalDeliveryOfficeName,EmployeeID,EmployeeNumber,extensionAttribute1,msTSProfilePath,distinguishedName -errorvariable myerrorvariable } Catch { # Bei nicht gefundenem Anmeldenamen wird zur Eingabe gesprungen $GetADUserResult = @() Set-WLUserEingabe } # Wenn der Benutzer vorhanden ist, werden die Attribute angezeigt. Get-WLUserDaten

    Ich freue mich über jede Anmerkung oder Verbesserung!

    Gruß

    Dirk

    Donnerstag, 18. Juli 2013 12:48

Antworten

  • Hallo,

    das kommt darauf an wie man Fehler interpretiert, wobei man eigentlich nicht mehr von Fehlern redet sondern von Ausnahmen. :-)

    Und damit das Script nicht "rot" :-) sieht, kann man solche Ausnahmen mit Try/Catch behandeln.

    Get-ChildItem fgdfgdfg.gdfg


    Weil es diese Datei auf meinem System nicht erhalte ich eine rote Fehermeldung die mich darauf aufmerksam macht.
    Nun wuerde ich dies dem Nutzer des Scriptes gerne "freundlicher" mitteilen, also starten wir einen Versuch mit Try/Catch

    Try {Get-ChildItem fgdfgdfg.gdfg} catch {"oh jeh, die Datei gibt es nicht"}


    Leider sehe ich meine Fehlermeldung nicht sondern wieder die rote, weil der Entwickler des Cmdlets davon ausgeht das dieser Fehler immer mal wieder autaucht und kein Stopfehler ist, d.h. ein Script laeuft nach so einem Fehler weiter. Wenn ich den wirklich abfangen will muss ich das so machen.

    Try {Get-ChildItem fgdfgdfg.gdfg -ErrorAction Stop} catch {"oh jeh, die Datei gibt es nicht"}


    Und schon sehe ich meine Fehlermeldung und nicht mehr die "Rote".

    Und je nachdem was im Try Block abgeht kann es verschiedene Ausnahmen geben, die kannst Du dann einzelnen in catch Bloecken bearbeiten.

    Try {Get-ChildItem fgdfgdfg.gdfg -ErrorAction Stop} catch [System.Management.Automation.ItemNotFoundException] {"oh jeh, die Datei gibt es nicht"} catch {"unbekannter Fehler"}

    Und wie die einzelnen Ausnahmen benannt werden kannst Du ueber die Var. $Error ermitteln, das ist ein Array wo die neueste Meldung immer den Index 0 hat.

    Mit $Error[0].Exception.GetType().FullName siehst du dann den  Namen, es kann aber sein, dass nur eine allgemeiner angezeigt wird, z.B: System.Management.Automation.runtimeexception das kann dann allerdings "alles" sein, in dem Fall sollte es aber immer noch eine sogenannte Innerexception geben die naeher auf das Problem eingeht.
    Die musst du dann beim Catch verwenden.
    $Error[0].Exception.InnerException.GetType().FullName


    Beste Gruesse
    brima

    • Bearbeitet brima Donnerstag, 18. Juli 2013 18:41 mehr info
    • Als Antwort markiert Dirk Heimann Freitag, 19. Juli 2013 06:33
    Donnerstag, 18. Juli 2013 18:02
  • Es spricht überhaupt nichts dagegen, dies so einzusetzen wie Du es machst.
    In manchen Sprachen, wie z.B. Visual Basic, muss man erwartetet Fehler provozieren und dann abfangen um gewisse Zustände abzufragen. Da gibt es manchmal keine andere Möglichkeit.
    Das Fehler abfangen ist nicht so performant wie eine eventuelle vorherige Abfrage.
    Deshalb sollte man, wenn es Möglich ist, eine IF Abfrage benutzen. Dafür gibt es die verschiedenen Test Cmdlets z.B. Test-Path oder Test-Connection.

    >>>> Unerwarteter Fehler
    Häng dich da nicht zu sehr an diesem einen Wort auf!

    In deinem Fall kannst du nicht vorher abfragen ob es einen nicht vorhandenen User nicht gibt! ;-)
    Du MUSST also auf diesen Fehler reagieren.

    Aber genauer und mehr spezifisch!

    Try heißt ja IMMER ich versuche etwas, das schief gehen könnte. Hier geht man ja bewusst in eine "unsichere" Situation.
    Catch gibt dem Programmierer/Scripter (also dir), die Möglichkeit auf den Fehler richtig zu reagieren und mehr Programm-Ablaufsicherheit herzustellen.

    Der Programmierer des Cmdlets Get-ADUser hatte zwei Möglichkeiten, dich darüber zu informieren, dass es einen gesuchten User nicht gibt.

    1. er hätte einfach $Null (ein leeres Objekt) zurückgeben können, um Anzuzeigen das der User nicht existiert.

    Das ist aber nicht sehr informativ, da ja auch andere Fehler dies bewirken können (z.B. Domäne nicht erreichbar, Netzwerk weg usw.)

    2. Oder er wirft einen aussagekräftigen spezifischen Fehler (Exception). Mit der Ursache, warum der User nicht gefunden werden konnte.

    Ein nacktes Catch fängt ALLE Fehler ab, egal welche Ursache sie haben! Hier nimmst du dir selbst die Möglichkeit auf verschiedene Fehler auf verschiedene Arten zu reagieren.

    In deinem Fall würde bei JEDEM Fehler, egal welcher Art, die Funktion Set-WLUserEingabe aufgerufen. Also auch wenn die Domäne nicht erreichbar ist.
    Ist das doof!?

    Wen du einen nicht vorhandenen User suchst, dann siehst du das in einer Speziellen Exception vom Typ: "ADIdentityNotFoundException".

    PowerShell wurde mit .NET entwickelt und benutzt auch die .NET Fehler Exceptions !
    Hier kannst du also bei den .NET Programierern abgucken. Die benutzen Try{} Catch{} Finally{} genauso wie PowerShell!

    Lies dir Bitte mal hier den Abschnitt 7.1 bis 7.1.7 durch :
    http://openbook.galileocomputing.de/visual_csharp_2012/1997_07_001.html#dodtpbc0629a3-2b8c-494f-b422-fda1c70d3c74

    Try Catch Finally and error handling in PowerShell
    http://www.vexasoft.com/blogs/powershell/7255220-powershell-tutorial-try-catch-finally-and-error-handling-in-powershell

    How Can I Use Try/Catch/Finally in Windows PowerShell?
    http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/11/hey-scripting-guy-march-11-2010.aspx

    Wichtig hier in der PowerShell ist es das man -ErrorAction Stop benutzt, wie Brima schon schrieb.

    Try  { 
       #Fehler abfangen, wenn der Anmeldename nicht gefunden wird. 
       $Script:GetADUserResult = Get-ADUser -Identity $TB_Anmeldename.Text  -Properties Title,Initials,telephoneNumber,otherTelephone,mobile,otherMobile,mail,description,physicalDeliveryOfficeName,EmployeeID,EmployeeNumber,extensionAttribute1,msTSProfilePath,distinguishedName -errorvariable myerrorvariable -ErrorAction Stop  
      }
      # Auf die Spezielle ADIdentityNotFoundException Exception reagieren
      Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]  {
      # Bei nicht gefundenem Anmeldenamen wird zur Eingabe gesprungen
       $GetADUserResult = @()
       Set-WLUserEingabe
      }
      # alle anderen Möglichen Fehler behandeln
      Catch {
      	# den Fehler weiterreichen damit er angezeigt wird (programm wird nicht gestoppt!)
    	Write-Error $_
      }
      
      # Nur ausführen wenn ein User vorhanden ist
      If ($Script:GetADUserResult) {
      	# Wenn der Benutzer vorhanden ist, werden die Attribute angezeigt.
      	Get-WLUserDaten
      }
    gruss Peter Kriegel


    Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
    Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
    My PowerShell Blog http://www.admin-source.info
    [string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
    German ? Come to German PowerShell Forum!


    • Bearbeitet Peter Kriegel Freitag, 19. Juli 2013 06:32 lästig
    • Als Antwort markiert Dirk Heimann Freitag, 19. Juli 2013 06:34
    Freitag, 19. Juli 2013 06:13

Alle Antworten

  • Hallo,

    das kommt darauf an wie man Fehler interpretiert, wobei man eigentlich nicht mehr von Fehlern redet sondern von Ausnahmen. :-)

    Und damit das Script nicht "rot" :-) sieht, kann man solche Ausnahmen mit Try/Catch behandeln.

    Get-ChildItem fgdfgdfg.gdfg


    Weil es diese Datei auf meinem System nicht erhalte ich eine rote Fehermeldung die mich darauf aufmerksam macht.
    Nun wuerde ich dies dem Nutzer des Scriptes gerne "freundlicher" mitteilen, also starten wir einen Versuch mit Try/Catch

    Try {Get-ChildItem fgdfgdfg.gdfg} catch {"oh jeh, die Datei gibt es nicht"}


    Leider sehe ich meine Fehlermeldung nicht sondern wieder die rote, weil der Entwickler des Cmdlets davon ausgeht das dieser Fehler immer mal wieder autaucht und kein Stopfehler ist, d.h. ein Script laeuft nach so einem Fehler weiter. Wenn ich den wirklich abfangen will muss ich das so machen.

    Try {Get-ChildItem fgdfgdfg.gdfg -ErrorAction Stop} catch {"oh jeh, die Datei gibt es nicht"}


    Und schon sehe ich meine Fehlermeldung und nicht mehr die "Rote".

    Und je nachdem was im Try Block abgeht kann es verschiedene Ausnahmen geben, die kannst Du dann einzelnen in catch Bloecken bearbeiten.

    Try {Get-ChildItem fgdfgdfg.gdfg -ErrorAction Stop} catch [System.Management.Automation.ItemNotFoundException] {"oh jeh, die Datei gibt es nicht"} catch {"unbekannter Fehler"}

    Und wie die einzelnen Ausnahmen benannt werden kannst Du ueber die Var. $Error ermitteln, das ist ein Array wo die neueste Meldung immer den Index 0 hat.

    Mit $Error[0].Exception.GetType().FullName siehst du dann den  Namen, es kann aber sein, dass nur eine allgemeiner angezeigt wird, z.B: System.Management.Automation.runtimeexception das kann dann allerdings "alles" sein, in dem Fall sollte es aber immer noch eine sogenannte Innerexception geben die naeher auf das Problem eingeht.
    Die musst du dann beim Catch verwenden.
    $Error[0].Exception.InnerException.GetType().FullName


    Beste Gruesse
    brima

    • Bearbeitet brima Donnerstag, 18. Juli 2013 18:41 mehr info
    • Als Antwort markiert Dirk Heimann Freitag, 19. Juli 2013 06:33
    Donnerstag, 18. Juli 2013 18:02
  • Es spricht überhaupt nichts dagegen, dies so einzusetzen wie Du es machst.
    In manchen Sprachen, wie z.B. Visual Basic, muss man erwartetet Fehler provozieren und dann abfangen um gewisse Zustände abzufragen. Da gibt es manchmal keine andere Möglichkeit.
    Das Fehler abfangen ist nicht so performant wie eine eventuelle vorherige Abfrage.
    Deshalb sollte man, wenn es Möglich ist, eine IF Abfrage benutzen. Dafür gibt es die verschiedenen Test Cmdlets z.B. Test-Path oder Test-Connection.

    >>>> Unerwarteter Fehler
    Häng dich da nicht zu sehr an diesem einen Wort auf!

    In deinem Fall kannst du nicht vorher abfragen ob es einen nicht vorhandenen User nicht gibt! ;-)
    Du MUSST also auf diesen Fehler reagieren.

    Aber genauer und mehr spezifisch!

    Try heißt ja IMMER ich versuche etwas, das schief gehen könnte. Hier geht man ja bewusst in eine "unsichere" Situation.
    Catch gibt dem Programmierer/Scripter (also dir), die Möglichkeit auf den Fehler richtig zu reagieren und mehr Programm-Ablaufsicherheit herzustellen.

    Der Programmierer des Cmdlets Get-ADUser hatte zwei Möglichkeiten, dich darüber zu informieren, dass es einen gesuchten User nicht gibt.

    1. er hätte einfach $Null (ein leeres Objekt) zurückgeben können, um Anzuzeigen das der User nicht existiert.

    Das ist aber nicht sehr informativ, da ja auch andere Fehler dies bewirken können (z.B. Domäne nicht erreichbar, Netzwerk weg usw.)

    2. Oder er wirft einen aussagekräftigen spezifischen Fehler (Exception). Mit der Ursache, warum der User nicht gefunden werden konnte.

    Ein nacktes Catch fängt ALLE Fehler ab, egal welche Ursache sie haben! Hier nimmst du dir selbst die Möglichkeit auf verschiedene Fehler auf verschiedene Arten zu reagieren.

    In deinem Fall würde bei JEDEM Fehler, egal welcher Art, die Funktion Set-WLUserEingabe aufgerufen. Also auch wenn die Domäne nicht erreichbar ist.
    Ist das doof!?

    Wen du einen nicht vorhandenen User suchst, dann siehst du das in einer Speziellen Exception vom Typ: "ADIdentityNotFoundException".

    PowerShell wurde mit .NET entwickelt und benutzt auch die .NET Fehler Exceptions !
    Hier kannst du also bei den .NET Programierern abgucken. Die benutzen Try{} Catch{} Finally{} genauso wie PowerShell!

    Lies dir Bitte mal hier den Abschnitt 7.1 bis 7.1.7 durch :
    http://openbook.galileocomputing.de/visual_csharp_2012/1997_07_001.html#dodtpbc0629a3-2b8c-494f-b422-fda1c70d3c74

    Try Catch Finally and error handling in PowerShell
    http://www.vexasoft.com/blogs/powershell/7255220-powershell-tutorial-try-catch-finally-and-error-handling-in-powershell

    How Can I Use Try/Catch/Finally in Windows PowerShell?
    http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/11/hey-scripting-guy-march-11-2010.aspx

    Wichtig hier in der PowerShell ist es das man -ErrorAction Stop benutzt, wie Brima schon schrieb.

    Try  { 
       #Fehler abfangen, wenn der Anmeldename nicht gefunden wird. 
       $Script:GetADUserResult = Get-ADUser -Identity $TB_Anmeldename.Text  -Properties Title,Initials,telephoneNumber,otherTelephone,mobile,otherMobile,mail,description,physicalDeliveryOfficeName,EmployeeID,EmployeeNumber,extensionAttribute1,msTSProfilePath,distinguishedName -errorvariable myerrorvariable -ErrorAction Stop  
      }
      # Auf die Spezielle ADIdentityNotFoundException Exception reagieren
      Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]  {
      # Bei nicht gefundenem Anmeldenamen wird zur Eingabe gesprungen
       $GetADUserResult = @()
       Set-WLUserEingabe
      }
      # alle anderen Möglichen Fehler behandeln
      Catch {
      	# den Fehler weiterreichen damit er angezeigt wird (programm wird nicht gestoppt!)
    	Write-Error $_
      }
      
      # Nur ausführen wenn ein User vorhanden ist
      If ($Script:GetADUserResult) {
      	# Wenn der Benutzer vorhanden ist, werden die Attribute angezeigt.
      	Get-WLUserDaten
      }
    gruss Peter Kriegel


    Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
    Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
    My PowerShell Blog http://www.admin-source.info
    [string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
    German ? Come to German PowerShell Forum!


    • Bearbeitet Peter Kriegel Freitag, 19. Juli 2013 06:32 lästig
    • Als Antwort markiert Dirk Heimann Freitag, 19. Juli 2013 06:34
    Freitag, 19. Juli 2013 06:13
  • Super Antworten!!!

    Ihr habt mir richtig weitergeholfen. Ich hatte z.B. nirgens gelesen, dass ich mehrere Catch Bereiche einrichten kann. Ich werde diese Form mal ausprobieren.

    Danke auch für die ausführlichen Antworten!!!! Und die Lesehinweise. Werde mich jetzt mal mit der Try-Catch-Finaly Methode auseinander setzen.

    Gruß

    Dirk

    Freitag, 19. Juli 2013 06:32
  • Einen wichtigen habe ich noch vergessen!

    http://www.colorconsole.de/PS_Windows/de/about_try_catch_finally.htm

    oder besser:

    Get-Help about_Try_Catch_Finally


    Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
    Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
    My PowerShell Blog http://www.admin-source.info
    [string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
    German ? Come to German PowerShell Forum!

    Freitag, 19. Juli 2013 09:36