1

I have a script to display VM disk status for our vCenter. I would like to be able to highlight the rows in which "Free Space%" is less than 20. I can't find a way to isolate this variable and add a separate styling for it. My code is below:

Add-PSSnapin vmware.vimautomation.core
Connect-viserver "servername"

$editdate = Get-Date
$diskReport = "locationofreport.html"
$servers = get-vm | Sort name

#HTML Styling
$a = "<title>VM Disk Status</title>
<style>
 Body{background:#003366; height:100%; width:100%; padding:0;}
 Table{text-align:center; width:850px; padding-bottom:10px; border-width:1px; border-style:solid; border-color:black; margin: 0 auto; font-family: Georgia;}
 TH{border-width:1px;padding:5px; border-style:solid; border-color:black; background-color:grey; color:#FFDB4D;}
 TD{border-width:1px; padding:2px; border-style: solid; border-color:black; background-color:grey(this is the element I want to vary); color:white;}
 P{font-size:3em; text-align:center; font-family:Georgia; color:#FFDB4D}
</style>"
$b = "<p>VM Check Disk Page<br />Last Edited on $editdate</p>"

#Start Script
If (Test-Path $diskreport)
   {Remove-Item $diskreport}

$b | Add-Content $diskreport

ForEach ($vm in $servers) {
   ($vm.extensiondata.Guest.Disk |
      Select @{N="Name";E={$vm.name}},
      Diskpath,
      @{N="Capacity(MB)";E={[math]::Round($_.Capacity/ 1MB)}},
      @{N="Free Space(MB)";E={[math]::Round($_.FreeSpace/ 1MB)}},
      @{N="Free Space %";E={[math]::Round(((100*($_.FreeSpace))/($_.Capacity)),0)}}
   ) | ConvertTo-Html -head $a | add-content $diskreport
}

If anyone had any insight, that would be great.

2
  • I accomplished manually in my answer to this question. stackoverflow.com/questions/25809637/… basically building the output one row at a time. There might be more eloquent solutions available. Commented Oct 26, 2015 at 18:29
  • Thanks for your response Matt. I have been using your script as well as looking at some new CSS tags (apparently there is a th.after which allows for switches to be places in CSS). I use this as a learning experience as well so it's a slow process. Again, thanks for your time. Commented Oct 27, 2015 at 21:11

2 Answers 2

1

By manually outputting the table as advised by Matt, and using some CSS classes (please don't use inline styling (style="..." in the HTML tags), add classes in the CSS stylesheet, as you already have one), you can achieve this.

Also, check the changes I made to the CSS, it's a bit shorter (and more readable like this).

I have a similar script running at work that displays the content of a CSV file on a webpage, adding classes on the fly depending of the values.

CSS :

<style>

body {
  background: #003366;
  height: 100%;
  width: 100%;
  padding: 0;
}

table{
  text-align: center;
  width: 850px;
  padding-bottom: 10px;
  border: 1px solid black;
  margin: 0 auto; 
  font-family: Georgia;
}

th {
  border: 1px solid black;
  padding: 5px; 
  background-color: grey;
  color: #FFDB4D;
}

td {
  border: 1px solid black;
  padding: 2px;
  background-color: grey;
  color: white;
}

p {
  font-size: 3em;
  text-align: center;
  font-family: Georgia;
  color: #FFDB4D
}

tr.under-20 td {
  /* this targets cells in rows having class="under-20" */
  background-color: red;
  font-weight: bold;
}

</style>

With a for / foreach loop, you can output the table structure which is basically :

HTML :

<table> <!-- table start -->
  <tr> <!-- row start -->
    <th>First name</th> <!-- header cell -->
    <th>Last name</th> <!-- header cell -->
  </tr> <!-- row end -->
  <tr> <!-- row start -->
    <td>John</td> <!-- normal cell -->
    <td>Doe</td> <!-- normal cell -->
  </tr> <!-- row end -->
  <tr classs="under-20"> <!-- cells in this row will have a red background based on the stylesheet above -->
    <td>Jane</td>
    <td>Doe</td>
  </tr>
</table> <!-- table end -->

Example of PS code to generate the table (feel free to ask if you don't get it) :

$title = "page title goes here"

$stylesheet = "/* CSS goes here */

            body {
                font-family: Arial, sans-serif
            }

            th {
                background-color: grey;
            }

            tr.under-20 td {
                background-color: red;
                color: white;
            }"

$html = "<html>
    <head>
        <title>$title</title>
        <style>`n`
            $stylesheet`n`
        </style>
    </head>
    <body>"

foreach ($vm in $servers) {
    $html += "`n`t`t<table>`
        `n`t`t`t<tr>`
            `n`t`t`t`t<th>Name</th>`
            `n`t`t`t`t<th>Path</th>`
            `n`t`t`t`t<th>Capacity</th>`
            `n`t`t`t`t<th>Free space (MB)</th>`
            `n`t`t`t`t<th>Free space (%)</th>`
        `n`t`t`t</tr>"

    foreach($disk in $vm.extensiondata.Guest.Disk) {
        $name = $vm.name
        $diskpath = $disk.Diskpath
        $capacity = [math]::Round($disk.Capacity/ 1MB)
        $freeSpace = [math]::Round($disk.FreeSpace/ 1MB)
        $freePercent = [math]::Round(((100 * $disk.FreeSpace) / $disk.Capacity), 0)

        if($freePercent -le 20) {
            $rowclass = "under-20"
        } else {
            $rowclass = ""
        }

        $html += "`n`t`t`t<tr class=`"$rowclass`">`
            `n`t`t`t`t<td>$name</td>`
            `n`t`t`t`t<td>$diskpath</td>`
            `n`t`t`t`t<td>$capacity</td>`
            `n`t`t`t`t<td>$freeSpace</td>`
            `n`t`t`t`t<td>$freePercent</td>`
        `n`t`t`t</tr>"
    }
    $html += "`n`t`t</table>"
}

$html += "`n`t</body>`n</html>"

$html | Out-File "diskreport.html"

Escaped tabs and newlines provide code indentation, trailing backticks in the strings are intended.

Sign up to request clarification or add additional context in comments.

6 Comments

I have been meaning to redo my answer on that other question because of lack of css.
As your (quality) code may be copied and pasted a lot, you should show good practises, yes ^^
I have enough answers that I forget about the old ones.... until I have to look them up again.
I appreciate your response, and yes this CSS approach would work IF I can dynamically class the data being output by the PowerShell script. My problem wasn't organizing the styling, it was how to identify the row value being output as -lt 20 and then altering the class of that <tr>.
Did you try to build the html table yourself ? I'll try to provide some PS code to help you
|
0

Found Set-CellColor function at

https://community.spiceworks.com/topic/843831-convert-html-background-cell-color-based-on-condition

But it seemed to be broke. Fixed the per-cell functionality but have not tested the -ROW switch

Function Set-CellColor {
<#
.SYNOPSIS
    Function that allows you to set individual cell colors in an HTML table
.DESCRIPTION
    To be used inconjunction with ConvertTo-HTML this simple function allows you
    to set particular colors for cells in an HTML table.  You provide the criteria
    the script uses to make the determination if a cell should be a particular 
    color (property -gt 5, property -like "*Apple*", etc).

    You can add the function to your scripts, dot source it to load into your current
    PowerShell session or add it to your $Profile so it is always available.

    To dot source:
        .".\Set-CellColor.ps1"
.PARAMETER Property
    Property, or column that you will be keying on.  
.PARAMETER Color
    Name or 6-digit hex value of the color you want the cell to be
.PARAMETER InputObject
    HTML you want the script to process.  This can be entered directly into the
    parameter or piped to the function.
.PARAMETER Filter
    Specifies a query to determine if a cell should have its color changed.  $true
    results will make the color change while $false result will return nothing.

    Syntax
    <Property Name> <Operator> <Value>

    <Property Name>::= the same as $Property.  This must match exactly
    <Operator>::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-like" | "-notlike" 
        <JoinOperator> ::= "-and" | "-or"
        <NotOperator> ::= "-not"

    The script first attempts to convert the cell to a number, and if it fails it will
    cast it as a string.  So 40 will be a number and you can use -lt, -gt, etc.  But 40%
    would be cast as a string so you could only use -eq, -ne, -like, etc.  
.PARAMETER Row
    Instructs the script to change the entire row to the specified color instead of the individual cell.
.INPUTS
    HTML with table
.OUTPUTS
    HTML
.EXAMPLE
    get-process | convertto-html | set-cellcolor -Propety cpu -Color red -Filter "cpu -gt 1000" | out-file c:\test\get-process.html

    Assuming Set-CellColor has been dot sourced, run Get-Process and convert to HTML.  
    Then change the CPU cell to red only if the CPU field is greater than 1000.
.EXAMPLE
    get-process | convertto-html | set-cellcolor cpu red -filter "cpu -gt 1000 -and cpu -lt 2000" | out-file c:\test\get-process.html

    Same as Example 1, but now we will only turn a cell red if CPU is greater than 100 
    but less than 2000.
.EXAMPLE
    $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1"
    PS C:\> $HTML = $HTML | Set-CellColor Server green -Filter "server -eq 'dc2'"
    PS C:\> $HTML | Set-CellColor Path Yellow -Filter "Path -like ""*memory*""" | Out-File c:\Test\colortest.html

    Takes a collection of objects in $Data, sorts on the property Server and converts to HTML.  From there 
    we set the "CookedValue" property to red if it's greater then 1.  We then send the HTML through Set-CellColor
    again, this time setting the Server cell to green if it's "dc2".  One more time through Set-CellColor
    turns the Path cell to Yellow if it contains the word "memory" in it.

.EXAMPLE
    $HTML = $Data | sort server | ConvertTo-html -head $header | Set-CellColor cookedvalue red -Filter "cookedvalue -gt 1" -Row

    Now, if the cookedvalue property is greater than 1 the function will highlight the entire row red.

.NOTES
    Author:             Martin Pugh
    Twitter:            @thesurlyadm1n
    Spiceworks:         Martin9700
    Blog:               www.thesurlyadmin.com

    Changelog:
        1.6             Fixed missing Style=`" and other mising double quotes or un-escaped, -ROW switch not tested
        1.5             Added ability to set row color with -Row switch instead of the individual cell
        1.03            Added error message in case the $Property field cannot be found in the table header
        1.02            Added some additional text to help.  Added some error trapping around $Filter creation.
        1.01            Added verbose output
        1.0             Initial Release
.LINK
    http://community.spiceworks.com/scripts/show/2450-change-cell-color-in-html-table-with-powershell-set-cellcolor
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,Position=0)]
        [string]$Property,
        [Parameter(Mandatory=$True,Position=1)]
        [string]$Color,
        [Parameter(Mandatory=$True,ValueFromPipeline)]
        [Object[]]$InputObject,
        [Parameter(Mandatory=$True)]
        [string]$Filter,
        [Parameter(Mandatory=$False)]
        [switch]$Row
    )

    Begin {
        Write-Verbose "$(Get-Date): Function Set-CellColor begins"
        If ($Filter) {
           If ($Filter.ToUpper().IndexOf($Property.ToUpper()) -ge 0) {
               $Filter = $Filter.ToUpper().Replace($Property.ToUpper(),"`$Value")
                Try {
                    [scriptblock]$Filter = [scriptblock]::Create($Filter)
                } Catch {
                    [string]$ErrorMessage = "$($_.Exception.Message) $($_.ScriptStackTrace) $($_.Exception.InnerException)"
                    Write-Warning "$(Get-Date): ""$Filter"" caused an error
                    `r`n $ErrorMessage" 
                    Return
                }
            } Else {
                Write-Warning "Could not locate $Property in the Filter, which is required.  Filter: $Filter"
                Return
            }
        }
    }

    Process {
        ForEach ($Line in $InputObject) {
            If ($Line.IndexOf("<tr><th") -ge 0)
            {   Write-Verbose "$(Get-Date): Processing headers..."
                $Search = $Line | Select-String -Pattern '<th ?[a-z\-:;"=]*>(.*?)<\/th>' -AllMatches
                $Index = 0
                ForEach ($Match in $Search.Matches) {
                    If ($Match.Groups[1].Value -eq $Property) {   Break  }
                    $Index ++
                }
                If ($Index -eq $Search.Matches.Count) {
                    Write-Warning "$(Get-Date): Unable to locate property: $Property in table header"
                    Return
                }
                Write-Verbose "$(Get-Date): $Property column found at index: $Index"
            }
            If ($Line -match "<tr( background-color:.+?"")?><td") {
                $Search = $Line | Select-String -Pattern '<td ?[a-z\-:;"=]*>(.*?)<\/td>' -AllMatches
                $Value = $Search.Matches[$Index].Groups[1].Value -as [double]
                If (-not $Value) {
                    $Value = $Search.Matches[$Index].Groups[1].Value
                }
                If (Invoke-Command $Filter) {
                    If ($Row) {
                        Write-Verbose "$(Get-Date): Criteria met!  Changing row to $Color..."
                        If ($Line -match "<tr background-color:(.+?)"">") {
                            $Line = $Line -replace "<tr Style=`"background-color:$($Matches[1])`"","<tr Style=`"background-color:$Color`""
                        }
                        Else {
                            $Line = $Line.Replace("<tr>","<tr Style=`"background-color:$Color`">")
                        }
                    }
                    Else {
                        Write-Verbose "$(Get-Date): Criteria met!  Changing cell to $Color..."
                        $Line = $Line.Replace($Search.Matches[$Index].Value,"<td Style=`"background-color:$Color`">$Value</td>")
                    }
                }
            } Else { 
#               Write-Host "no Match" 
            }
            Write-Output $Line
        }
    }

    End {
        Write-Verbose "$(Get-Date): Function Set-CellColor completed"
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.