Formatting columns of HTML output depending on the

2019-09-11 00:41发布

问题:

I'm trying to apply conditional formatting to the output of a simple PowerShell function:

function Get-RamInfo {
    $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName
    $cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName
    $memcalc = ($cs.totalphysicalmemory / 1GB) - ($os.freephysicalmemory / 1MB)
    $calc = ($os.freephysicalmemory / 1MB) / ($cs.totalphysicalmemory / 1GB) * 100 -as [int]

    $props = [ordered]@{'Total RAM (GB)'="{0:N2}" -f ($cs.totalphysicalmemory / 1GB);
        'Total RAM In Use (GB)'="{0:N2}" -f ([math]::Round($memcalc,2));
        'Total RAM Available (GB)'="{0:N2}" -f ($os.freephysicalmemory / 1MB);
        'Total Ram Available (%)'= $calc;
    }

    $obj = New-Object -TypeName PSObject -Property $props

    Write-Output $obj
}

Here is the actual processing of the data and the logic applied:

$frag3 = Get-RamInfo -ComputerName $computername |
         ConvertTo-Html -As Table -Fragment -PreContent '<h2>Memory Info</h2>' |
         foreach {
             if ($_.'Total Ram Available (%)' -lt 20) {
                 $_ -replace "<tr>", '<tr class="warning">'
             } elseif ($_.'Total Ram Available (%)' -lt 10) {
                 $_ -replace "<tr>", '<tr class="danger">'
             } else{
                 $_
             }
         } | Out-String

I only want the if statement to reference the column labelled "Total RAM Available (%)" when applying the logic. E.g. If the value of the column labelled "Total RAM Available (%)" is less than 20, then execute the formatting, if it's less than 10, then execute different formatting, for anything else just output the string as normal without formatting.

Here is the HTML output I get:

<h2>Memory Info</h2>
<table>
<colgroup><col/><col/><col/><col/></colgroup>
<tr class="warning"><th>Total RAM (GB)</th><th>Total RAM In Use (GB)</th><th>Total RAM Available (GB)</th><th>Total Ram Available (%)</th></tr>
<tr class="warning"><td>31.96</td><td>7.44</td><td>24.52</td><td>77</td></tr>
</table>
  1. I don't think I'm referencing the single column correctly as it's applying the formatting to every table cell.
  2. It seems that the method I'm choosing to apply the logic is quite convoluted.

回答1:

The problem is that once you have converted object to HTML you wont be able to use if/else statemnet to its properties. I have edited your script a little. It should work now.

function Get-RamInfo {
    $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
    $cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
    $memcalc = ($cs.totalphysicalmemory / 1GB) - ($os.freephysicalmemory / 1MB)
    $calc = ($os.freephysicalmemory / 1MB) / ($cs.totalphysicalmemory / 1GB) * 100 -as [int]

    $props = [ordered]@{'Total RAM (GB)'="{0:N2}" -f ($cs.totalphysicalmemory / 1GB);
        'Total RAM In Use (GB)'="{0:N2}" -f ([math]::Round($memcalc,2));
        'Total RAM Available (GB)'="{0:N2}" -f ($os.freephysicalmemory / 1MB);
        'Total Ram Available (%)'= $calc;
    }

    $obj = New-Object -TypeName PSObject -Property $props

    Write-Output $obj
}

$raminfo = Get-RamInfo -ComputerName $computername  | 
                Select -Property *,@{
                                         name='class';e={
                                             if ($_.'Total Ram Available (%)' -lt 20){'<tr class="warning">'}
                                             elseif ($_.'Total Ram Available (%)' -lt 10){'<tr class="danger">'}
                                             else{'<tr>'}
                                         }
                                     }

$frag3 = $raminfo | Select 'Total RAM (GB)','Total RAM In Use (GB)','Total RAM Available (GB)','Total Ram Available (%)' | 
         ConvertTo-Html -As Table -Fragment -PreContent '<h2>Memory Info</h2>' |
            foreach { $_ -replace '<tr>',$($raminfo.class)
            } | Out-String


回答2:

At the point where your if statement sees the data you don't have the objects and properties that you're trying to check anymore. Use a regular expression and a switch statement instead to extract the numeric values from the HTML string:

$re = '<tr>(<td>[0-9.]+?</td><td>[0-9.]+?</td><td>([0-9.]+?)</td>)'

... | ForEach-Object {
  if ($_ -match $re) {
    switch ([int]$matches[2]) {
      {$_ -lt 20} { $_ -replace $re, '<tr class="warning">$1' }
      {$_ -lt 10} { $_ -replace $re, '<tr class="critical">$1' }
      default     { $_ }
    }
  }
} | ...