# # Generate the html report and save it to the report folder # TODO: change to the class Function Export-VCGReport { Param( [Parameter(Mandatory=$true)] $Data, [Parameter(Mandatory=$true)] $Dir ) if (!(Test-Path $Dir)) { New-Item -Type directory -Confirm:$false -Path $Dir -Force |Out-Null } $Data,$flag = refactorData $Data $null=Generate_CsvReport $Data $Dir $null=Generate_HtmlReport $Data $Dir $null=Generate_SummaryReport $Data $Dir } Function Generate_HtmlReport($Data, $Dir) { info ("Generating compatibility detail report...") $content = $generalHead $content += '

ESXi Hardware Compatibility Report for {0}

' -f $Data.hostname $content += $generalBodyBase if (-not(checkVersion($Data))) { $content += 'Installed Release' } else { $content += 'Checked Release' } $content += $generalBodyRest foreach ($VCResource in $Data) { $checkVersion = $VCResource.checkRelease $Count1 = $VCResource.DCResource.HostResource.ComponentResource.Count $Process = '' if ($VCResource.hostname -ne 'null') { $Process += '{1}' -f $Count1, [string]$VCResource.hostname } else { $Process += '{1}' -f $Count1, '/' } foreach ($DCResource in $VCResource.DCResource) { $Count2 = $DCResource.HostResource.ComponentResource.Count if ($DCResource.dcname -ne 'null') { $Process += '{1}' -f [string]$Count2, [string]$DCResource.dcname } else { $Process += '{1}' -f [string]$Count2, '/' } foreach ($HostResourceOne in $DCResource.HostResource) { $Count = $HostResourceOne.ComponentResource.count $Process += '{1}' -f $Count, $HostResourceOne.HostName foreach ($OneDevice in $HostResourceOne.ComponentResource) { if ($OneDevice.type -eq 'Server') { # $InfoServer = "" | Select HostName, Manufacturer, Model, CPU, Version, Bios, CpuFeature, Uuid, VcgLink, Status, FoundRelease, MatchResult, Warnings $InfoServer = @{} $InfoServer.HostName = $HostResourceOne.hostname $InfoServer.Version = $HostResourceOne.version $InfoServer.Manufacturer = $OneDevice.vendor $InfoServer.Model = $OneDevice.model $InfoServer.CPU = $OneDevice.cpumodel $InfoServer.Bios = $OneDevice.biosversion $InfoServer.CpuFeature = $OneDevice.cpufeatureid $InfoServer.Uuid = $OneDevice.uuid $InfoServer.VcgLink = $OneDevice.vcgLink $InfoServer.Status = formatStatus($OneDevice.status) $InfoServer.MatchResult = $OneDevice.matchResult $InfoServer.Warnings = (([string]$OneDevice.warnings) -split "More information")[0] # server info $Process += 'Server' $Process += '{0}' -f $InfoServer.Model $Process += '{0}' -f $InfoServer.Manufacturer if (-not $checkVersion) { $Process += '{0}' -f $InfoServer.Version } else { $Process += '{0}' -f $checkVersion } $Process += '{0}' -f $InfoServer.Status $Process += '{0},
CpuFeature:{1},
Bios:{2}' -f $InfoServer.CPU, $InfoServer.CpuFeature, $InfoServer.Bios if ($InfoServer.VcgLink.Count -gt 0) { $Process += '{0}
' -f $InfoServer.Warnings foreach ($link in $InfoServer.VcgLink) { $Process += ' VCG link
' -f $link } $Process += '' } else {$Process += '{0}
N/A' -f $InfoServer.Warnings} $Process += '' } else { # $InfoPci = "" | Select model, vendor, Vid, Did, Svid, Ssid, Driver, DriverVersion, Version, Pccid, VcgLink, Status, FoundRelease, MatchResult, Warnings $InfoPci = @{} $InfoPci.model = $OneDevice.model $InfoPci.vendor = $OneDevice.vendor $InfoPci.Vid = $OneDevice.vid $InfoPci.Did = $OneDevice.did $InfoPci.Svid = $OneDevice.svid $InfoPci.Ssid = $OneDevice.ssid $InfoPci.Driver = $OneDevice.driver $InfoPci.DriverVersion = $OneDevice.driverversion $InfoPci.Version = $HostResourceOne.version $InfoPci.Pccid = $OneDevice.pciid $InfoPci.VcgLink = $OneDevice.vcgLink $InfoPci.Status = formatStatus($OneDevice.status) $InfoPci.MatchResult = $OneDevice.matchResult $InfoPci.Warnings = (([string]$OneDevice.warnings) -split "More information")[0] # IO info # TODO:Variable information coverage, need to be modified $Process += '' $Process += 'IO Device' $Process += '{0}' -f $InfoPci.model $Process += '{0}' -f $InfoPci.vendor if (-not $checkVersion) { $Process += '{0}' -f $InfoPci.Version } else { $Process += '{0}' -f $checkVersion } $Process += '{0}' -f $InfoPci.Status $Process += 'PCI ID:{0}
Driver:{1} Version:{2}' -f $InfoPci.Pccid, $InfoPci.Driver, $InfoPci.DriverVersion if ($InfoPci.VcgLink.Count -gt 0) { $Process += '{0}
' -f $InfoPci.Warnings foreach ($link in $InfoPci.VcgLink) { $Process += ' VCG link
' -f $link } $Process += '' } else {$Process += '{0}
N/A' -f $InfoPci.Warnings} $Process += '' } } } } $content += $Process } $content += $generalFooter #define filename and filepath $dataTime = Get-Date -Format 'yyyy-M-d_h-m' $vcName = vcName($Data) $filename = 'compreport_' + $vcName + $dataTime + '.html' $filePath = $Dir + '\' + $filename #save report $content |Out-File -FilePath $filePath -Encoding utf8| Out-Null info ("Report " + "'" + $filePath + "'" + " has been created!") } Function Generate_SummaryReport($Data, $Dir) { info ("Generating compatibility summary report...") $content = $summaryHead $vcCount = $Data.length $barsWidth = 45 / ($vcCount+1) $content += 'var barsWidth = {0};' -f $barsWidth # get vCName arry and host count $vcNameArray = @() foreach ($DCResource in $Data) { $vcNameArray += $DCResource.DCResource[0].vcname } $content += "var vCname = [" foreach ($vc in $vcNameArray) { $content += '"{0}",' -f $vc } $content += "];" # Count Compatible or unpgrade $compatibleCountFormat = '[' $mayNotCompatibleCountFormat = '[' $UnabletoUpgradeCountFormat = '[' foreach ($VCResource in $Data) { $checkVersion = $VCResource.checkRelease $compatibleCount = 0 $notcompatibleCount = 0 $UnabletoUpgradeCount = 0 foreach ($DCResource in $VCResource.DCResource) { foreach ($HostResourceOne in $DCResource.HostResource) { foreach ($OneDevice in $HostResourceOne.ComponentResource) { $flagcompatible = 0 # if($checkVersion){ # if(-not($OneDevice.upgrade)){ # $flagcompatible = 'null' # break # } # } #whether compatible if ($OneDevice.status -ne 'Compatible') { $flagcompatible = 0 break } else { $flagcompatible = 1 } #whether upgrade } if ($flagcompatible -eq 1) { $compatibleCount += 1 } elseif($flagcompatible -eq 0){ $notcompatibleCount += 1 } elseif($flagcompatible -eq 'null') { $UnabletoUpgradeCount += 1 } } } $compatibleCountFormat += $compatibleCount $compatibleCountFormat += ',' $mayNotCompatibleCountFormat += $notcompatibleCount $mayNotCompatibleCountFormat += ',' $UnabletoUpgradeCountFormat += $UnabletoUpgradeCount $UnabletoUpgradeCountFormat += ',' } $compatibleCountFormat += ',]' $mayNotCompatibleCountFormat += ',]' $UnabletoUpgradeCountFormat += ']' $dataDict = [Ordered]@{} if (-not(checkVersion($Data))) { $content += 'var lengendSeries = ["Compatible","May Not Compatible"];' $content += $hostCountHead $dataDict.Insert(0, "Compatible", $compatibleCountFormat) $dataDict.Insert(1, "May Not Compatible", $mayNotCompatibleCountFormat) } else { $content += 'var lengendSeries = ["Compatible","May Not Compatible","Unable to upgrade"];' $content += $hostCountHead $dataDict.Insert(0, "Compatible", $compatibleCountFormat) $dataDict.Insert(1, "May Not Compatible", $mayNotCompatibleCountFormat) $dataDict.Insert(2, "Unable to upgrade", $UnabletoUpgradeCountFormat) } [System.Collections.IEnumerator]$dataDict = $dataDict.Keys.GetEnumerator(); $formatContent = formatHostCountGraphic $dataDict $content += $formatContent $content += $hostCountRest # Host Compatibility $compatibleCount = 0 $mayNotcompatibleCount = 0 $unableUpgradeCount = 0 foreach ($VCResource in $Data) { foreach ($DCResource in $VCResource.DCResource) { foreach ($HostResourceOne in $DCResource.HostResource) { foreach ($OneDevice in $HostResourceOne.ComponentResource) { #whether compatible $flagcompatible = 0 # if ($checkVersion){ # if (-not($OneDevice.upgrade)){ # $flagcompatible = 'null' # break # } # } if ($OneDevice.status -ne 'Compatible') { $flagcompatible = 0 break } else { $flagcompatible = 1 } } if ($flagcompatible -eq 1) { $compatibleCount += 1 } elseif ($flagcompatible -eq 0) { $mayNotcompatibleCount += 1 } elseif ($flagcompatible -eq 'null') { $unableUpgradeCount += 1 } } } } if (-not(checkVersion($Data))) { $content += "var seriesCount = {'Compatible':$compatibleCount, 'May Not Compatible':$mayNotcompatibleCount,};" $content += "var lengendSeries = ['Compatible','May Not Compatible'];" $content += "var catalog = [ {value:seriesCount['Compatible'], name:'Compatible'}, {value:seriesCount['May Not Compatible'], name:'May Not Compatible'}, ];" $content += "var colors = [colorsC,colorsM];" } else { $content += "var seriesCount = {'Compatible':$compatibleCount, 'May Not Compatible':$mayNotcompatibleCount,'Unable to Upgrade':$unableUpgradeCount};" $content += "var lengendSeries = ['Compatible','May Not Compatible','Unable to Upgrade'];" $content += "var catalog = [ {value:seriesCount['Compatible'], name:'Compatible'}, {value:seriesCount['May Not Compatible'], name:'May Not Compatible'}, {value:seriesCount['Unable to Upgrade'], name:'Unable to Upgrade'}, ];" $content += "var colors = [colorsC,colorsM,colorsU];" } $content += $hostCompatible #Host Model Compatibility by vCenter if (-not(checkVersion($Data))) { $serverSource = "[['series', 'Compatible', 'May Not Compatible',]," } else { $serverSource = "[['series', 'Compatible','May Not compatible','No Upgrade Path']," } foreach ($VCResource in $Data) { $compatibleCount = 0 $mayNotCompatibleCount = 0 $unableUpgradeCount = 0 $checkVersion = $VCResource.checkRelease foreach ($DCResourceOne in $VCResource.DCResource) { foreach ($HostResourceOne in $DCResourceOne.HostResource) { $flagcompatible = 0 foreach ($ComoenentResourceOne in $HostResourceOne.ComponentResource) { #whether compatible if ($ComoenentResourceOne.type -eq 'Server') { # if ($checkVersion) { # if (-not($ComoenentResourceOne.upgrade)) { # $flagcompatible = 'null' # break # } # } if ($ComoenentResourceOne.status -ne 'Compatible') { $flagcompatible = 0 } else { $flagcompatible = 1 } break } } if ($flagcompatible -eq 1) { $compatibleCount += 1 } elseif ($flagcompatible -eq 0) { $mayNotcompatibleCount += 1 } elseif ($flagcompatible -eq 'null') { $unableUpgradeCount += 1 } } } if (-not $checkVersion) { $serverSource += '["{0}",{1},{2}],' -f $DCResourceOne.vcname, $compatibleCount, $mayNotCompatibleCount } else { $serverSource += '["{0}",{1},{2},{3}],' -f $DCResourceOne.vcname, $compatibleCount, $mayNotCompatibleCount, $unableUpgradeCount } } $serverSource += '];' $content += 'var serverSource = {0}' -f $serverSource $content += $hostModelCompatibleHead if (-not $checkVersion) { $colorsArray = 'colorsC', 'colorsM' } else { $colorsArray = 'colorsC', 'colorsM', 'colorsU' } foreach ($colors in $colorsArray) { $content += $hostModelCompatibleBody $content += "color:$colors}," } $content += $hostModelCompatibleRest #count IO Device compatibility by vCenter if (-not(checkVersion($Data))) { $ioSource = "[['series', 'Compatible', 'May Not Compatible',]," } else { $ioSource = "[['series', 'Compatible','May Not Compatible','No Upgrade Path',]," } foreach ($VCResource in $Data) { $compatibleCount = 0 $mayNotCompatibleCount = 0 $unableUpgradeCount = 0 $checkVersion = $VCResource.checkRelease foreach ($DCResourceOne in $VCResource.DCResource) { foreach ($HostResourceOne in $DCResourceOne.HostResource) { $flagcompatible = 0 foreach ($ComoenentResourceOne in $HostResourceOne.ComponentResource) { if ($ComoenentResourceOne.type -eq 'IO Device') { # if ($checkVersion) { # if (-not($ComoenentResourceOne.upgrade)) { # $flagcompatible = 'null' # } # } if ($ComoenentResourceOne.status -ne 'Compatible') { $flagcompatible = 0 } else { $flagcompatible = 1 } if ($flagcompatible -eq 1) { $compatibleCount += 1 } elseif ($flagcompatible -eq 0) { $mayNotCompatibleCount += 1 } elseif ($flagcompatible -eq 'null') { $unableUpgradeCount += 1 } } } } } if (-not $checkVersion) { $ioSource += '["{0}",{1},{2}],' -f $DCResourceOne.vcname, $compatibleCount, $mayNotCompatibleCount } else { $ioSource += '["{0}",{1},{2},{3}],' -f $DCResourceOne.vcname, $compatibleCount, $mayNotCompatibleCount, $unableUpgradeCount } } $ioSource += '];' $content += 'var ioSource = {0}' -f $ioSource $content += $ioCompatibleHead if (-not $checkVersion) { $colorsArray = 'colorsC', 'colorsM' } else { $colorsArray = 'colorsC', 'colorsM', 'colorsU' } foreach ($colors in $colorsArray) { $content += $ioCompatibleBody $content += "color:$colors}," } $content += $ioCompatibleRest $dataTime = Get-Date -Format 'yyyy-M-d_h-m' $vcName = vcName($Data) $filename = 'sumreport_' + $vcName + $dataTime + '.html' $filePath = $Dir + '\' + $filename # Out-put a html report $content |Out-File -FilePath $filePath -Encoding utf8| Out-Null info ("Report " + "'" + $filePath + "'" + " has been created!") } Function Generate_CsvReport($Data, $Dir) { info("Generating compatibility csv report") #define header $content = '' $content += "VC," $content += "DataCenter," $content += "Host," $content += "Type," $content += "Model Name," $content += "Vendor," if (-not(checkVersion($Data))) { $content += "Installed Release," } else { $content += "Checked Release," } $content += "Compatible Status," $content += "Hardware Detail," $content += "Comments," $content += 'VCG Link,' $content += "`n" #formate content foreach ($VCResource in $Data) { $checkVersion = $VCResource.checkRelease foreach ($DCResourceOne in $VCResource.DCResource) { foreach ($HostResourceOne in $DCResourceOne.HostResource) { $installVersion = $HostResourceOne.version foreach ($ComoenentResourceOne in $HostResourceOne.ComponentResource) { if ($DCResourceOne.vcname -ne 'null') { $content += "{0}," -f $DCResourceOne.vcname } else { $content += "{0}," -f '/' } #DataCenterDetail if ($DCResourceOne.dcname -ne 'null') { $content += "{0}," -f $DCResourceOne.dcname } else { $content += "{0}," -f '/' } #Host $content += "{0}," -f $HostResourceOne.hostname #Type $content += "{0}," -f $ComoenentResourceOne.type #Model Name $content += '"{0}",' -f $ComoenentResourceOne.model #Vendor $content += '"{0}",' -f $ComoenentResourceOne.vendor if (-not $checkVersion) { #Installed Release $content += '"{0}",' -f $installVersion } else { $content += '"{0}",' -f $checkVersion } #Status $content += '"{0}",' -f (formatStatus($ComoenentResourceOne.status)) #CompatibleHardware if ($ComoenentResourceOne.type -eq 'IO Device') { $CompatibleHardware = "'PCI ID:{0}, Driver:{1} {2}" -f $ComoenentResourceOne.pciid, $ComoenentResourceOne.Driver, $ComoenentResourceOne.DriverVersion } else { $CompatibleHardware = "'CPU: {0}(Feature:{1}) BIOS:{2}" -f $ComoenentResourceOne.cpumodel, $ComoenentResourceOne.cpufeatureid, $ComoenentResourceOne.biosversion } $content += '"{0}",' -f $CompatibleHardware #Comments if ($ComoenentResourceOne.Warnings.Count -gt 0) { $Comments = $ComoenentResourceOne.Warnings } else { $Comments ='N/A' } $content += '"{0}",' -f $Comments #VCG Link $VCGLink = '' foreach ($link in $ComoenentResourceOne.VcgLink) { $VCGLink += $link $VCGLink += ' ' } $content += '"{0}",' -f $VCGLink $content += "`n" } } } } #define filename and path $dataTime = Get-Date -Format 'yyyy-M-d_h-m' $vcName = vcName($Data) $filename = 'compreport_' + $vcName + $dataTime + '.csv' $filePath = $Dir + '\' + $filename #save csv report info ("Report " + "'" + $filePath + "'" + " has been created!") $content |Out-File -FilePath $filePath -Encoding utf8| Out-Null return $content } Function refactorData ($data) { $DCResource,$flag = refactorDC $data $data,$flag = refactorVC $DCResource return $data, $true } Function refactorDC($data) { $DCResource = @() $HostResource = @() $HR = @{} $DC = @{} $ReData = $data $HR.__type__ = $ReData[0].__type__ $HR.vcname = $ReData[0].vcname $HR.dcname = $ReData[0].dcname $HR.hostname = $ReData[0].hostname $HR.apitype = $ReData[0].apitype $HR.powerstatus = $ReData[0].powerstatus $HR.version = $ReData[0].version $HR.fullname = $ReData[0].fullname $HR.connectionstatus = $ReData[0].connectionstatus $HR.ComponentResource = $ReData[0].ComponentResource $HostResource += $HR # HostResource = [{'hostname':'10.110.126.170'}] $DC.dcname = $ReData[0].dcname #$DC={'dcname':'ha-datacenter'} $DC.vcname = $ReData[0].vcname $DC.HostResource = $HostResource #$DC={'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'}]} $DC.checkRelease = $ReData[0].checkRelease $DCResource += $DC #$DCResource = [{'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'},]}] $dcname = $ReData[0].dcname $vcname = $ReData[0].vcname $DcIndex = 0 for ($i = 1; $i -lt $ReData.Count; $i++) { $temp = $ReData[$i] $HR = @{} if ($temp.dcname -eq $dcname -and $temp.vcname -eq $vcname) { $HR.__type__ = $temp.__type__ $HR.vcname = $temp.vcname $HR.dcname = $temp.dcname $HR.hostname = $temp.hostname $HR.apitype = $temp.apitype $HR.powerstatus = $temp.powerstatus $HR.version = $temp.version $HR.fullname = $temp.fullname $HR.connectionstatus = $temp.connectionstatus $HR.ComponentResource = $temp.ComponentResource $DCResource[$DcIndex].HostResource += $HR } else { $DcIndex += 1 $DCResource += @{} #$DCResource = [{'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'},{'hostname':'10.110.126.171'}]},{}] $DCResource[$DcIndex].dcname = $temp.dcname # [{'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'},{'hostname':'10.110.126.171'}]},{'dcname':'hw-datacenter'}] $DCResource[$DcIndex].vcname = $temp.vcname $DCResource[$DcIndex].checkRelease = $temp.checkRelease $DCResource[$DcIndex].HostResource = @() # [{'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'},{'hostname':'10.110.126.171'}]},{'dcname':'hw-datacenter','HostResource':[]}] $HR = @{} $HR.__type__ = $temp.__type__ $HR.vcname = $temp.vcname $HR.dcname = $temp.dcname $HR.hostname = $temp.hostname $HR.apitype = $temp.apitype $HR.powerstatus = $temp.powerstatus $HR.version = $temp.version $HR.fullname = $temp.fullname $HR.connectionstatus = $temp.connectionstatus $HR.ComponentResource = $temp.ComponentResource $DCResource[$DcIndex].HostResource += $HR # [{'dcname':'ha-datacenter','HostResource':[{'hostname':'10.110.126.170'},{'hostname':'10.110.126.171'}]},{'dcname':'hw-datacenter','HostResource':[{'hostname':'10.110.126.173'}]}] $dcname = $temp.dcname $vcname = $temp.vcname } } return $DCResource,$true # return $DCResource } Function refactorVC ($data) { $VCResource = @() $DCResource = @() $VC = @{} $DCResource += $data[0] $VC.DCResource = $DCResource $VC.hostname = $data[0].vcName $VC.checkRelease = $data[0].checkRelease $VCResource += $VC $vcname = $data[0].vcname $VcIndex = 0 for ($i = 1 ; $i -lt $data.Count; $i++){ $temp = $data[$i] if ($vcname -eq $temp.vcname) { $VCResource[$VcIndex].DCResource += $temp } else { $VcIndex += 1 $DCResource = @() $VC = @{} $DCResource += $temp $VC.hostname = $temp.vcName $VC.DCResource = $DCResource $VC.checkRelease = $temp.checkRelease $VCResource += $VC $vcname = $temp.vcname } } return $VCResource,$true } Function vcName($Data) { $vcName = '' foreach ($VCResource in $Data) { $vcName += $VCResource.hostname $vcName += '_' } return $vcName } Function checkVersion($Data) { foreach ($VCResource in $Data) { $checkVersion = $VCResource.checkRelease return $checkVersion } } Function formatStatus($status) { if ($status -eq 'MayNotBeCompatible') { return 'May Not Be Compatible' } else { return $status } } Function formatHostCountGraphic($dataDict) { while ($dataDict.MoveNext()) { $items = $dataDict.Key if ($items -eq 'Compatible') { $colors = 'colorsC' } elseif ($items -eq 'May Not Compatible') { $colors = 'colorsM' } elseif ($items -eq 'Unable to upgrade') { $colors = 'colorsU' } $content += $hostCountBody $items = "'{0}'" -f $items $content += 'name: {0},' -f $items $content += 'data: {0},' -f $dataDict.Value $content += 'color: {0},' -f $colors $content += '},' } return $content } #Detail report $generalHead = @' ESXi Compatible Report '@ $generalBodyBase = @'

[WARNING] The compatible status may not be fully accurate, please validate it with the official VMware Compatibility Guide

'@ $generalBodyRest = @' '@ $generalFooter = @'
VC DataCenter Host Type Model Name VendorCompatible Status Hardware Detail Comments
'@ #Summary report $summaryHead = @' Summary Report
'@