My Daily Hyper-V Status Email–Part 1 of 5

My Daily Hyper-V Status Email–Part 1 of 5

  • Comments 5

I have spent a fair amount of time creating a reliable and resilient Hyper-V deployment in my house.  For the most part this system runs smoothly, however, the resiliency of the design leads to an interesting problem.

My Hyper-V servers are housed in a small closet off the side of my garage.  And if something goes wrong (hard disk failure, system failure, etc…) everything keeps on running happily.  And that is the problem, it should not run happily, it should tell me that something is wrong.  If something is wrong I needed to know straight away – so I can replace broken parts, etc… before a bigger problem develops.

To address this issue– I have created a PowerShell script that runs on each server and sends me a daily status email.

I have been refining this status email script over the last year or so – and am very happy with the results.  Some of the goals I had with this script were:

  • Should work with my ISPs SMTP server (so it works even if my internal infrastructure is in a bad state)
  • Should tell me everything I need to know about my servers
  • Should allow me to tell the status at a glance

At this point in time, I get a daily status email with all the information I need, handily color coded so I can see quickly if everything is good or not:


This week I am going to step through all the parts of this script (it is quite a large script!) and explain what they do, and why they are there.

Today I am going to cover some of the “trimming” that is necessary to make this script work.  Below is a code snippet which represents to top and bottom sections of my script – with all the data logic pulled out of the middle.

# Variables
$filedate = get-date
$computer = gc env:computername
$metricsData = get-vm | measure-vm
$tableColor = "WhiteSmoke"
$errorColor = "Red"
$warningColor = "Yellow"
$FromEmail = ""
$ToEmail = ""
# Establish Connection to SMTP server
$smtpServer = ""
$smtpCreds = new-object Net.NetworkCredential("yourUserName", "yourPassword")
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.UseDefaultCredentials = $false
$smtp.Credentials = $smtpCreds
# HTML Style Definition
$message = "<!DOCTYPE html PUBLIC`"-//W3C//DTD XHTML 1.0 Strict//EN`" `"`">"
$message = "<html xmlns=`"`"><body>"
$message = "<style>"
$message = $message + "TABLE{border-width:2px;border-style: solid;border-color: #C0C0C0 ;border-collapse: collapse;width: 100%}"
$message = $message + "TH{border-width: 2px;padding: 0px;border-style: solid;border-color: #C0C0C0 ;text-align: left}"
$message = $message + "TD{border-width: 2px;padding: 0px;border-style: solid;border-color: #C0C0C0 ;text-align: left}"
$message = $message + "TD{border-width: 2px;padding: 0px;border-style: solid;border-color: #C0C0C0 ;text-align: left}"
$message = $message + "H1{font-family:Calibri;}"
$message = $message + "H2{font-family:Calibri;}"
$message = $message + "Body{font-family:Calibri;}"
$message = $message + "</style>"
# Title
$message = $message + "<h2>Data for Hyper-V Server '$($computer)' : $($filedate)</h2>"
# A whole bunch of code goes here...
$message = $message + "</body></html>"
$email = new-object Net.Mail.MailMessage
$email.Subject = "Hyper-V Server Report: $($filedate)"
$email.From = new-object Net.Mail.MailAddress($FromEmail)
$email.IsBodyHtml = $true
$email.Body =  $message
# Send Email

This is basically the code that is necessary to send an email using PowerShell.  Note, there are simpler ways to send an email using PowerShell – but I am doing it with the Net.Mail.SmtpClient and Net.Mail.MailMessage objects for two reasons:

  1. My ISP (like many ISPs) requires that I authenticate to their SMTP server in order to send email.  This script supports SMTP authentication.
  2. I really wanted a color coded email – so that problems would be bright red and grab my attention.  To do this properly means that I need to be able to generate a HTML based email, not just a plain text one.

The rough summary of the code above is:

  1. All the necessary variables are established (note – I have removed my email addresses, usernames and passwords – so you will need to swap in appropriate values here).
  2. A connection to the SMTP server is created
  3. A HTML header is created for the email
  4. There is a whole bunch of code removed (that I will be covering over the course of this week)
  5. The email message is constructed, using the HTML message string as the body
  6. Finally, the email is sent using the SMTP server

Over this week I will be covering the sections of this script that:

  1. Gather key event log information
  2. Gather VM and VM Replication health information
  3. Gather Storage health information
  4. Gather utilization data about the virtual machines

The final result – for those who are too impatient to wait out the week – is the script that I have attached to the end of this blog post.  I have this script setup to run once a day using a scheduled task.


Leave a Comment
  • Please add 4 and 1 and type the answer here:
  • Post
  • Thank you dear Ben,

    Awesome report :)

    I noticed two errors below when I run it on my Hyper-V host, however I received the email.


    Get-WinEvent : No events were found that match the specified selection criteria.

    At C:\Users\Administrator\Desktop\POSH\Hyper-V_DailyStatsReport.ps1:55 char:42

    + $message = $message + "Errors: <br>" + ((Get-WinEvent -FilterHashTable @{LogName ...

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : ObjectNotFound: (:) [Get-WinEvent], Exception

       + FullyQualifiedErrorId : NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand

    Get-WinEvent : No events were found that match the specified selection criteria.

    At C:\Users\Administrator\Desktop\POSH\Hyper-V_DailyStatsReport.ps1:63 char:44

    + $message = $message + "Warnings: <br>" + ((Get-WinEvent -FilterHashTable @{LogNa ...

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : ObjectNotFound: (:) [Get-WinEvent], Exception

       + FullyQualifiedErrorId : NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand

  • Sharbel -

    The script will show these errors if there are no Hyper-V specific event log entries in the last 24 hours.  I should clean this up - but they can be safely ignored for now.



  • Thanks a lot for the script. Since i don't know powershell that much, i couldn't do this on my own if my life depended on it :D

    One question: what user do you run the scheduled task as? I tried "network service" but it doesn't report anything about VMs, only storage.

  • thanks for sharing the wonderful script.

    Can this script be run against Hyper-V Clusters to get overall health..?



  • Thanks Ben. Great script! I added $computer to the line 164 so I know by the subject of the email which server it is for.

Page 1 of 1 (5 items)