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:

Using powershell to generate html reports of hyper-v hosts and their virtual machines
Using powershell to generate html reports of hyper-v hosts and their virtual machines

It includes uptime, Cluster Service Status and the Virtual Machines (VM’s)

Hope you find it helpful.

Discover more from Everything-PowerShell

Subscribe now to keep reading and get access to the full archive.

Continue reading