Introduction to Hyper-V and PowerShell
Hyper-V is a virtualization technology developed by Microsoft that allows users to create and manage virtual machines (VMs) on Windows operating systems. It provides a robust platform for deploying and running multiple operating systems concurrently on a single physical server, making it an essential tool for data centers and enterprises seeking to optimize resource utilization. Hyper-V facilitates various functionalities such as VM isolation, load balancing, and dynamic resource allocation, enabling organizations to enhance operational efficiency and operational continuity.
Creating the PowerShell Script to Generate HTML Reports
PowerShell reports make life much easier than going to each Hyper-V host and checking what VM is running where, is the cluster service up etc.
I used a function that was created by Techibee (https://techibee.com/powershell/find-list-of-hyper-v-servers-in-domain-using-powershell/2100), all credit to this person and just built on it and at the end create an HTML report that has nested tables in as well. The script is quite long but it works in PowerShell ISE and PowerShell.
It does Import the Active Directory and Hyper-V module which are two requirements to run it. It searches Active Directory for Hyper-V based on the SCP set for the Hyper-V role. If you do not see your server in the report, you will need to check ADSIEDIT and ensure that the attributes are set correctly.
The File Path where the html file is saved is “C:\Installs”, you can modify it to where you want to save the HTML file. If it cannot find the directory specified the script will terminate.
Below is the PowerShell script:
# Function to get all Hyper-V servers in the domain
function Get-HyperVServersInDomain {
[cmdletbinding()]
param()
try {
Import-Module ActiveDirectory -ErrorAction Stop
} catch {
Write-Warning "Failed to import Active Directory module. Exiting"
return
}
try {
$Hypervs = Get-ADObject -Filter 'ObjectClass -eq "serviceConnectionPoint" -and Name -eq "Microsoft Hyper-V"' -ErrorAction Stop
} catch {
Write-Error "Failed to query active directory. More details : $_"
}
$HyperVServers = @()
foreach ($Hyperv in $Hypervs) {
$temp = $Hyperv.DistinguishedName.split(",")
$HypervDN = $temp[1..$temp.Count] -join ","
$Comp = Get-ADComputer -Id $HypervDN -Prop *
$OutputObj = New-Object PSObject -Prop (
@{
HyperVName = $Comp.Name
OSVersion = $($Comp.operatingSystem)
})
$HyperVServers += $OutputObj
}
return $HyperVServers | Sort-Object HyperVName
}
# Import the Hyper-V module
Import-Module Hyper-V
# Get all Hyper-V hosts
$hyperVHosts = Get-HyperVServersInDomain
# Initialize HTML content
$html = @"
<html>
<head>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: lightgrey;
border: 1px solid black;
padding: 8px;
}
td {
border: 1px solid black;
padding: 8px;
}
.nested-table {
width: 100%;
border-collapse: collapse;
}
.nested-table th, .nested-table td {
border: 1px solid black;
padding: 4px;
}
.uptime-red {
background-color: red;
color: white;
}
.uptime-yellow {
background-color: yellow;
color: black;
}
.uptime-green {
background-color: green;
color: white;
}
.vm-running {
background-color: green;
color: white;
}
.vm-other {
background-color: red;
color: white;
}
.cluster-running {
background-color: green;
color: white;
}
.cluster-not-running {
background-color: red;
color: white;
}
</style>
</head>
<body>
<h2>Hyper-V Hosts and Virtual Machines</h2>
<table>
<tr>
<th>Hyper-V Host</th>
<th>Uptime (Days)</th>
<th>Cluster Service Running</th>
<th>VMs</th>
</tr>
"@
foreach ($hyperVHost in $hyperVHosts) {
try {
# Check if the server is reachable
if (Test-Connection -ComputerName $hyperVHost.HyperVName -Count 1 -Quiet) {
# Get uptime of the Hyper-V host
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $hyperVHost.HyperVName
if ($os) {
$lastBootUpTime = $os.ConvertToDateTime($os.LastBootUpTime)
$uptime = (Get-Date) - $lastBootUpTime
$uptimeDays = $uptime.Days
# Determine uptime color
if ($uptimeDays -gt 35) {
$uptimeClass = "uptime-red"
} elseif ($uptimeDays -le 2) {
$uptimeClass = "uptime-yellow"
} else {
$uptimeClass = "uptime-green"
}
} else {
$uptimeDays = "N/A"
$uptimeClass = ""
}
# Check if the cluster service is running
$clusterService = Get-Service -Name 'ClusSvc' -ComputerName $hyperVHost.HyperVName -ErrorAction SilentlyContinue
if ($clusterService) {
$clusterServiceRunning = $clusterService.Status -eq 'Running'
$clusterServiceClass = if ($clusterServiceRunning) { "cluster-running" } else { "cluster-not-running" }
} else {
$clusterServiceRunning = "N/A"
$clusterServiceClass = ""
}
# Get all VMs on the Hyper-V host
$vms = Get-VM -ComputerName $hyperVHost.HyperVName -ErrorAction SilentlyContinue
$vmTable = @"
<table class='nested-table'>
<tr>
<th>VM Name</th>
<th>VM State</th>
</tr>
"@
if ($vms) {
foreach ($vm in $vms) {
$vmStateClass = if ($vm.State -eq 'Running') { "vm-running" } else { "vm-other" }
$vmTable += @"
<tr>
<td>$($vm.Name)</td>
<td class='$vmStateClass'>$($vm.State)</td>
</tr>
"@
}
} else {
$vmTable += @"
<tr>
<td colspan='2'>No VMs found or unable to retrieve VMs</td>
</tr>
"@
}
$vmTable += "</table>"
$html += @"
<tr>
<td>$($hyperVHost.HyperVName)</td>
<td class='$uptimeClass'>$uptimeDays</td>
<td class='$clusterServiceClass'>$clusterServiceRunning</td>
<td>$vmTable</td>
</tr>
"@
} else {
Write-Host "Host $($hyperVHost.HyperVName) is not reachable."
}
} catch {
Write-Host "Error retrieving information for host $($hyperVHost.HyperVName): $_"
}
}
# Close HTML tags
$html += @"
</table>
</body>
</html>
"@
# Output HTML to a file
$html | Out-File -FilePath "C:\Installs\HyperVReport.html"
Below is a sample of the HTML report that was generated:
It includes uptime, Cluster Service Status and the Virtual Machines (VM’s)
Hope you find it helpful.