V 1.1 Released

 

A PowerShell script for Hyper-V Administrator to identify the consistency of Windows Updates, HBA Drivers, HBA Firmware, Network Interface Drivers etc. This is the first version. Please provide your feedback as comments. Also if let me know if you would like to see any specific version on the next version.

 

Hyper-V update status

 The list of available updates are fetched from the Technet Wiki page - http://social.technet.microsoft.com/wiki/contents/articles/20885.hyper-v-update-list-for-windows-server-2012-r2.aspx

 

As these are more crucial for the Hyper-V infrastructure, Each updates are checked across the cluster nodes and listed out.

 

 

Windows Updates Status

 

Check for all nodes and identify the missing updates. The master update list is build based on all updates installed on the server. Also list out the missing updates on each node compared to the master updates.

 

 

 

HBA Drivers/Firmwares Status

Check for the installed HBA cards on all nodes and list the Firmware/Driver.

 

 

 Network Interface Drivers

If Powershell remoting is enabled on the cluster nodes, This script will also check for the Network Interface Driver version.

 

 

 

Usage:

Edit the script - Line 8 and add your cluster name.

$cluname = "YOURCLUSTERNAME"

Edit Line 336 - Modify the Recipients Email Address and the SMTP server

Send-MailMessage -To yourname@yourdomain.com -From HyperV-Dashboard@InsideVirtualization.com -Body (Get-Content $ResultFile |Out-String) -SmtpServer smtp.yourdomain.com -Subject "Hyper-V Cluster - Updates/Driver/Firmware Consistency Report" -BodyAsHtml

Run the script from PowerShell Elevated Mode.

 

Note - You may get a IE Security Popup related with Internet Explorer Enhanced Security Configuration. Just close that. I am not sure how to avoid this. 

 

Thanks Ben for Get-HbaWin.

http://gallery.technet.microsoft.com/scriptcenter/Find-HBA-and-WWPN-53121140

 

Version History:

 

V.1.1  11/5/2014

* Minor bug fix based on community feedback  (Cannot index into a null arra on Line 308)

PowerShell
Edit|Remove
# Created By - Shabarianth Ramadasan - InsideVirtualization.Com 
# shabarinath@insidevirtualization.com 
# Data - 11/05/2014 
Import-Module -Name FailoverClusters, hyper-$ResultFile = "HyperV-Host-Details.htm"  
New-Item -ItemType File $ResultFile -Force 
$dt = Get-Date 
$Nodes = Get-ClusterNode -Cluster YOURCLUSTERNAME 
$Count = $Nodes.Count 
Get-ClusterNode -Cluster cs-mshv-clu6 |Foreach {$MasterUpdateList = $MasterUpdateList + (Get-HotFix -Computer $_.Name).HotfixID} 
$MasterUpdateList = $MasterUpdateList|Sort -Unique 
$TechnetWikiPage = Invoke-WebRequest "http://social.technet.microsoft.com/wiki/contents/articles/20885.hyper-v-update-list-for-windows-server-2012-r2.aspx" 
@($TechnetWikiPage.ParsedHtml.getElementsByTagName("table"))[1]|Select-Object OuterText |Select-String -Pattern "KB"|Out-File KB.txt 
foreach ($line in (Get-Content .\kb.txt))  
    { 
    if ($line -match "KB" -And $Line -notmatch "kb article" -And $line.length -gt "20")  
        { 
        $line.substring($line.IndexOf("KB"),10) |Out-File KbList.Txt -append 
        } 
    } 
$kblist = Get-content kblist.txt 
$kblen = $kblist.length 
For ($i=0; $i -lt $kblen$i++) 
    { 
    If($kblist[$i].IndexOf(" ")) 
        { 
        $kblist[$i] = $kblist[$i].Replace(" ","") 
        } 
    If($kblist[$i].IndexOf(":")) 
        { 
        $kblist[$i] = $kblist[$i].Replace(":","") 
        } 
    } 
Remove-Item kb.txt -Force 
Remove-item KbList.Txt -Force 
Function fWriteHtmlHeader  
    {  
    Param ($FileName)  
    $date = ( get-date ).ToString('yyyy/MM/dd')  
    Add-Content $FileName "<html>"  
    Add-Content $FileName "<head>"  
    Add-Content $FileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"  
    Add-Content $FileName '<title>Hyper-V Cluster - Updates/Driver/Firmware Consistency Report</title>'  
    Add-Content $FileName '<STYLE TYPE="text/css">'  
    Add-Content $FileName  "<!--"  
    Add-Content $FileName  "td {"  
    Add-Content $FileName  "font-family: Tahoma;"  
    Add-Content $FileName  "font-size: 11px;"  
    Add-Content $FileName  "border-top: 1px solid #999999;"  
    Add-Content $FileName  "border-right: 1px solid #999999;"  
    Add-Content $FileName  "border-bottom: 1px solid #999999;"  
    Add-Content $FileName  "border-left: 1px solid #999999;"  
    Add-Content $FileName  "}"  
    Add-Content $FileName  "body {"  
        Add-Content $FileName  "margin-left: 5px;"  
    Add-Content $FileName  "margin-top: 5px;"  
    Add-Content $FileName  "margin-right: 5px;"  
    Add-Content $FileName  "margin-bottom: 5px;"  
    Add-Content $FileName  ""  
    Add-Content $FileName  "table {"  
    Add-Content $FileName  "border: thin solid #000000;"  
    Add-Content $FileName  "}"  
    Add-Content $FileName  "-->"  
    Add-Content $FileName  "</style>"  
    Add-Content $FileName "</head>"  
    Add-Content $FileName "<body>"  
    Add-Content $FileName  "<table width='100%'>"  
    Add-Content $FileName  "<tr bgcolor='#0B0B61'>"  
    Add-Content $FileName  "<td colspan='30' height='20' align='center'>"  
    Add-Content $FileName  "<font face='tahoma' color='#FF0040' size='4'><strong>Hyper-V Cluster - Windows Updates/Driver/Firmware Consistency Report -  $date</strong></font>"  
    Add-Content $FileName  "</td>"  
    Add-Content $FileName  "</tr>"  
    Add-Content $FileName  "</table>"  
        }  
 
Function fWriteHyperVUpdateTableHeader 
    {  
    Param ($FileName) 
    $TechnetWikiURL = "<a href = 'http://social.technet.microsoft.com/wiki/contents/articles/20885.hyper-v-update-list-for-windows-server-2012-r2.aspx' style= color: #FFFF00 >Technet Wiki</a>" 
    Add-Content $FileName  "<table width='100%'>"  
    Add-Content $FileName  "<tr colspan='1' height='20' align='center' bgcolor='#282828'>"  
    Add-Content $FileName  "<td width = '100%' size='2' align=center><font color='yellow'><strong>Hyper-V Update Status - Based on $TechnetWikiURL</a></font></strong></td>"  
    Add-Content $FileName  "</tr>" 
        Add-Content $FileName  "</table>"  
    [int] $Spacing = 100/($Count + 1) 
    Add-Content $FileName  "<table width='100%'>" 
     Add-Content $FileName "<tr bgcolor=#BE81F7>"  
    Add-Content $FileName "<td width='$Spacing%' align=center>KB</td>" 
    For ($i=0; $i -lt $Count$i++) 
        { 
        $cname = $Nodes[$i].Name 
        Add-Content $FileName "<td width='$spacing%' align=center>$cname</td>" 
        $cname 
        } 
    Add-Content $FileName "</tr>"  
    } 
 
Function fWriteHyperVUpdateTable 
    { 
    Param ($FileName$KBid) 
    [int] $Spacing = 100/($Count + 1) 
    Add-Content $FileName "<td width='$Spacing%' align=center>$KBid</td>" 
    For ($j=0; $j -lt $count$j++) 
        { 
        IF (Get-HotFix -Id $KBid -ComputerName $Nodes.Name[$j-ErrorAction SilentlyContinue) 
            { 
            Add-Content $FileName "<td width='$spacing%' BGCOLOR='#74DF00' align=center>Installed</td>" 
            } 
        Else 
            { 
            Add-Content $FileName "<td width='$spacing%' align=center>NotInstalled</td>" 
            } 
        } 
    Add-Content $FileName "</tr>" 
    } 
         
Function fWriteWindowsUpdateTableHeader 
    { 
    Param ($FileName) 
    Add-Content $FileName  "<table width='100%'>"  
    Add-Content $FileName  "<tr colspan='1' height='20' align='center' bgcolor='#282828'>"  
    Add-Content $FileName  "<td width = '100%' size='2' align=center><font color='yellow'><strong>Windows Update Check - To identify all cluster nodes has same level of updates</a></font></strong></td>"  
    Add-Content $FileName  "</tr>" 
        Add-Content $FileName  "</table>"  
    Add-Content $FileName  "<table width='100%'>" 
     Add-Content $FileName "<tr bgcolor=#BE81F7>"  
    Add-Content $FileName "<td width='10%' align=center>NodeName</td>" 
    Add-Content $FileName "<td width='10%' align=center>TotalPatchesInstalled</td>" 
    Add-Content $FileName "<td width='10%' align=center>TotalMissingPatches</td>" 
    Add-Content $FileName "<td width='10%' align=center>MissingPatches</td>" 
    Add-Content $FileName "</tr>" 
    } 
 
Function fWriteWindowsUpdateTable 
    { 
    Param ($FileName$cname$installedu$missingu$missingkb) 
    Add-Content $FileName "<tr>" 
    Add-Content $FileName "<td width='10%' align=center>$cname</td>" 
    Add-Content $FileName "<td width='10%' align=center>$installedu</td>" 
    Add-Content $FileName "<td width='10%' align=center>$missingu</td>" 
    Add-Content $FileName "<td width='70%' align=left>$missingkb</td>" 
    Add-Content $FileName "</tr>" 
    } 
 
Function fWriteHBATableHeader 
    { 
    Param ($FileName) 
    Add-Content $FileName  "<table width='100%'>"  
    Add-Content $FileName  "<tr colspan='1' height='20' align='center' bgcolor='#282828'>"  
    Add-Content $FileName  "<td width = '100%' size='2' align=center><font color='yellow'><strong>HBA Check - To identify all cluster nodes as same level of HBA Drivers/Firmware</a></font></strong></td>"  
    Add-Content $FileName  "</tr>" 
        Add-Content $FileName  "</table>"  
    Add-Content $FileName  "<table width='100%'>" 
     Add-Content $FileName "<tr bgcolor=#BE81F7>"  
    Add-Content $FileName "<td width='10%' align=center>NodeName</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1Model</td>" 
    Add-Content $FileName "<td width='15%' align=center>HBA1-ModelDescription</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1Status</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1WWN</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1DriverName</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA1FirmwareVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2Model</td>" 
    Add-Content $FileName "<td width='15%' align=center>HBA2-ModelDescription</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2Status</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2WWN</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>HBA2FirmwareVer</td>" 
    Add-Content $FileName "</tr>" 
    } 
 
Function fWriteHBATable 
    { 
    Param ($FileName$cname$HBA1Model$HBA1ModelD$HBA1Status$HBA1WWN$HBA1DriverN$HBA1DriverV$HBA1FirmwareV$HBA2Model$HBA2ModelD$HBA2Status$HBA2WWN$HBA2DriverN$HBA2DriverV$HBA2FirmwareV) 
    Add-Content $FileName "<tr>" 
    Add-Content $FileName "<td width='10%' align=center>$cname</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1Model</td>" 
    Add-Content $FileName "<td width='15%' align=center>$HBA1ModelD</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1Status</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1WWN</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1DriverN</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1DriverV</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA1FirmwareV</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2Model</td>" 
    Add-Content $FileName "<td width='15%' align=center>$HBA2ModelD</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2Status</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2WWN</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2DriverN</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2DriverV</td>" 
    Add-Content $FileName "<td width='5%' align=center>$HBA2FirmwareV</td>" 
    Add-Content $FileName "</tr>" 
    } 
 
Function fWriteNICTableHeader 
    { 
    Param ($FileName) 
    Add-Content $FileName  "<table width='100%'>"  
    Add-Content $FileName  "<tr colspan='1' height='20' align='center' bgcolor='#282828'>"  
    Add-Content $FileName  "<td width = '100%' size='2' align=center><font color='yellow'><strong>Network Interface Check - To identify all cluster nodes has same version of NIC Drivers</a></font></strong></td>"  
    Add-Content $FileName  "</tr>" 
        Add-Content $FileName  "</table>"  
    Add-Content $FileName  "<table width='100%'>" 
     Add-Content $FileName "<tr bgcolor=#BE81F7>"  
    Add-Content $FileName "<td width='10%' align=center>NodeName</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC1-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC1MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC1DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC2-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC2MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC2DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC3-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC3MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC3DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC4-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC4MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC4DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC5-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC5MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC5DriverVer</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC6-Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC6MAC</td>" 
    Add-Content $FileName "<td width='5%' align=center>NIC6DriverVer</td>" 
    Add-Content $FileName "</tr>" 
    } 
 
Function fWriteNICTable 
    { 
    Param ($FileName$cname$Nic1Name$Nic1Mac$Nic1Driver$Nic2Name$Nic2Mac$Nic2Driver$Nic3Name$Nic3Mac$Nic3Driver$Nic4Name$Nic4Mac$Nic4Driver$Nic5Name$Nic5Mac$Nic5Driver$Nic6Name$Nic6Mac$Nic6Driver) 
    Add-Content $FileName "<tr>"  
    Add-Content $FileName "<td width='10%' align=center>$cname</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic1Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic1Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic1Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic2Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic2Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic2Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic3Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic3Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic3Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic4Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic4Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic4Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic5Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic5Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic5Driver</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic6Name</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic6Mac</td>" 
    Add-Content $FileName "<td width='5%' align=center>$Nic6Driver</td>" 
    Add-Content $FileName "</tr>" 
    } 
Function fWriteHtmlFooter  
    {  
    Param ($FileName)   
    Add-Content $FileName "</body>"  
    Add-Content $FileName "</html>"  
    }  
 
Function Get-HBAWin 
    {   
    Param ([String[]]$ComputerName = $ENV:ComputerName, [Switch]$LogOffline)   
   
    $ComputerName | ForEach-Object {   
    try {  
        $Computer = $_  
         $Params = @{  
        Namespace    = 'root\WMI'  
        class        = 'MSFC_FCAdapterHBAAttributes'  
        ComputerName = $Computer   
        ErrorAction  = 'Stop'  
        }  
      
        Get-WmiObject @Params  | ForEach-Object {   
            $hash=@{   
                ComputerName     = $_.__SERVER   
                NodeWWN          = (($_.NodeWWN) | ForEach-Object {"{0:x}" -$_}) -join ":"   
                Active           = $_.Active   
                DriverName       = $_.DriverName   
                DriverVersion    = $_.DriverVersion   
                FirmwareVersion  = $_.FirmwareVersion   
                Model            = $_.Model   
                ModelDescription = $_.ModelDescription   
                }   
            New-Object psobject -Property $hash   
        }#Foreach-Object(Adapter)   
}#try  
catch {  
    Write-Warning -Message $_  
    if ($LogOffline)  
    {  
        "$Computer is offline or not supported" 
    }  
}  
 
}#Foreach-Object(Computer)   
   
}#Get-HBAWin 
 
fWriteHtmlHeader $ResultFile 
fWriteHyperVUpdateTableHeader $ResultFile 
$KbList |Foreach {fWriteHyperVUpdateTable $ResultFile $_Add-Content $ResultFile  "</table>"  
fWriteWindowsUpdateTableHeader $ResultFile 
For ($l=0; $l -lt $Count$l++) 
    { 
    $miskb = "" 
    [array] $InstalledUpdates = Get-Hotfix -ComputerName $Nodes.Name[$l] 
    $MissingUpdates = (Compare-Object -ReferenceObject $MasterUpdateList -DifferenceObject (($InstalledUpdates).HotfixID))|Select InputObject 
    $MissingUpdates |foreach {[string] $miskb +=" "+ $_.Inputobject } 
    fWriteWindowsUpdateTable $ResultFile $nodes.name[$l$InstalledUpdates.Count $MissingUpdates.Count $miskb 
    } 
Add-Content $ResultFile  "</table>"  
fWriteHBATableHeader $ResultFile 
For ($m=0; $m -lt $Count$m++) 
    { 
    $HBAResult = Get-HBAWin -Computer $Nodes[$m].name 
    fWriteHBATable $ResultFile $HBAResult[0].ComputerName $HBAResult[0].Model $HBAResult[0].ModelDescription $HBAResult[0].Active $HBAResult[0].NodeWWN $HBAResult[0].DriverName $HBAResult[0].DriverVersion $HBAResult[0].FirmwareVersion $HBAResult[1].Model $HBAResult[1].ModelDescription $HBAResult[1].Active $HBAResult[1].NodeWWN $HBAResult[1].DriverName $HBAResult[1].DriverVersion $HBAResult[1].FirmwareVersion 
    } 
Add-Content $ResultFile  "</table>"  
$TableInit = "0" 
For ($n=0; $n -lt $Count$n++) 
    { 
    If (Test-WSMan -ComputerName $Nodes.Name[$n]) 
        { 
        If ($TableInit -eq "0") 
            { 
            fWriteNICTableHeader $ResultFile 
            $TableInit = "1" 
            } 
        $NicResult = Invoke-Command -ComputerName $Nodes.Name[$n-ScriptBlock {Get-NetAdapter -Physical} 
        fWriteNICTable $ResultFile $Nodes.Name[$n$NicResult.Name[0] $NicResult.MacAddress[0] $NicResult.DriverVersionString[0] $NicResult.Name[1] $NicResult.MacAddress[1] $NicResult.DriverVersionString[1] $NicResult.Name[2] $NicResult.MacAddress[2] $NicResult.DriverVersionString[2] $NicResult.Name[3] $NicResult.MacAddress[3] $NicResult.DriverVersionString[3] $NicResult.Name[4] $NicResult.MacAddress[4] $NicResult.DriverVersionString[4] $NicResult.Name[5] $NicResult.MacAddress[5] $NicResult.DriverVersionString[5] 
        } 
    } 
Add-Content $ResultFile  "</table>" 
fWriteHtmlFooter $ResultFile 
Send-MailMessage -To youremail@yourdomain.com -From HyperV-Dashboard@InsideVirtualization.com -Body (Get-Content $ResultFile |Out-String-SmtpServer yoursmtpserver.yourdomain.com -Subject "HyperV Host - Consistency Report" -BodyAsHtml 
Remove-Item $ResultFile -Force