Hyper-V BPA HTML report

 

Hello again and happy 2011. Coming back from holidays I’ve decided to contribute to the community with one useful Powershell script to parse Hyper-V BPA reports on HTML. You can run it with Powershell on Full or Server Core. Don’t forget to run Powershell as administrator and configure the Execution policy

Here is the code. Enjoy it

  
 Param ($BPAModelID, $OutputFileName, $ReportTitle)
 $HTMLFileName = $PWD.Path + "\Hyper-V_BPA_reportXML.html"
  
 Function Write-ScriptProgress ($Activity = "", $Status = "") {
     if ($Activity -ne $LastActivity) {
         if (-not $TroubleShootingModuleLoaded -and ($Activity -ne "")) {
             $Activity | Out-Host
         }
         if ($Activity -ne "") {
             Set-variable -Name "LastActivity" -Value $Activity -Scope "global"
         } else {
             $Activity = $LastActivity
         }    
     }
     if ($TroubleShootingModuleLoaded) {
             Write-DiagProgress -activity $Activity -status $Status
         
     } else {
         "    [" + (Get-Date) + "] " + $Status | Out-Host
     }
 }
  
 Function SaveToHTMLFile($SourceXMLDoc, $HTMLFileName){
     
     $XMLFilename = $Env:TEMP + "\" + [System.IO.Path]::GetFileNameWithoutExtension($HTMLFileName) + ".XML"
     $SourceXMLDoc.Save($XMLFilename)
     
     [xml] $XSLContent = ExtractEmbeddedXSL
  
     $XSLObject = New-Object System.Xml.Xsl.XslTransform
     $XSLObject.Load($XSLContent)
     $XSLObject.Transform($XMLFilename, $HTMLFilename)
     
     Remove-Item $XMLFilename
     "Output saved to $HTMLFilename"
 }
  
 Function AddXMLElement ([xml] $xmlDoc,
                         [string] $ElementName="Item", 
                         [string] $Value,
                         [string] $AttributeName="name", 
                         [string] $attributeValue,
                         [string] $xpath="/Root")
 {
     [System.Xml.XmlElement] $rootElement=$xmlDoc.SelectNodes($xpath).Item(0)
     if ($rootElement -ne $null) { 
         [System.Xml.XmlElement] $element = $xmlDoc.CreateElement($ElementName)
         if ($attributeValue.Length -ne 0) {$element.SetAttribute($AttributeName, $attributeValue)}
         if ($Value.lenght -ne 0) { 
             if ($PowerShellV2) {
                 $element.innerXML = $Value
             } else {
                 $element.set_InnerXml($Value)
             }
         }
         $x = $rootElement.AppendChild($element)
     } else {
         "Error. Path $xpath returned a null value. Current XML document: `n" + $xmlDoc.OuterXml
     }
 }
  
 Function ExtractEmbeddedXSL(){
     $PSScriptName = $myInvocation.ScriptName
     
     Get-Content $PSScriptName | ForEach-Object {
         if ($insideXSL) {
             if ($_ -eq "}") {$insideXSL = $true}
         }
         if ($insideXSL) {
             $XSLContent += $_.Substring(1).Replace("{CDATA{", ([char]91 + "CDATA" + [char]91)).Replace("}}>", ([char]93 + [char]93 + ">")) + "`r`n"
         }
         if ($_ -eq "Function EmbeddedXSL(){"){$insideXSL = $true}
     }
     return $XSLContent
 }
  
 #***********************************************
 #*  Starts here
 #***********************************************
 Import-Module BestPractices
 if ((Get-WmiObject -Class Win32_ComputerSystem).DomainRole -gt 1) { #Server
  
     if ((Get-Host).Name -ne "Default Host") {
         "Windows Troubleshooting Platform not loaded."
         $TroubleshootingModuleLoaded = $false
     } else {
         $TroubleshootingModuleLoaded = $true
     }
     
     Write-ScriptProgress -activity $ReportTitle -status "Starting Best Practices Analyzer"
     
     $PowerShellV2 = (((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine").PowerShellVersion).Substring(0,1) -ge 2)
     
     $Error.Clear()
     
     if ($Error.Count -eq 0) {
         $InstalledBPAs = Get-BPAModel
         $BPAModelID = "Microsoft/Windows/Hyper-V"
         if ((($InstalledBPAs | where-object {$_.Id -eq $BPAModelID}).Id) -ne $null) {
             
             Write-ScriptProgress -activity $ReportTitle -status "Running Best Practices Analyzer"    
             
             $BPAResults = Invoke-BpaModel $BPAModelID
         
             write $FileLocation
             
             if (($BPAResults | where-object {($_.ModelID -eq $BPAModelID) -and ($_.Success -eq $true)}) -ne $null) {
                 Write-ScriptProgress -activity $ReportTitle -status "Generating Output"    
                 $BPAXMLDoc = Get-BpaResult $BPAModelID | ConvertTo-XML
                 
                 if ($BPAXMLDoc -ne $null) {
                     AddXMLElement -xmlDoc $BPAXMLDoc -ElementName "Machine" -Value $Env:COMPUTERNAME -xpath "/Objects"
                     AddXMLElement -xmlDoc $BPAXMLDoc -ElementName "TimeField" -Value ($BPAResults[0].Detail).ScanTime -xpath "/Objects"
                     AddXMLElement -xmlDoc $BPAXMLDoc -ElementName "ModelId" -Value ($BPAResults[0].Detail).ModelId -xpath "/Objects"
                     AddXMLElement -xmlDoc $BPAXMLDoc -ElementName "ReportTitle" -Value $ReportTitle -xpath "/Objects"
                     AddXMLElement -xmlDoc $BPAXMLDoc -ElementName "OutputFileName" -Value $OutputFileName -xpath "/Objects"
                     
                     SaveToHTMLFile -HTMLFileName $HTMLFileName -SourceXMLDoc $BPAXMLDoc
                     
                     if ($TroubleshootingModuleLoaded) {
                         CollectFiles -filesToCollect $OutputFileName -fileDescription $ReportTitle -sectionDescription "Best Practices Analyzer reports"
                         if ($BPAXMLDoc.SelectNodes("(//Object[(Property[@Name=`'Severity`'] = `'Warning`') or (Property[@Name=`'Severity`'] = `'Error`')])").Count -ne 0) {
                             $BPAXMLFile = [System.IO.Path]::GetFullPath($PWD.Path + ("\..\BPAResults.XML"))
                             if (Test-Path $BPAXMLFile){
                                 [xml] $ExistingBPAXMLDoc = Get-Content $BPAXMLFile
                                 AddXMLElement -xmlDoc $ExistingBPAXMLDoc -xpath "/Root" -ElementName "BPAModel" -Value $BPAXMLDoc.SelectNodes("/Objects").Item(0).InnerXML
                                 $ExistingBPAXMLDoc.Save($BPAXMLFile)
                             } else {
                                 [xml] $BPAFileXMLDoc = "<Root/>"
                                 AddXMLElement  -xmlDoc $BPAFileXMLDoc -xpath "/Root" -ElementName "BPAModel" -Value $BPAXMLDoc.SelectNodes("/Objects").Item(0).InnerXML
                                 $BPAFileXMLDoc.Save($BPAXMLFile)
                             }
                             Update-DiagRootCause -id RC_BPAInfo -Detected $true
                         }
                     }
                     Write-ScriptProgress -activity $ReportTitle -status "Completed."
                 } else {
                     "Get-BpaResult did not return any result"
                 }
             }
         
         } else {
             $Msg = "ERROR: BPA Module $BPAModelID is not installed. Follow the list of installed BPAs: `r`n"
             foreach ($BPA in $InstalledBPAs) 
             {
                 $Msg += "   " + $BPA.Id + "`r`n"
             }
             $Msg | Write
             
         }
     } else {
         "ERROR: Unable to load BestPractices module"  | Write
     }
 }
  
 Function EmbeddedXSL(){
 #<?xml version="1.0"?>
 #<xsl:stylesheet xmlns:xsl="https://www.w3.org/1999/XSL/Transform" version="1.0">
 #<xsl:output method="html" />
 #<xsl:template match="/Objects">
 #<html dir="ltr" xmlns:v="urn:schemas-microsoft-com:vml" gpmc_reportInitialized="false">
 #<head>
 #<!-- Styles -->
 #  <style type="text/css">
 #    body    { background-color:#FFFFFF; border:1px solid #666666; color:#000000; font-size:68%; font-family:MS Shell Dlg; margin:0,0,10px,0; word-break:normal; word-wrap:break-word; }
 #
 #    table   { font-size:100%; table-layout:fixed; width:100%; }
 #
 #    td,th   { overflow:visible; text-align:left; vertical-align:top; white-space:normal; }
 #
 #    .title  { background:#FFFFFF; border:none; color:#333333; display:block; height:24px; margin:0px,0px,-1px,0px; padding-top:4px; position:relative; table-layout:fixed; width:100%; z-index:5; }
 #
 #    .he0False { background-color:#FEF7D6; border:1px solid #BBBBBB; color:#3333CC; cursor:hand; display:block; font-family:Verdana; font-size:110%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:0px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%;
 #    filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#FEF7D6',EndColorStr='white');}
 #
 #    .he0True { background-color:#D8D8D8; border:1px solid #BBBBBB; color:#3333CC; cursor:hand; display:block; font-family:Verdana; font-size:110%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:0px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%;
 #    filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#D8D8D8',EndColorStr='white');}
 #
 #    .he0_expanded   { background-color:#FEF7D6; border:1px solid #BBBBBB; color:#3333CC; cursor:hand; display:block; font-family:Verdana; font-size:110%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:0px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%;
 #    filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='#FEF7D6',EndColorStr='white');}
 #
 #    .hev    { background-color:#CCDFFF; border:1px solid #BBBBBB; color:#3333CC; display:block; font-family:Verdana; font-size:110%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:0px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%;
 #    filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr='white',EndColorStr='#CCDFFF');}
 #
 #    .he3_expanded { background-color:#C0D2DE; border:1px solid #BBBBBB; color:#000000; display:block; font-family:MS Shell Dlg; font-size:100%; height:2.25em; margin-bottom:-1px; font-weight:bold; margin-left:0px; margin-right:0px; padding-left:4px; padding-right:5em; padding-top:4px; position:relative; width:100%; }
 #
 #    .he4_expanded { background-color:#E9EFF3; border:1px solid #BBBBBB; color:#000000; display:block; font-family:MS Shell Dlg; font-size:100%; height:2.25em; margin-bottom:-1px; font-weight:bold; margin-left:0px; margin-right:0px; padding-left:4px; padding-right:5em; padding-top:4px; position:relative; width:100%; }
 #
 #    .he1    { background-color:#C0D2DE; border:1px solid #BBBBBB; color:#000000; cursor:hand; display:block; font-family:Segoe UI, Verdana; font-size:110%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:0px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%; }
 #
 #    .he2    { background-color:#C0D2DE; border:1px solid #BBBBBB; color:#000000; cursor:hand; display:block; font-family:MS Shell Dlg; font-size:100%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:10px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%; }
 #
 #    .he2b    { background-color:#C0D2DE; border:1px solid #BBBBBB; color:#000000; cursor:hand; display:block; font-family:MS Shell Dlg; font-size:100%; font-weight:bold; height:2.25em; margin-bottom:-1px; margin-left:10px; margin-right:0px; padding-left:8px; padding-right:5em; padding-top:4px; position:relative; width:100%; }
 #
 #    .he4i   { background-color:#F9F9F9; border:1px solid #BBBBBB; color:#000000; display:block; font-family:MS Shell Dlg; font-size:100%; margin-bottom:-1px; margin-left:15px; margin-right:0px; padding-bottom:5px; padding-left:12px; padding-top:4px; position:relative; width:100%; }
 #
 #    .he5i   { background-color:#E9EFF3; border:1px solid #BBBBBB; color:#000000; display:block; font-family:MS Shell Dlg; font-size:100%; margin-bottom:-1px; margin-left:8px; margin-right:0px; padding-bottom:5px; padding-left:12px; padding-top:4px; position:relative; width:100%; }
 #
 #    DIV .expando { color:#000000; text-decoration:none; display:block; font-family:MS Shell Dlg; font-size:100%; font-weight:normal; position:absolute; right:10px; text-decoration:underline; z-index: 0; }
 #
 #    .info4 TD, .info4 TH              { padding-right:10px; width:25%;}
 #
 #    .infoFirstCol                     { padding-right:10px; width:20%; }
 #    .infoSecondCol                     { padding-right:10px; width:80%; }
 #
 #    .lines0                           {background-color: #F5F5F5;}
 #    .lines1                           {background-color: #F9F9F9;}
 #
 #    .subtable, .subtable3             { border:1px solid #CCCCCC; margin-left:0px; background:#FFFFFF; margin-bottom:10px; }
 #
 #    .subtable TD, .subtable3 TD       { padding-left:10px; padding-right:5px; padding-top:3px; padding-bottom:3px; line-height:1.1em; width:10%; }
 #
 #    .subtable TH, .subtable3 TH       { border-bottom:1px solid #CCCCCC; font-weight:normal; padding-left:10px; line-height:1.6em;  }
 #
 #    .explainlink:hover      { color:#0000FF; text-decoration:underline; }
 #
 #    .filler { background:transparent; border:none; color:#FFFFFF; display:block; font:100% MS Shell Dlg; line-height:8px; margin-bottom:-1px; margin-left:43px; margin-right:0px; padding-top:4px; position:relative; }
 #
 #    .container { display:block; position:relative; }
 #
 #    .rsopheader { background-color:#A0BACB; border-bottom:1px solid black; color:#333333; font-family:MS Shell Dlg; font-size:130%; font-weight:bold; padding-bottom:5px; text-align:center;
 #    filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#FFFFFF',EndColorStr='#A0BACB')}
 #
 #    .rsopname { color:#333333; font-family:MS Shell Dlg; font-size:130%; font-weight:bold; padding-left:11px; }
 #
 #    #uri    { color:#333333; font-family:MS Shell Dlg; font-size:100%; padding-left:11px; }
 #
 #    #dtstamp{ color:#333333; font-family:MS Shell Dlg; font-size:100%; padding-left:11px; text-align:left; width:30%; }
 #
 #    #objshowhide { color:#000000; cursor:hand; font-family:MS Shell Dlg; font-size:100%; font-weight:bold; margin-right:0px; padding-right:10px; text-align:right; text-decoration:underline; z-index:2; word-wrap:normal; }
 #
 #    v\:* {behavior:url(#default#VML);}
 #
 #  </style>
 #<!-- Script 1 -->
 #
 #<script language="vbscript" type="text/vbscript">
 #<![CDATA[
 #<!--
 #'================================================================================
 #' String "strShowHide(0/1)"
 #' 0 = Hide all mode.
 #' 1 = Show all mode.
 #strShowHide = 1
 #
 #'Localized strings
 #strShow = "show"
 #strHide = "hide"
 #strShowAll = "show all"
 #strHideAll = "hide all"
 #strShown = "shown"
 #strHidden = "hidden"
 #strExpandoNumPixelsFromEdge = "10px"
 #
 #
 #Function IsSectionHeader(obj)
 #    IsSectionHeader = (obj.className = "he0_expanded") Or (obj.className = "he1_expanded") Or (obj.className = "he1") Or (obj.className = "he0True") Or (obj.className = "he0False") Or (obj.className = "he2") Or (obj.className = "he2g") Or (obj.className = "he2c") or (obj.className = "he3") Or (obj.className = "he4") Or (obj.className = "he4h") Or (obj.className = "he5") Or (obj.className = "he5h")  or (obj.className = "he4_expanded")
 #End Function
 #
 #
 #Function IsSectionExpandedByDefault(objHeader)
 #    IsSectionExpandedByDefault = (Right(objHeader.className, Len("_expanded")) = "_expanded")
 #End Function
 #
 #
 #' strState must be show | hide | toggle
 #Sub SetSectionState(objHeader, strState)
 #    ' Get the container object for the section.  It's the first one after the header obj.
 #
 #    i = objHeader.sourceIndex
 #    Set all = objHeader.parentElement.document.all
 #    While (all(i).className <> "container")
 #        i = i + 1
 #    Wend
 #
 #    Set objContainer = all(i)
 #
 #    If strState = "toggle" Then
 #        If objContainer.style.display = "none" Then
 #            SetSectionState objHeader, "show"
 #        Else
 #            SetSectionState objHeader, "hide"
 #        End If
 #
 #    Else
 #        Set objExpando = objHeader.children(1)
 #
 #        If strState = "show" Then
 #            objContainer.style.display = "block"
 #            rem objExpando.innerText = strHide
 #            rem objExpando.innerHTML = "<v:group id=" & chr(34) & "Show" & chr(34) & " class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:15px;height:15px;vertical-align:middle" & chr(34) & " coordsize=" & chr(34) & "100,100" & chr(34) & " alt=" & chr(34) & "Hide" & chr(34) & "><v:shape class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:100; height:100; z-index:0" & chr(34) & " fillcolor=" & chr(34) & "green" & chr(34) & " strokecolor=" & chr(34) & "green" & chr(34) & "><v:path v=" & chr(34) & "m 30,50 l 70,50 x e" & chr(34) & " /></v:shape></v:group>"
 #            objExpando.innerHTML =   "<v:group class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:15px;height:15px;vertical-align:middle" & chr(34) & " coordsize=" & chr(34) & "100,100" & chr(34) & " alt=" & chr(34) & "Show" & chr(34) & "><v:rect " & chr(34) & " stroked=" & chr(34) & "False" & chr(34) & "fillcolor=" & chr(34) & "#808080" & chr(34) & " style=" & chr(34) & "top:47;left:25;width:50;height:5" & chr(34) & " /></v:group>"
 #        ElseIf strState = "hide" Then
 #            objContainer.style.display = "none"
 #            rem objExpando.innerText = strShow
 #            rem objExpando.outerHTML = "<v:group class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:15px;height:15px;vertical-align:middle" & chr(34) & " coordsize=" & chr(34) & "100,100" & chr(34) & " alt=" & chr(34) & "Show" & chr(34) & "><v:shape class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:100; height:100; z-index:0" & chr(34) & " fillcolor=" & chr(34) & "black" & chr(34) & " strokecolor=" & chr(34) & "red" & chr(34) & "><v:path v=" & chr(34) & "m 99,1 l 1,1 50,50 x e" & chr(34) & " /></v:shape></v:group>"
 #            objExpando.innerHTML =   "<v:group class=" & chr(34) & "vmlimage" & chr(34) & " style=" & chr(34) & "width:15px;height:15px;vertical-align:middle" & chr(34) & " coordsize=" & chr(34) & "100,100" & chr(34) & " alt=" & chr(34) & "Show" & chr(34) & "><v:rect fillcolor=" & chr(34) & "#808080" & chr(34) & " stroked=" & chr(34) & "False" & chr(34) & " style=" & chr(34) & "top:47;left:25;width:50;height:5" & chr(34) & " /><v:rect fillcolor=" & chr(34) & "#808080" & chr(34) & " stroked=" & chr(34) & "False" & chr(34) & " style=" & chr(34) & "top:25;left:47;width:5;height:50" & chr(34) & " /></v:group>"
 #        End If
 #
 #    End If
 #End Sub
 #
 #
 #Sub ShowSection(objHeader)
 #    SetSectionState objHeader, "show"
 #End Sub
 #
 #
 #Sub HideSection(objHeader)
 #    SetSectionState objHeader, "hide"
 #End Sub
 #
 #
 #Sub ToggleSection(objHeader)
 #    SetSectionState objHeader, "toggle"
 #End Sub
 #
 #
 #'================================================================================
 #' When user clicks anywhere in the document body, determine if user is clicking
 #' on a header element.
 #'================================================================================
 #Function document_onclick()
 #    Set strsrc    = window.event.srcElement
 #
 #    While (strsrc.className = "sectionTitle" Or strsrc.className = "expando" Or strsrc.className = "vmlimage")
 #        Set strsrc = strsrc.parentElement
 #    Wend
 #
 #    ' Only handle clicks on headers.
 #    If Not IsSectionHeader(strsrc) Then Exit Function
 #
 #    ToggleSection strsrc
 #
 #    window.event.returnValue = False
 #End Function
 #
 #'================================================================================
 #' link at the top of the page to collapse/expand all collapsable elements
 #'================================================================================
 #Function objshowhide_onClick()
 #    Set objBody = document.body.all
 #    Select Case strShowHide
 #        Case 0
 #            strShowHide = 1
 #            objshowhide.innerText = strShowAll
 #            For Each obji In objBody
 #                If IsSectionHeader(obji) Then
 #                    HideSection obji
 #                End If
 #            Next
 #        Case 1
 #            strShowHide = 0
 #            objshowhide.innerText = strHideAll
 #            For Each obji In objBody
 #                If IsSectionHeader(obji) Then
 #                    ShowSection obji
 #                End If
 #            Next
 #    End Select
 #End Function
 #
 #'================================================================================
 #' onload collapse all except the first two levels of headers (he0, he1)
 #'================================================================================
 #Function window_onload()
 #    ' Only initialize once.  The UI may reinsert a report into the webbrowser control,
 #    ' firing onLoad multiple times.
 #    If UCase(document.documentElement.getAttribute("gpmc_reportInitialized")) <> "TRUE" Then
 #
 #        ' Set text direction
 #        Call fDetDir(UCase(document.dir))
 #
 #        ' Initialize sections to default expanded/collapsed state.
 #        Set objBody = document.body.all
 #
 #        For Each obji in objBody
 #            If IsSectionHeader(obji) Then
 #                If IsSectionExpandedByDefault(obji) Then
 #                    ShowSection obji
 #                Else
 #                    HideSection obji
 #                End If
 #            End If
 #        Next
 #
 #        objshowhide.innerText = strShowAll
 #
 #        document.documentElement.setAttribute "gpmc_reportInitialized", "true"
 #    End If
 #End Function
 #
 #
 #
 #
 #'================================================================================
 #' When direction (LTR/RTL) changes, change adjust for readability
 #'================================================================================
 #Function document_onPropertyChange()
 #    If window.event.propertyName = "dir" Then
 #        Call fDetDir(UCase(document.dir))
 #    End If
 #End Function
 #Function fDetDir(strDir)
 #    strDir = UCase(strDir)
 #    Select Case strDir
 #        Case "LTR"
 #            Set colRules = document.styleSheets(0).rules
 #            For i = 0 To colRules.length -1
 #                Set nug = colRules.item(i)
 #                strClass = nug.selectorText
 #                If nug.style.textAlign = "right" Then
 #                    nug.style.textAlign = "left"
 #                End If
 #                Select Case strClass
 #                    Case "DIV .expando"
 #                        nug.style.Left = ""
 #                        nug.style.right = strExpandoNumPixelsFromEdge
 #                    Case "#objshowhide"
 #                        nug.style.textAlign = "right"
 #                End Select
 #            Next
 #        Case "RTL"
 #            Set colRules = document.styleSheets(0).rules
 #            For i = 0 To colRules.length -1
 #                Set nug = colRules.item(i)
 #                strClass = nug.selectorText
 #                If nug.style.textAlign = "left" Then
 #                    nug.style.textAlign = "right"
 #                End If
 #                Select Case strClass
 #                    Case "DIV .expando"
 #                        nug.style.Left = strExpandoNumPixelsFromEdge
 #                        nug.style.right = ""
 #                    Case "#objshowhide"
 #                        nug.style.textAlign = "left"
 #                End Select
 #            Next
 #    End Select
 #End Function
 #
 #'================================================================================
 #'When printing reports, if a given section is expanded, let's says "shown" (instead of "hide" in the UI).
 #'================================================================================
 #Function window_onbeforeprint()
 #    For Each obji In document.all
 #        If obji.className = "expando" Then
 #            If obji.innerText = strHide Then obji.innerText = strShown
 #            If obji.innerText = strShow Then obji.innerText = strHidden
 #        End If
 #    Next
 #End Function
 #
 #'================================================================================
 #'If a section is collapsed, change to "hidden" in the printout (instead of "show").
 #'================================================================================
 #Function window_onafterprint()
 #    For Each obji In document.all
 #        If obji.className = "expando" Then
 #            If obji.innerText = strShown Then obji.innerText = strHide
 #            If obji.innerText = strHidden Then obji.innerText = strShow
 #        End If
 #    Next
 #End Function
 #
 #'================================================================================
 #' Adding keypress support for accessibility
 #'================================================================================
 #Function document_onKeyPress()
 #    If window.event.keyCode = "32" Or window.event.keyCode = "13" Or window.event.keyCode = "10" Then 'space bar (32) or carriage return (13) or line feed (10)
 #        If window.event.srcElement.className = "expando" Then Call document_onclick() : window.event.returnValue = false
 #        If window.event.srcElement.className = "sectionTitle" Then Call document_onclick() : window.event.returnValue = false
 #        If window.event.srcElement.id = "objshowhide" Then Call objshowhide_onClick() : window.event.returnValue = false
 #    End If
 #End Function
 #
 #-->
 #]]>
 #</script>
 #
 #<!-- Script 2 -->
 #
 #<script language="javascript"><![CDATA[
 #<!--
 #function getExplainWindowTitle()
 #{
 #        return document.getElementById("explainText_windowTitle").innerHTML;
 #}
 #
 #function getExplainWindowStyles()
 #{
 #        return document.getElementById("explainText_windowStyles").innerHTML;
 #}
 #
 #function getExplainWindowSettingPathLabel()
 #{
 #        return document.getElementById("explainText_settingPathLabel").innerHTML;
 #}
 #
 #function getExplainWindowExplainTextLabel()
 #{
 #        return document.getElementById("explainText_explainTextLabel").innerHTML;
 #}
 #
 #function getExplainWindowPrintButton()
 #{
 #        return document.getElementById("explainText_printButton").innerHTML;
 #}
 #
 #function getExplainWindowCloseButton()
 #{
 #        return document.getElementById("explainText_closeButton").innerHTML;
 #}
 #
 #function getNoExplainTextAvailable()
 #{
 #        return document.getElementById("explainText_noExplainTextAvailable").innerHTML;
 #}
 #
 #function getExplainWindowSupportedLabel()
 #{
 #        return document.getElementById("explainText_supportedLabel").innerHTML;
 #}
 #
 #function getNoSupportedTextAvailable()
 #{
 #        return document.getElementById("explainText_noSupportedTextAvailable").innerHTML;
 #}
 #
 #function showExplainText(srcElement)
 #{
 #    var strSettingName = srcElement.getAttribute("gpmc_settingName");
 #    var strSettingPath = srcElement.getAttribute("gpmc_settingPath");
 #    var strSettingDescription = srcElement.getAttribute("gpmc_settingDescription");
 #
 #    if (strSettingDescription == "")
 #    {
 #                strSettingDescription = getNoExplainTextAvailable();
 #    }
 #
 #    var strSupported = srcElement.getAttribute("gpmc_supported");
 #
 #    if (strSupported == "")
 #    {
 #        strSupported = getNoSupportedTextAvailable();
 #    }
 #
 #    var strHtml = "<html>\n";
 #    strHtml += "<head>\n";
 #    strHtml += "<title>" + getExplainWindowTitle() + "</title>\n";
 #    strHtml += "<style type='text/css'>\n" + getExplainWindowStyles() + "</style>\n";
 #    strHtml += "</head>\n";
 #    strHtml += "<body>\n";
 #    strHtml += "<div class='head'>" + strSettingName +"</div>\n";
 #    strHtml += "<div class='path'><b>" + getExplainWindowSettingPathLabel() + "</b><br/>" + strSettingPath +"</div>\n";
 #    strHtml += "<div class='path'><b>" + getExplainWindowSupportedLabel() + "</b><br/>" + strSupported +"</div>\n";
 #    strHtml += "<div class='info'>\n";
 #    strHtml += "<div class='hdr'>" + getExplainWindowExplainTextLabel() + "</div>\n";
 #    strHtml += "<div class='bdy'>" + strSettingDescription + "</div>\n";
 #    strHtml += "<div class='btn'>";
 #    strHtml += getExplainWindowPrintButton();
 #    strHtml += getExplainWindowCloseButton();
 #    strHtml += "</div></body></html>";
 #
 #    var strDiagArgs = "height=360px, width=630px, status=no, toolbar=no, scrollbars=yes, resizable=yes ";
 #    var expWin = window.open("", "expWin", strDiagArgs);
 #    expWin.document.write("");
 #    expWin.document.close();
 #    expWin.document.write(strHtml);
 #    expWin.document.close();
 #    expWin.focus();
 #
 #    //cancels navigation for IE.
 #    if(navigator.userAgent.indexOf("MSIE") > 0)
 #    {
 #        window.event.returnValue = false;
 #    }
 #
 #    return false;
 #}
 #-->
 #]]>
 #</script>
 #
 #</head>
 #
 #<body>
 #
 #    <table class="title" cellpadding="0" cellspacing="0">
 #    <tr><td colspan="2" class="rsopheader"><xsl:value-of select="ReportTitle"/></td></tr>
 #    <tr><td colspan="2" class="rsopname">Machine name: <xsl:value-of select="Machine"/></td></tr>
 #    <tr><td id="dtstamp">Data collected on: <xsl:value-of select="TimeField"/></td><td><div id="objshowhide" tabindex="0"></div></td></tr>
 #    </table>
 #    <div class="filler"></div>
 #
 #  <div class="hev">
 #    <span class="sectionTitle" tabindex="0">
 #      Messages
 #    </span>
 #  </div>
 #  <div class="filler"></div>
 #
 #  <xsl:for-each select="./Object">
 #    <xsl:sort order="ascending" select="./Property[@Name = 'Severity'] = 'Information'" data-type="text"/>
 #    <xsl:sort order="ascending" select="./Property[@Name = 'Severity'] = 'Warning'" data-type="text"/>
 #    <xsl:sort order="ascending" select="./Property[@Name = 'Severity'] = 'Error'" data-type="text"/>
 #    <xsl:variable name="excluded" select="./Property[@Name='Excluded']" />
 #    <div class="he0{$excluded}"><span class="sectionTitle" tabindex="0"> 
 #    <xsl:choose>
 #      <xsl:when test="./Property[@Name='Severity'] = 'Error'">
 #        <v:group class="vmlimage" style="width:15px;height:15px;vertical-align:middle" coordsize="100,100" title="Error">
 #          <v:oval class="vmlimage" style='width:100;height:100;z-index:0' fillcolor="red" strokecolor="red">
 #          </v:oval>
 #          <v:line class="vmlimage" style="z-index:1" from="25,25" to="75,75" strokecolor="white" strokeweight="3px">
 #          </v:line>
 #          <v:line class="vmlimage" style="z-index:2" from="75,25" to="25,75" strokecolor="white" strokeweight="3px">
 #          </v:line>
 #        </v:group>
 #        <xsl:text>&#160;</xsl:text>
 #      </xsl:when>
 #      <xsl:when test="./Property[@Name='Severity'] = 'Warning'">
 #        <v:group class="vmlimage" style="width:15px;height:15px;vertical-align:middle" coordsize="100,100" title="Warning">
 #          <v:shape class="vmlimage" style="width:100; height:100; z-index:0" fillcolor="yellow" strokecolor="black">
 #            <v:path v="m 50,0 l 0,99 99,99 x e" />
 #          </v:shape>
 #          <v:rect class="vmlimage" style="top:35; left:45; width:10; height:35; z-index:1" fillcolor="black" strokecolor="black">
 #          </v:rect>
 #          <v:rect class="vmlimage" style="top:85; left:45; width:10; height:5; z-index:1" fillcolor="black" strokecolor="black">
 #          </v:rect>
 #        </v:group>
 #        <xsl:text>&#160;</xsl:text>
 #      </xsl:when>
 #      <xsl:when test="./Property[@Name='Severity'] = 'Information'">
 #        <v:group id="Inf1" class="vmlimage" style="width:15px;height:15px;vertical-align:middle" coordsize="100,100" title="Information">
 #          <v:oval class="vmlimage" style="width:100;height:100;z-index:0" fillcolor="#336699" strokecolor="black" />
 #          <v:line class="vmlimage" style="z-index:1" from="50,15" to="50,25" strokecolor="white" strokeweight="3px" />
 #          <v:line class="vmlimage" style="z-index:2" from="50,35" to="50,80" strokecolor="white" strokeweight="3px" />
 #        </v:group>
 #        <xsl:text>&#160;</xsl:text>
 #      </xsl:when>
 #    </xsl:choose>
 #    <xsl:value-of select="./Property[@Name='Title']"/></span><a class="expando" href="#"></a></div>
 #    
 #        <div class="container"><div class="he4i"><table cellpadding="0" class="info4" >
 #        <tr><td></td><td></td><td></td><td></td><td></td></tr>
 #        <xsl:variable name="pos" select="position()" />
 #        <xsl:variable name="mod" select="($pos mod 2)" />
 #    <xsl:if test="./Property[@Name='Category']"><tr class="lines1"><td>Category</td><td colspan="4"><xsl:value-of select="./Property[@Name='Category']"/></td></tr></xsl:if>
 #    <xsl:if test="string-length(./Property[@Name='Problem']) > 0"><tr class="lines0"><td>Problem</td><td colspan="4"><b><xsl:value-of select="./Property[@Name='Problem']"/></b></td></tr></xsl:if>
 #    <xsl:if test="string-length(./Property[@Name='Impact']) > 0"><tr class="lines1"><td>Impact</td><td colspan="4"><xsl:value-of select="./Property[@Name='Impact']"/></td></tr></xsl:if>
 #    <xsl:if test="string-length(./Property[@Name='Resolution']) > 0"><tr class="lines0"><td>Resolution</td><td colspan="4"><xsl:value-of select="./Property[@Name='Resolution']"/></td></tr></xsl:if>
 #    <xsl:if test="string-length(./Property[@Name='Compliance']) > 0"><tr class="lines0"><td>Compliance</td><td colspan="4"><b><xsl:value-of select="./Property[@Name='Compliance']"/></b></td></tr></xsl:if>
 #    <xsl:if test="./Property[@Name='Help']"><tr class="lines1"><td>Additional Help</td><td colspan="4"><a href="{./Property[@Name='Help']}"><xsl:value-of select="./Property[@Name='Help']"/></a></td></tr></xsl:if>
 #    <xsl:if test="./Property[@Name='Excluded']"><tr class="lines0"><td>Excluded</td><td colspan="4"><xsl:value-of select="./Property[@Name='Excluded']"/></td></tr></xsl:if>
 #    <xsl:if test="./Property[@Name='RuleId']"><tr class="lines1"><td>Rule ID</td><td colspan="4"><xsl:value-of select="./Property[@Name='RuleId']"/></td></tr></xsl:if>
 #    <xsl:if test="./Property[@Name='ResultId']"><tr class="lines0"><td>Result ID</td><td colspan="4"><xsl:value-of select="./Property[@Name='ResultId']"/></td></tr></xsl:if>
 #        </table>
 #
 #    </div></div>
 #    <div class="filler"></div>
 #
 #    </xsl:for-each>
 #
 #</body>
 #</html>
 #</xsl:template>
 #</xsl:stylesheet>
 }

and this is an output sample

image