HOWTO: Monitor a webpage and alert on change

This is admittedly kind of a silly HOWTO but does contain a number of very useful concepts.

I am eagerly awaiting the Lenovo Thinkpad P50 laptop.  The official webpage for this laptop went live today but for pricing it simply says “Coming Soon”.
Rather than refresh the page constantly, I figured I’d let PowerShell do the work for me.  Specifically:

1) Connect to the shop.lenovo.com website every hour and check if the “Coming Soon” pricing has changed
2) If the text is still present, do nothing
3) If the the “Coming Soon” text has been removed (presumably replaced by actual pricing) do the following:
4) Create a pop up tooltip in the Windows System tray alerting me that the pricing is now available
5) In case I miss the popup, email me as well.

To accomplish this, take the code below, save it to a file and create a scheduled task to run it every hour.  That’s it.  You will now be notified as soon as the laptop is available for purchase!

Note: You may be wondering why I didn’t use the built-in Invoke-WebRequest cmdlet.  Normally I would but for Lenovo’s website specifically, I would consistently get “403 – Forbidden” errors.
I tried adding custom user agents and even went as far as using Fiddler to figure out what a good header looks like and then copied that.
The issue appears to be that the Lenovo website is compressed with Gzip and encoded in such a way that (I couldn’t figure out anyway) how to make it work with the built in tool.

imageimage

Function Show-BalloonTip($Text)
{
# Set notification title and message.
$Title = "Lenovo P50 Countdown"
$Message = $Text

# How long to display the notification in milliseconds.
# Must be between 10 and 30 seconds.
$Timeout = 30000

# Balloon icon type: None, Info, Warning or Error.
$BalloonIcon = "Info"

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$HostProcessPath = Get-Process -id $pid | Select-Object -ExpandProperty Path
$NotifyIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($HostProcessPath)
$NotifyIcon.BalloonTipTitle = $Title
$NotifyIcon.BalloonTipText = $Message
$NotifyIcon.BalloonTipIcon = $BalloonIcon
$NotifyIcon.Visible = $True
$NotifyIcon.ShowBalloonTip($Timeout)

Start-sleep -Seconds 10
$NotifyIcon.Dispose()
}

Function Get-Webpage($URL)
{
$request = New-Object System.Net.WebClient

# Custom headers required to access shop.lenovo.com as the page is compressed with gzip and otherwise returns 403 Forbidden errors
$request.headers.add("User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko")
$request.headers.add("Accept-Language: en-US")
$request.headers.add("X-Requested-With: XMLHttpRequest")
$request.headers.add("Accept: text/html, application/xhtml+xml, */*")
$request.UseDefaultCredentials = $true
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$request.Proxy.Credentials = $request.Credentials

$RawHTML = $request.DownloadString($URL)

# The text comes in one long string. Seperate out each line on each carriage return
$RawHTML -split "`r`n"
}

$HTML = Get-Webpage "http://shop.lenovo.com/ca/en/laptops/thinkpad/p-series/p50/"

# Currently Coming Soon appears 3 times in the code. Once pricing appears this should no longer be present so display the message
if (($HTML | select-string "coming soon" | measure-object).count -ne 3)
{
Show-BalloonTip "The Thinkpad P50 is ready for purchase!"

$smtpServer = "mail.domain.com"
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "me@mydomain.com"
$msg.To.Add("target@domain.com")
$msg.IsBodyHTML = $false
$msg.Subject = "Lenovo P50 Pricing is a go!"
$msg.Body = "The Lenovo P50 website is no longer saying coming soon and presumably has pricing now!"
$smtp.Send($msg)
}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.