2013-01-09 10 views
8

Coś, o czym ostatnio myślałem, i chciałbym, żeby jakiś wkład od dobrych ludzi w Stack Overflow był włączony.Wyślij wiadomość e-mail, jeśli skrypt PowerShell otrzyma jakiekolwiek błędy i zakończy działanie skryptu.

Prowadzę dość dużą liczbę skryptów PowerShell na różnych harmonogramach (przy użyciu Harmonogramu zadań). Te skrypty zazwyczaj zbierają dane i przechowują je w tabelach SQL dla mnie. Powiedziałbym, że obecnie uruchamiam 40-50 scenariuszy, może więcej.

Jedna rzecz, że poważnie rozważa ostatnio jest najlepszym sposobem:

  1. Zapewnienie, że jeśli wystąpią błędy skrypt kończy działanie bez dalszego przetwarzania.
  2. Skrypt powinien również wysłać do mnie wiadomość e-mail z informacją o niepowodzeniu z informacjami o wyjątku, pokazując, jak daleko się on dostał.
  3. Transkrypcja/postęp jest rejestrowany, dzięki czemu mogę przejrzeć wszystkie błędy i spróbować lepiej poradzić sobie z nimi w skrypcie.

To będzie sporo pracy do wykonania, więc chciałbym od samego początku podążać właściwą drogą.

Jedynym sposobem, widzę osiągnięcia czegoś takiego byłoby wykonać następujące czynności:

Set $ ​​ErrorActionPreference na "Stop"

To powinno spowodować żadnych wyjątków do uruchomienia try/catch blok.

Uruchom cały skrypt w bloku Try/Catch/Finally.

Ostatecznie blok jest opcjonalny oczywiście. Coś takiego:

$ErrorActionPreference = "Stop" 

Try 
{ 
    $Content = gc "C:\Temp\NonExistentFile.txt" 
    foreach ($Line in $Content) 
    { 
     Write-Host $Line 
    } 
} 
Catch 
{ 
    Write-Host $_ -ForegroundColor "Red" -BackgroundColor "Black" 
    break 
} 

Zaloguj się „Transcript” Dane w HTML i napisz treść na niepowodzenie.

Próbowałem kilka sposobów rejestrowania i jednego z klawiszy rzeczy dla mnie jest to, że chcę coś, co jest:

  1. Łatwe do zalogowania się dostarczając tekst i plik dziennika Lokalizacja.
  2. Zawiera datę/godzinę na początku każdego wiersza pliku dziennika.

Zacząłem pisać tekst w plikach .txt, ale było trochę pracy do zrobienia.

Rozpoczęcie transkrypcji było w porządku, ale nie zawierało daty/czasu w każdym wierszu.

Osiągnąłem pewien sukces dzięki niestandardowej funkcji, która wykorzystywałaby funkcję Start-Transcript i zapisywałby każdy tekst, który do niej wysłałem, w Write-Host, z datą/czasem na początku każdego wiersza.

Ale ostatecznie myślę, że muszę zrobić to zalogować się do dokumentu .html, a następnie wysłać wiadomość e-mail z zawartością, jeśli wystąpi błąd.Coś takiego jak na przykład:

Function Send-ErrorEmail 
{ 
    Write-Host "Would Send Email Here" -ForegroundColor "Magenta" 
} 

Function Write-Html 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(ValueFromPipeline=$True)]$Text, 
     $HTMLTag 
    ) 

    [string]$CurrentDateTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss - ") 

    switch ($HTMLTag) 
    { 
     "h1" {$ReturnText = ("<h1>" + $Text + "</h1>")} 
     "h2" {$ReturnText = ("<h2>" + $Text + "</h2>")} 
     default {$ReturnText = ("<p>" + $CurrentDateTime + $Text + "</p>")} 
    } 

    Write-Host -ForegroundColor "Yellow" ($CurrentDateTime + $Text) 
    return $ReturnText 
} 

$ErrorActionPreference = "Stop" 

Try 
{ 
    #Stores the HTML File 
    $LogfilePath = "C:\Temp\LogFile.html" 

    #Begin HTML 
    $HTML = @() 
    $HTML += "<html><head></head><body>" 
    $HTML += "Begin Script" | Write-Html 

    #Loop through Computers 
    $Computers = "LocalHost", "DoesNotExist", "127.0.0.1" 
    foreach ($Computer in $Computers) 
    { 
     #Get Services 
     $HTML += "Computer: $Computer" | Write-Html -HTMLTag "h1" 
     $Services = Get-Service -Computer $Computer 
     $HTML += $Services | ConvertTo-Html -Fragment 
    } 

    #Complete HTML 
    $HTML += "Script End" | Write-Html 
    $HTML += "</body></html>" 
    $HTML | Out-File $LogfilePath 
} 
Catch 
{ 
    #Add Exception to HTML 
    $HTML += $_ | Out-String | Write-Html 

    #Complete HTML 
    $HTML += "</body></html>" 
    $HTML | Out-File $LogfilePath 

    #Send EMail 
    Send-ErrorEmail 

    #Exit Script 
    exit 
} 

Jakieś myśli? Ulepszenia, które według ciebie mogę zrobić? Oczywiście dokument HTML jest brzydki bez formatowania CSS, a funkcja Wyślij pocztę nic nie robi, ale wydaje się być najprostszym sposobem robienia tego, co chcę.

Mogę oczywiście używać wszystkich funkcji ze wszystkich skryptów, aby ułatwić zmianę adresu e-mail z powiadomieniem lub podobnym.

+0

Powinieneś rozważyć zmianę tytułu pytania na pytanie, jeszcze lepiej, zmień to, by reprezentowało twoje główne pytanie. –

Odpowiedz

10

Do globalnej obsługi błędów wolę używać instrukcji pułapki.

function ErrorHandler($error) 
{ 
    ... write out error info 
    ... send email message with error info 
    ... etc 
} 

trap { ErrorHandler $_; break } 

... rest of script code 

A jeśli chcesz wyskoczyć na jakiekolwiek błędy, to tak, aby ustawić $ErrorActionPreferenceStop.

+2

Co ciekawe, czytałem w tej pułapce jeszcze jedno i natknąłem się na to, a potem zrozumiałem, że to ty! :) http://rkeithhill.wordpress.com/2009/08/03/effective-powershell-item-16-dealing-with-errors/ - Nie spędziłem zbyt wiele czasu, ale wygląda na pułapkę instrukcja nie działa poprawnie, gdy jest wywoływana interaktywnie? Nie mogę uzyskać twojego drugiego do ostatniego przykładu, aby wywołać pułapkę, chyba że umieściłem ją w pliku .ps1 i wykonam to. – HungryHippos

+0

Zwykle nigdy nie użyłbym pułapki interaktywnie, ale można ją uruchomić, wprowadzając zakres inny niż zasięg globalny, np. wykonaj to interaktywnie: '& {trap {" błąd uwięziony !! "; dalej }; throw "oops"} ' –

+0

Dzięki Keith, zmieniłem sposób testowania skryptu, więc zamiast tego mogłem użyć pułapki {}. Wydaje mi się, że działa to dobrze dla mnie, i lepiej oświadczyć to raz w scenariuszu, a nie zamknąć całej rzeczy w Try/Catch I liczyć. Najważniejsze, że tęsknię za interaktywnym testowaniem skryptów, jest możliwość sprawdzania zmiennych dla pól/danych w odstępach czasowych. Zaznaczę twoją odpowiedź jako odpowiedź teraz. – HungryHippos