2013-01-09 22 views
8

最近我一直在想的事情,我希望Stack Overflow的好人士提供一些意見。如果PowerShell腳本得到任何錯誤並終止腳本,請發送電子郵件

我根據不同的計劃(使用Task Scheduler)運行大量的PowerShell腳本。這些腳本通常會爲我收集數據並將其存儲在SQL表中。我會說我目前正在運行40-50個腳本,或許更多。我已經認真考慮了最近

一件事是最好的方法:

  1. 確保如果出現任何錯誤的腳本退出而不進一步處理。
  2. 腳本還應該發送給我一封關於異常細節失敗的電子郵件,告訴我它有多遠。
  3. 記錄/進度已記錄,因此我可以查看任何錯誤並嘗試更好地在腳本中處理它們。

這將是一個相當的工作要做,所以我想從一開始就採用正確的方法。

我可以看到實現這樣的事情的唯一方法是做到以下幾點:

設置$ ErrorActionPreference「停止」

這應當引起任何異常觸發一個try/catch塊。

在Try/Catch/Finally塊中運行整個腳本。

當然,最後的塊是可選的。事情是這樣的:

$ErrorActionPreference = "Stop" 

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

登錄的「成績單」數據轉換成HTML並通過電子郵件發送失敗的內容。

我試圖記錄的一些方法,並且按鍵的事情對我來說一個是我想要的東西,那就是:

  1. 容易登錄到通過提供文本和日誌文件位置。
  2. 包含日誌文件每行開始處的日期/時間。

我開始將文本寫入.txt文件,但這是一件需要做的工作。

Start-Transcript可以,但不包括每行的日期/時間。

我使用了一個自定義的函數,可以使用Start-Transcript,並且可以將任何發送到Write-Host的文本寫入到Write-Host中,並在每行的開頭添加日期/時間。

但最終我認爲我需要做的是登錄到一個.html文檔,然後通過電子郵件發送錯誤內容。例如這樣的一個例子:

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 
} 

有什麼想法?你認爲我可以改進嗎?很明顯,HTML文檔很醜,沒有CSS格式,Send Mail函數也沒有做任何事情,但它似乎是最簡單的方法來做我想要的。

我當然可以在所有腳本中點出任何函數,以方便更改通知電子郵件地址或類似內容。

+0

你應該考慮改變你的問題的標題是一個問題,更好的是,改變它代表你的主要問題。 –

回答

10

對於全局錯誤處理,我更喜歡使用陷阱語句。

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

trap { ErrorHandler $_; break } 

... rest of script code 

如果你想保釋任何錯誤,那麼,設置$ErrorActionPreferenceStop

+2

有趣的是,我正在讀更多的陷阱聲明,並遇到了這個,然後我意識到這是你! :) http://rkeithhill.wordpress.com/2009/08/03/effective-powershell-item-16-dealing-with-errors/ - 我沒有花很多時間,但它看起來像陷阱語句在交互調用時無法正常工作?除非我將它放入.ps1文件並執行該操作,否則我無法讓您的第二個到最後一個示例調用陷阱。 – HungryHippos

+0

我通常不會以交互方式使用陷阱,但您可以通過放入除全局範圍以外的作用域來使其工作,例如交互執行:'&{trap {「error trapped !!」;繼續};拋出「oops」}' –

+0

感謝Keith,我剛剛改變了測試腳本的方式,所以我可以使用陷阱{}。似乎對我來說工作得很好,並且最好在腳本中聲明一次,而不是必須將整個事件包裝到Try/Catch I中。我錯過交互測試腳本的主要原因是能夠間隔地檢查字段/數據的變量。我會將你的回答標記爲現在的答案。 – HungryHippos

相關問題