2
0

initial commit

This commit is contained in:
2024-07-19 17:17:03 +02:00
parent c42bb7f6d0
commit 0ba5d9c93f

View File

@@ -0,0 +1,376 @@
<#
.SYNOPSIS
This PowerShell script generates a comprehensive Hyper-V status report, including VM status, replication health, and metric details,
and sends it to specified recipients via email.
.DESCRIPTION
This script is designed to provide a detailed report on the status of Hyper-V servers, including the state of virtual machines, replication health,
and performance metrics such as CPU, memory, disk usage, and network traffic. The report is generated in HTML format and sent to specified recipients via email.
The script also includes error handling and logging mechanisms to ensure that any issues are captured and reported.
The report can be customized to include or exclude specific information, and the email recipients can be configured to receive the report on a regular basis.
.NOTES
This script is intended for use in a test or production environment. Make sure to test the script in a non-production environment before running it in production.
Author: D.de Kooker - info@dcomputers.nl
Version: 1.0
DISCLAIMER: Use scripts at your own risk, if there is anything I can help you with I will try but I do not take responsibility for the way that anyone else uses my scripts.
Sharing is caring. Share your knowledge with the world so that everybody can learn from it.
.LINK
The latest version can Always be found on my GIT page on the link below:
https://git.dcomputers.nl/Dcomputers/PowershellScripts
#>
#region script parameters
param (
[parameter()]
[String[]]$HyperVServers = $ENV:COMPUTERNAME
)
#endregion
#region Global script settings and variables
#General
$Version = "v1.0"
$logfilelocation = "$($MyInvocation.MyCommand.Path | Split-Path -Parent)\Logs"
$logfilename = "$(Get-Date -Format yyyyMMddHHmmss).log"
$summaryfilename = "$(Get-Date -Format yyyyMMddHHmmss)-Summary.txt"
#Email report settings
$STR_SMTPServer = ""
$STR_SMTPServerPort = ""
$STR_SMTPUsername = ""
$STR_SMTPPassword = ""
$STR_EmailSubject= "Hyper-V Status Report - $(Get-Date -Format "dd-MM-yyyy")"
$STR_SMTPFromaddress = "ICT Servicedesk <servicedesk@contoso.com>"
$STR_Receivers = "servicedesk@contoso.com,systemengineer1@contoso.com" #List of commaseperated emailaddresses
#endregion
#region functions
function SendMailv2 ($To,$Subject,$Body,$Attachments = @()){
$SMTPClient = New-Object Net.Mail.SmtpClient($STR_SMTPServer, $STR_SMTPServerPort)
# $SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($STR_SMTPUsername, $STR_SMTPPassword);
$SMTPMessage = New-Object System.Net.Mail.MailMessage($STR_SMTPFromaddress,$To,$Subject,$Body)
$SMTPMessage.IsBodyHTML = $true
# Add attachments if provided
if ($Attachments.Count -gt 0) {
foreach ($attachment in $Attachments) {
$SMTPMessage.Attachments.Add((New-Object System.Net.Mail.Attachment($attachment)))
}
}
$SMTPClient.Send($SMTPMessage)
}
function Initiate-Log {
# Get current user and session information
$username = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$computerName = $env:COMPUTERNAME
$sessionID = $pid
$date = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
# Write log header
$logHeader = "[$date] Log initiated by $username on $computerName (Session ID: $sessionID)"
Add-Content -Path $logfilelocation\$logfilename -Value "**********************"
Add-Content -Path $logfilelocation\$logfilename -Value "LogFile initiation"
Add-Content -Path $logfilelocation\$logfilename -Value "Start time: $date"
Add-Content -Path $logfilelocation\$logfilename -Value "Username: $username"
Add-Content -Path $logfilelocation\$logfilename -Value "Machine: $computerName"
Add-Content -Path $logfilelocation\$logfilename -Value "Process ID: $sessionID"
Add-Content -Path $logfilelocation\$logfilename -Value "Script Version: $Version"
Add-Content -Path $logfilelocation\$logfilename -Value "Script Source: https://git.dcomputers.nl/Dcomputers/PowershellScripts"
Add-Content -Path $logfilelocation\$logfilename -Value "**********************"
}
function Write-Log {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[string]$Message,
[Parameter(Mandatory=$false)]
[ValidateSet("INFO", "WARNING", "ERROR")]
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logmessage = "[$timestamp] [$Level] $Message"
Add-Content -Path $logfilelocation\$logfilename -Value $logmessage
}
function Write-Summary {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[string]$Message
)
Add-Content -Path $logfilelocation\$summaryfilename -Value $Message
}
#endregion
#region prerequisites check
#Create log directory if not present and initiate logfile
if (!(test-path $logfilelocation)) {mkdir $logfilelocation}
Initiate-Log
#Check if the required Powershell Modules are available
$modules = @("Hyper-V")
foreach ($module in $modules) {
if (!(Get-Module -Name $module -ListAvailable)) {
Write-Host "The $module module is not installed. Please install it and try again."
Write-Log -Message "The $module module is not installed. Please install it and try again." -Level ERROR
exit 1
}
else {
Import-Module $module
Write-Log -Message "The $module module is loaded." -Level INFO
}
}
#Check connectivity to the Hyper-V Servers
$STR_HVServers = @()
$STR_HVServersError = @()
foreach ($srv in $HyperVServers){
if (Test-WSMan -ComputerName $srv -ErrorAction SilentlyContinue){
$STR_HVServers += $srv
Write-Log -Message "Connection check for $srv successfull" -Level INFO
}
else {
$STR_HVServersError += $srv
Write-Log -Message "Unable to connect to $srv remotely" -Level WARNING
}
}
if (!$STR_HVServers){
Write-Log -Message "No Hyper-V Servers available" -Level ERROR
Write-Log -Message "Stopping script, cannot continue" -Level ERROR
exit 1
}
#endregion
#region script where action is taken
#gather VM information from all Hyper-V servers
$VMinfo = @()
foreach ($hvserver in $STR_HVServers){
$VMs = Get-VM -ComputerName $hvserver | Sort-Object State,Name
foreach ($vm in $VMs) {
$VMinfo += [PSCustomObject]@{
HVServer = $hvserver
VMName = $vm.Name
State = $vm.State
Status = $vm.Status
UpTime = $vm.UpTime
}
}
}
#gather VM replication health from all Hyper-V servers
$VMreplinfo = @()
foreach ($hvserver in $STR_HVServers){
if (Get-VMReplication -ComputerName $hvserver){
Write-Log -Message "Found replica's on $hvserver, collecting data for the report" -Level INFO
$VMs = Get-VMReplication -ComputerName $hvserver | Sort-Object Health -Descending
foreach ($vm in $VMs) {
$VMreplinfo += [PSCustomObject]@{
HVServer = $hvserver
VMName = $vm.Name
ReplicationState = $vm.ReplicationState
ReplicationHealth = $vm.ReplicationHealth
LastReplicationTime = $vm.LastReplicationTime
PrimaryServer = $vm.PrimaryServer
ReplicaServer = $vm.ReplicaServer
ReplicationMode = $vm.ReplicationMode
RelationshipType = $vm.RelationshipType
}
}
}
else {
Write-Log -Message "No replica's found on $hvserver" -Level WARNING
}
}
#gather VM metric data form all Hyper-V servers
$VMmetricinfo = @()
foreach ($hvserver in $STR_HVServers){
if (Get-VM -ComputerName $hvserver | Measure-VM -ErrorAction SilentlyContinue){
Write-Log -Message "Found Metric info on $hvserver, collecting data for the report" -Level INFO
$VMs = Get-VM -ComputerName $hvserver | Where-Object {$_.Name -notlike "*replica*" -and $_.Name -notlike "*maintenance*"} | Measure-VM -ErrorAction SilentlyContinue | Sort-Object VMName
foreach ($vm in $VMs) {
$VMmetricinfo += [PSCustomObject]@{
HVServer = $hvserver
VMName = $vm.VMName
AvgCPU = $vm.AvgCPU
AvgRAM = ($vm.AvgRAM / 1024)
TotalDisk = ($vm.TotalDisk / 1024)
InboundNWTraffic = (($vm.NetworkMeteredTrafficReport | where-object {($_.Direction -eq "Inbound")} | measure-object TotalTraffic -sum).sum / 1024)
OutboundNWTraffic = (($vm.NetworkMeteredTrafficReport | where-object {($_.Direction -eq "Outbound")} | measure-object TotalTraffic -sum).sum / 1024)
MeteringDuration = $vm.MeteringDuration
}
#reset metric count
Get-VM -Name $($vm.VMName) -ComputerName $hvserver | Reset-VMResourceMetering
}
}
else {
Write-Log -Message "No Metric info found on $hvserver" -Level WARNING
}
Write-Log -Message "Enable metric logging for possible vm's" -Level INFO
Get-VM -ComputerName $hvserver | Where-Object {$_.Name -notlike "*replica*" -and $_.Name -notlike "*maintenance*"} | Enable-VMResourceMetering
}
#endregion
#region send reports and generate summary report
#Generate HTML report based on gathered info
$htmlReport = @"
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<style>
body{
font-family: 'Verdana', sans-serif;
font-size:9pt;
}
h2{
font-size: 12pt; /* sets the font size to 18 points */
font-weight: bold; /* sets the font weight to bold */
margin-bottom: 10px; /* adds a margin of 10 pixels below the heading */
}
h3{
font-size: 10pt; /* sets the font size to 18 points */
font-weight: bold; /* sets the font weight to bold */
}
tbody{
font-family: 'Verdana', sans-serif;
font-size:9pt;
}
th{
font-weight: bold; /* sets the font weight to bold */
padding-right:5px;
}
td{
padding-right:5px;
}
</style>
</head>
<body>
<h2>Hyper-V Status Report - $(Get-Date -Format "dd-MM-yyyy - HH:mm")</h2>
Script version: $Version <br/>
Checked Servers: $STR_HVServers <br/>
$(if ($STR_HVServersError){
"Unable to connect to servers: $STR_HVServersError"
})</p>
"@
foreach ($hvserver in $HyperVServers) {
#Generate VM status table
$htmlReport += @"
<h3>Server: $hvserver - VM Status</h3>
<table border='1'>
<tr>
<th>VM Name</th>
<th>State</th>
<th>Operational Status</th>
<th>Up Time</th>
</tr>
"@
foreach ($vm in ($VMinfo | Where-Object {$_.HVServer -eq $hvserver})) {
$htmlReport += @"
$(switch ($vm){
{($_.State -eq 'OFF') -and ($_.VMName -notlike "*replica*" -and $_.VMName -notlike "*maintenance*")} {"<tr bgcolor='Red'>"}
{($_.State -eq 'Saved') -and ($_.VMName -notlike "*replica*" -and $_.VMName -notlike "*maintenance*")} {"<tr bgcolor='Yellow'>"}
default {"<tr>"}
} )
<td>$($vm.VMName)</td>
<td>$($vm.State)</td>
<td>$($vm.Status)</td>
<td>$($vm.UpTime)</td>
</tr>
"@
}
$htmlReport += "</table>"
#Generate VM Replication Health table
$htmlReport += @"
<h3>Server: $hvserver - VM Replication Health</h3>
<table border='1'>
<tr>
<th>VM Name</th>
<th>State</th>
<th>Health</th>
<th>LastReplicationTime</th>
<th>PrimaryServer</th>
<th>ReplicaServer</th>
<th>Mode</th>
<th>Relation</th>
</tr>
"@
foreach ($vm in ($VMreplinfo | Where-Object {$_.HVServer -eq $hvserver})) {
$htmlReport += @"
$(switch ($vm.ReplicationHealth){
'Critical' {"<tr bgcolor='Red'>"}
'Warning' {"<tr bgcolor='Yellow'>"}
default {"<tr>"}
} )
<td>$($vm.VMName)</td>
<td>$($vm.ReplicationState)</td>
<td>$($vm.ReplicationHealth)</td>
<td>$($vm.LastReplicationTime)</td>
<td>$($vm.PrimaryServer)</td>
<td>$($vm.ReplicaServer)</td>
<td>$($vm.ReplicationMode)</td>
<td>$($vm.RelationshipType)</td>
</tr>
"@
}
$htmlReport += "</table>"
#Generate VM Metric details table
$htmlReport += @"
<h3>Server: $hvserver - VM Metric details</h3>
<table border='1'>
<tr>
<th>VM Name</th>
<th>Average CPU Utilization (MHz)</th>
<th>Average Memory (GB)</th>
<th>Disk Space Used (GB)</th>
<th>Inbound Network Traffic (GB)</th>
<th>Outbound Network Traffic (GB)</th>
<th>Metering data duration</th>
</tr>
"@
foreach ($vm in ($VMmetricinfo | Where-Object {$_.HVServer -eq $hvserver})) {
$htmlReport += @"
$(switch ($vm.ReplicationHealth){
'Critical' {"<tr bgcolor='Red'>"}
'Warning' {"<tr bgcolor='Yellow'>"}
default {"<tr>"}
} )
<td>$($vm.VMName)</td>
<td>$($vm.AvgCPU)</td>
<td>$($vm.AvgRAM)</td>
<td>$($vm.TotalDisk)</td>
<td>$($vm.InboundNWTraffic)</td>
<td>$($vm.OutboundNWTraffic)</td>
<td>$($vm.MeteringDuration)</td>
</tr>
"@
}
$htmlReport += "</table>"
}
$htmlReport += @"
<p><i>This is an automated report.</i></p>
</body>
</html>
"@
#Send email with the generated report
$reportstatus = "OK"
switch ($htmlReport) {
{ $_ -like "*bgcolor='Red'*" } { $reportstatus = "ERROR"; break }
{ $_ -like "*bgcolor='Yellow'*" } { $reportstatus = "WARNING"; break }
}
if ($reportstatus -ne "OK") {
$subject = "$($reportstatus): $STR_EmailSubject"
}
else {
$subject = "$STR_EmailSubject"
}
SendMailv2 -To $STR_Receivers -Subject $subject -Body $htmlReport
#endregion