Thursday, October 21, 2010

A Powershell Script for Monitoring Web Site Status

I’ve been having some problems with my server recently. If it restarts, because of windows update or for whatever reason, some of my websites can fail to start. I think it might be because WAS was configured as a manually started service, but I’m not sure. I wanted to be warned if any of the sites on my machine were down, and for an automatic restart to be attempted if they were.

I’ve written a little Powershell script to do this. It was an interesting exercise because one of the things that I wanted to do was get an email via my Google Apps account.

Am I insane? Is there a far easier and more obvious way of doing this? Let me know in the comments.

Here’s the script (and yes, I’m a total Powershell Noob :)

$fromAddress = "someServer@suteki.co.uk"
$toAddress = "mike.hadlow@suteki.co.uk"
$subject = "One or more websites are not responding"
$port = 587
$monitorPassword = "s0meN1cePa33w0rd"

$sites = @{
    "suteki.shop" = "http://suteki.shop/"; 
    "blue.shop" = "http://green.shop/"
    }

# send an email message via gmail
function SendMessage([string]$body)
{
    $message = new-object System.Net.Mail.MailMessage($fromAddress, $toAddress, $subject, $body)
    $smtpServer = "smtp.gmail.com"
    $client = new-object System.Net.Mail.SmtpClient($smtpServer)
    $client.EnableSsl = $TRUE
    $client.Port = 587
    $client.Credentials = new-object System.Net.NetworkCredential($fromAddress, $monitorPassword)
    $client.Send($message)
}

# make a request to the site and return the status code. Return 'Failed' if anything goes wrong
function CheckSiteStatus([string]$url)
{
    $req = [System.Net.HttpWebRequest]::Create($url)
    try
    {
        $res = $req.GetResponse()
        $res.StatusCode
    }
    catch
    {
        "Failed"
    }
}

function RestartSite([string]$site)
{
    C:\Windows\system32\inetsrv\appcmd stop site $site
    C:\Windows\system32\inetsrv\appcmd start site $site
}

function CheckSite([string]$url, [string]$site)
{
    $status = CheckSiteStatus $url
    if ($status -eq "OK")
    {
        ""
    }
    else
    {
        # attempt to restart site
        RestartSite $site
        "site '$site' failed to respond`n"
    }
}

function CheckSites()
{
    $body = ""
    foreach($site in $sites.Keys)
    {
        $url = $sites[$site]
        $body += CheckSite $url $site
    }
    if($body -ne "")
    {
        SendMessage $body
        $body
    }
    else
    {
        "OK"
    }
}

CheckSites

I’ve set it up with Task Scheduler to run every 10 minutes. One of the things I discovered when doing this is that if you say your task action is ‘C:\Scripts\Monitor.ps1’, you will just get notepad.exe executing You have to explicitly launch powershell and invoke: ‘powershell C:\Scripts\Monitor.ps1’.

6 comments:

Keith Bloom said...

Nice script Mike.

I've been using the web service Pingdom on for service monitoring http://www.pingdom.com/ Although I this won't try to fire the thing back up for me and you have to pay for more than one site.

Ken Egozi said...

This is a useful tool. I would however use Boo (or IronRuby) for such a script. It would probably be shorter and more readable.

I am going to set this up on my server soon and will post my port.

Mike Hadlow said...

Ken,

I agree. I'm not a great fan of Powershell as a language. I think MS really missed a trick by not using IronPython in this role. However having PS on every windows machine, plus the fact that it natively talks .NET, COM and WMI makes it pretty compelling for these kinds of scripting tasks.

Batchass said...

very nice! thanks for sharing

Anonymous said...

Check this powershell script top monitor an application

Anonymous said...

Check this powershell script top monitor an application

http://itbookmarks.blogspot.ca/2013/09/monitoring-application-with-powershell.html