Hyper-V Networking–Router Guard

Router guard is another advanced networking feature that was added in Windows Server 2012:

image

When you enable Router Guard Hyper-V switch will discard the following packets:

  • ICMPv4 Type 5 (Redirect message)
  • ICMPv4 Type 9 (Router Advertisement)
  • ICMPv6 Type 134 (Router Advertisement)
  • ICMPv6 Type 137 (Redirect message)

Much like DHCP guard – the two most common questions I get about router guard are:

  1. Why would I want to enable this option?

    Imagine you have a virtual machine that is configured for routing services and is connected to multiple virtual networks.  You want to make sure that routing services are only provided on one specific virtual network.  In this case you would enable the router guard on any networks where you did not want the virtual machine to act as a router.

  2. Why isn’t this option enabled by default everywhere?

    Router guard does have a, relatively minimal, impact on performance.  Given that most virtual machines are not running routing services it is not enabled by default, as it is not needed.

You can configure this setting through the UI or with PowerShell.  To configure it with PowerShell you should use the RouterGuard parameter on the Set-VMNetworkAdapter cmdlet:

image

Cheers,
Ben

Read More

Hyper-V Networking–DHCP Guard

If you start digging into the advanced settings section of a virtual network adapter – there is a lot of interesting stuff to look at.  Today I’m going to talk about the DHCP guard setting:

image

This setting stops the virtual machine from making DHCP offers over this network interface.  To be clear – this does not affect the ability to receive a DHCP offer (i.e. if you need to use DHCP to acquire an IP address that will work) it only blocks the ability for the virtual machine to act as a DHCP server.

Two questions that I often get about this feature are:

  1. Why would I want to enable this option?

    Imagine you have a DHCP server virtual machine that is connected to multiple virtual networks.  You want to make sure that DHCP offers are only provided on one specific virtual network.  In this case you would enable the DHCP guard on any networks where you did not want the virtual machine to act as a DHCP server.

  2. Why isn’t this option enabled by default everywhere?

    DHCP guard does have a, relatively minimal, impact on performance.  Given that most virtual machines are not running DHCP servers it is not enabled by default, as it is not needed.

You can configure this setting through the UI or with PowerShell.  To configure it with PowerShell you should use the DHCPGuard parameter on the Set-VMNetworkAdapter cmdlet:

image

Cheers,
Ben

Read More

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

After displaying event logs, virtual machine health and storage health – the last thing that is included in my daily status email is usage data.

For this I take advantage of the built in metrics functionality that is part of Hyper-V.

image

Looking at this report – I realize I should probably filter our replicated virtual machines (those are all the entries with zero data).  I guess I will have to fix that at some point in the future.  Regardless – here is the code that I use today:

# VM Metrics

$message = $message + "TH{background-color:blue}TR{background-color:$($tableColor)}"

$message = $message + "Virtual Machine Utilization Report 

"

 

$message = $message +  "CPU utilization data: 
"
+ ($metricsData | `

                                                           select-object @{Expression={$_.VMName};Label="Virtual Machine"}, `

                                                                         @{Expression={$_.AvgCPU};Label="Average CPU Utilization (MHz)"} `

                                                                         | ConvertTo-HTML -Fragment) `

                                                                         +" 
"

$message = $message + "Memory utilization data: 
"
+ ($metricsData | `

                                                             select-object @{Expression={$_.VMName};Label="Virtual Machine"}, `

                                                                           @{Expression={$_.AvgRAM};Label="Average Memory (MB)"}, `

                                                                           @{Expression={$_.MinRAM};Label="Minimum Memory (MB)"}, `

                                                                           @{Expression={$_.MaxRAM};Label="Maximum Memory (MB)"} `

                                                                           | ConvertTo-HTML -Fragment) `

                                                                           +" 
"

$message = $message + "Network utilization data: 
"
+ ($metricsData | `

                                                             select-object @{Expression={$_.VMName};Label="Virtual Machine"}, `

                                                                           @{Expression={"{0:N2}" -f (($_.NetworkMeteredTrafficReport | where-object {($_.Direction -eq "Inbound")}`

                                                                              | measure-object TotalTraffic -sum).sum / 1024)};Label="Inbound Network Traffic (GB)"}, `

                                                                           @{Expression={"{0:N2}" -f (($_.NetworkMeteredTrafficReport | where-object {($_.Direction -eq "Outbound")} `

                                                                              | measure-object TotalTraffic -sum).sum / 1024)};Label="Outbound Network Traffic (GB)"} `

                                                                           | ConvertTo-HTML -Fragment) `

                                                                           +" 
"

$message = $message + "Disk utilization data: 
"
+ ($metricsData | `

                                                           select-object @{Expression={$_.VMName};Label="Virtual Machine"}, `

                                                                         @{Expression={"{0:N2}" -f ($_.TotalDisk / 1024)};Label="Disk Space Used (GB)"} `

                                                                         | ConvertTo-HTML -Fragment) `

                                                                         +" 
"

$message = $message + "Metering Duration data: 
"
+ ($metricsData | `

                                                            select-object @{Expression={$_.VMName};Label="Virtual Machine"}, `

                                                                          @{Expression={$_.MeteringDuration};Label="Metering data duration"} `

                                                                          | ConvertTo-HTML -Fragment) `

                                                                          +" 
"

 

# Reset metrics

get-vm | Reset-VMResourceMetering

get-vm | Enable-VMResourceMetering

Notes about this code:

  • $metricsData contains the output of “get-vm | measure-vm” (this is mentioned in my first post in this series).  The reason why I do this is because measure-vm is a heavy command (it uses a chunk of CPU and disk) so I only want to run it once.
  • Once again – I use raw HTML to set the color of the table headers. 
  • Again – I run the output of these commands through Select-Object with the use of the “Expression” option to set column labels appropriately.
  • Again – I use ConvertTo-HTML –Fragment to get a nice HTML table outputted.
  • At the end of this code I reset the counters, and enable metering on all virtual machines.  I do this so that if I add any new virtual machines, they get picked up automatically.

Cheers,

Ben

Read More

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

Now that I have talked about displaying event log information and virtual machine health information; the next part of my status email is storage health information.

In my experience – the most common failure for my servers is a failed hard disk.  Now, as I have multiple levels of redundancy configured in my storage configuration, it is not always obvious that a disk has failed.  Luckily, it is very easy to get this information with PowerShell.

image

In fact, this is one of the primary reasons why I like using storage spaces.  The great integration with PowerShell.  Here is the code that I use to generate this table:

# Storage Health

$message = $message + "TH{background-color:DarkGreen}TR{background-color:$($errorColor)}"

$message = $message + "Storage Health 

"

$message = $message + "Physical Disk Health: 
"
+ ((Get-PhysicalDisk | `

                                                           Select-Object @{Expression={$_.FriendlyName};Label="Physical Disk Name"},  `

                                                                         @{Expression={$_.DeviceID};Label="Device ID"}, `

                                                                         @{Expression={$_.OperationalStatus};Label="Operational Status"}, `

                                                                         @{Expression={$_.HealthStatus};Label="Health Status"}, `

                                                                         @{Expression={"{0:N2}" -f ($_.Size / 1073741824)};Label="Size (GB)"} `

                                                                         | ConvertTo-HTML -Fragment) `

                                                                         | %{if($_.Contains("OKHealthy")){$_.Replace("", "<tr style=`"background-color:$($tableColor)`">")}else{$_}}) `

                                                                         + " 
"

$message = $message + "Storage Pool Health: 
"
+ ((Get-StoragePool | `

                                                      where-object {($_.FriendlyName -ne "Primordial")} | `

                                                          Select-Object @{Expression={$_.FriendlyName};Label="Storage Pool Name"}, `

                                                                        @{Expression={$_.OperationalStatus};Label="Operational Status"}, `

                                                                        @{Expression={$_.HealthStatus};Label="Health Status"} `

                                                                        | ConvertTo-HTML -Fragment) `

                                                                        | %{if($_.Contains("OKHealthy")){$_.Replace("", "<tr style=`"background-color:$($tableColor)`">")}else{$_}}) `

                                                                        + " 
"

$message = $message + "Virtual Disk Health: 
"
+ ((Get-VirtualDisk | `

                                                          Select-Object @{Expression={$_.FriendlyName};Label="Virtual Disk Name"}, `

                                                                        @{Expression={$_.OperationalStatus};Label="Operational Status"}, `

                                                                        @{Expression={$_.HealthStatus};Label="Health Status"} `

                                                                        | ConvertTo-HTML -Fragment) `

                                                                        | %{if($_.Contains("OKHealthy")){$_.Replace("", "<tr style=`"background-color:$($tableColor)`">")}else{$_}}) `

                                                                        + " 
"

Notes about this code:

  • I am using “Get-PhysicalDisk”, “Get-StoragePool” and “Get-VirtualDisk” to gather the raw data.
  • Once again – I use raw HTML to set the color of the table headers. 
  • Again – I run the output of these commands through Select-Object with the use of the “Expression” option to set column labels appropriately.
  • Again – I use ConvertTo-HTML –Fragment to get a nice HTML table outputted.
  • Again – I implement color coding for individual entries in the table.  I set each table cell to be “red” by default.  I then do some string parsing to see if the health is good – and switch the background color if I get a positive result.

Cheers,

Ben

Read More