JavaScript problem with EnhancedHTML module

I’ve created a HTML report using the EnhancedHTML module from February 2013 version of “Creating HTML Reports in PowerShell” book by Don. The HTML is generated, but when I load the page in a browser, (Chrome or IE), I get a DataTables warning for each table in the report:

“DataTables warning: Attempted to initialise DataTables on a node which is not a table: DIV”

Unfortunately, that’s all I get… No line numbers, etc. When I load it in FF with Firebug, I just a “ReferenceError: $ is not defined” error in the Firebug console.

Any ideas? What other information would be useful for figuring this out?

Here’s a sample of the rendered HTML and javascript, (scrubbed):

<script type="text/javascript" src="F:\Storage\Scripts\Windows\Modules\jquery.js"></script>
<script type="text/javascript" src="F:\Storage\Scripts\Windows\Modules\jquerydatatable.js"></script>
<script type="text/javascript">$(document).ready(function () {
$('#divSC').dataTable();
$('#divSCCM').dataTable();
$('#divSEP').dataTable();
$('#divSEPOld').dataTable();
$('#divSCEP').dataTable();
$('#divNoAV').dataTable();
$('#divProb').dataTable();
} );</script>
</head><body>
<h1>System Report for </h1>
<span class="sectionheader" onclick="$('#divSC').toggle(500);"><h2>♦ Special Circumstances</h2></span>

<div id="divSC" style="display:none;">
<table class="grid" id="tableSC">
<thead><tr><th>ComputerName</th><th>LastVerifiedDate</th><th>Notes</th></tr></thead><tbody>
<tr class="even"><td>Server1</td><td>20130208</td><td>test note1</td></tr>
<tr class="odd"><td>Server2</td><td>20130208</td><td>test note2</td></tr>
<tr class="even"><td>Server3</td><td>20130208</td><td>test note3</td></tr>
<tr class="odd"><td>Server4</td><td>20130208</td><td>test note4</td></tr>
<tr class="even"><td>Server5</td><td>20130208</td><td>test note5</td></tr>
<tr class="odd"><td>Server6</td><td>20130208</td><td>test note6</td></tr>
</tbody></table></div>

I’d need to see your PowerShell code. When you generate the final HTML, you’re giving it “divSC” as the thing to make dynamic, but it needs “tableSC,” which is the ID of the actual table.

E.g., you’re giving it the DIV, not the TABLE, as the error indicates.

You were absolutely correct… Simple problem that I was just overlooking.
Relevant code:

$params = @{'As'='Table';
                'PreContent'='<h2>♦ Special Circumstances</h2>';
                'TableCssID'='tableSC';
                'DivCssID'='divSC';
                'EvenRowCssClass'='even';
                'OddRowCssClass'='odd';
                'MakeHiddenSection'=$true;
                'TableCssClass'='grid'}
	if ($AVReport.SpecialCircumstancesList -ne $null) {
    	$html_sc = 	$AVReport.SpecialCircumstancesList | ConvertTo-EnhancedHTMLFragment @params | Out-String
	}
	else {
		$html_sc = 	"" | ConvertTo-EnhancedHTMLFragment @params | Out-String
	}
	$CSSIDs += "divSC"
	$HTMLFrags += $html_sc
	Write-Host "html_sc: $html_sc"

...

    $params = @{'CssStyleSheet'=$style;
                'Title'="System Report for $computer";
                'PreContent'="<h1>System Report for $computer</h1>";
                'CssIdsToMakeDataTables'=$CSSIDs;
                'HTMLFragments'=$HTMLFrags;
                'jQueryDataTableUri'='F:\Storage\Scripts\Windows\Modules\jquerydatatable.js';
                'jQueryUri'='F:\Storage\Scripts\Windows\Modules\jquery.js'}
    ConvertTo-EnhancedHTML @params |
    Out-File -FilePath $filepath

As you can see, I was adding “divSC” to my CSSIDs arrary instead of “tableSC”. I corrected that on all of my sections, and that error went away. I’m seeing some weird stuff with my even/odd row styles, but I’ll dig into that next.

Thanks, Don! I beat my head against this for a couple hours yesterday, and it was just that simple!

All right, Don, help me out on this one…

HTML looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<style>
	body {
	    color:#333333;
	    font-family:Calibri,Tahoma;
	    font-size: 10pt;
	}
	h1 {
	    text-align:center;
	}
	h2 {
	    border-top:1px solid #666666;
	}

	th {
	    font-weight:bold;
	    color:#eeeeee;
	    background-color:#333333;
	    cursor:pointer;
	}
	.odd  { background-color:#ffffff; }
	.even { background-color:#dddddd; }
	.paginate_enabled_next, .paginate_enabled_previous {
	    cursor:pointer; 
	    border:1px solid #222222; 
	    background-color:#dddddd; 
	    padding:2px; 
	    margin:4px;
	    border-radius:2px;
	}
	.paginate_disabled_previous, .paginate_disabled_next {
	    color:#666666; 
	    cursor:pointer;
	    background-color:#dddddd; 
	    padding:2px; 
	    margin:4px;
	    border-radius:2px;
	}
	.dataTables_info { margin-bottom:4px; }
	.sectionheader { cursor:pointer; }
	.sectionheader:hover { color:red; }
	.grid { width:100% }
	</style>

<title>System Report for </title>
<script type="text/javascript" src="F:\Storage\Scripts\Windows\Modules\jquery.js"></script>
<script type="text/javascript" src="F:\Storage\Scripts\Windows\Modules\jquerydatatable.js"></script>
<script type="text/javascript">$(document).ready(function () {
$('#tableNoAV').dataTable();
} );</script>
</head><body>
<h1>System Report for </h1>
<span class="sectionheader" onclick="$('#divNoAV').toggle(500);"><h2>♦ No Antivirus List</h2></span>

<div id="divNoAV" style="display:none;">
<table class="grid" id="tableNoAV">
<thead><tr><th>ComputerName</th></tr></thead><tbody>
<tr class="even"><td>ADM021234</td></tr>
<tr class="odd"><td>MEDAUTOT1</td></tr>
<tr class="even"><td>PGPWS</td></tr>
<tr class="odd"><td>SOD701221</td></tr>
<tr class="even"><td>SOD701224</td></tr>
<tr class="odd"><td>SOD701334</td></tr>
<tr class="even"><td>SOD701351</td></tr>
<tr class="odd"><td>SOD701354</td></tr>
<tr class="even"><td>SOD701357</td></tr>
</tbody></table></div>


<table>
</table>
</body></html>

But page looks like this (problem with even/odd rows):

Code that generated HTML:

#========================================================================
# Created with: SAPIEN Technologies, Inc., PowerShell Studio 2012 v3.1.22
# Created on:   9/5/2013 9:31 AM
# Created by:   cmdowning
# Organization: BCBSMS
# Filename:     
#========================================================================

Import-Module EnhancedHTML

function Create-HTMLReport {
	[CmdletBinding()]
	param (
		[Parameter(ValueFromPipeline=$true,Mandatory=$true)]$AVReport,
		[Parameter(ValueFromPipeline=$false,Mandatory=$true)]$Path
	)
	
	$style = @"
	<style>
	body {
	    color:#333333;
	    font-family:Calibri,Tahoma;
	    font-size: 10pt;
	}
	h1 {
	    text-align:center;
	}
	h2 {
	    border-top:1px solid #666666;
	}

	th {
	    font-weight:bold;
	    color:#eeeeee;
	    background-color:#333333;
	    cursor:pointer;
	}
	.odd  { background-color:#ffffff; }
	.even { background-color:#dddddd; }
	.paginate_enabled_next, .paginate_enabled_previous {
	    cursor:pointer; 
	    border:1px solid #222222; 
	    background-color:#dddddd; 
	    padding:2px; 
	    margin:4px;
	    border-radius:2px;
	}
	.paginate_disabled_previous, .paginate_disabled_next {
	    color:#666666; 
	    cursor:pointer;
	    background-color:#dddddd; 
	    padding:2px; 
	    margin:4px;
	    border-radius:2px;
	}
	.dataTables_info { margin-bottom:4px; }
	.sectionheader { cursor:pointer; }
	.sectionheader:hover { color:red; }
	.grid { width:100% }
	</style>
"@
	
	$CSSIDs = @()
	$HTMLFrags = @()
	$filepath = Join-Path -Path $Path -ChildPath "AVReport2.html"


	$params = @{'As'='Table';
                'PreContent'='<h2>♦ No Antivirus List</h2>';
                'TableCssID'='tableNoAV';
                'DivCssID'='divNoAV';
                'EvenRowCssClass'='even';
                'OddRowCssClass'='odd';
                'MakeHiddenSection'=$true;
                'TableCssClass'='grid'}
	if ($AVReport.NoAVList -ne $null) {
    	$html_noav = $AVReport.NoAVList | ConvertTo-EnhancedHTMLFragment @params | Out-String
	}
	else {
		$html_noav = "" | ConvertTo-EnhancedHTMLFragment @params | Out-String
	}
	$CSSIDs += "tableNoAV"
	$HTMLFrags += $html_noav

    $params = @{'CssStyleSheet'=$style;
                'Title'="System Report for $computer";
                'PreContent'="<h1>System Report for $computer</h1>";
                'CssIdsToMakeDataTables'=$CSSIDs;
                'HTMLFragments'=$HTMLFrags;
                'jQueryDataTableUri'='F:\Storage\Scripts\Windows\Modules\jquerydatatable.js';
                'jQueryUri'='F:\Storage\Scripts\Windows\Modules\jquery.js'}
    ConvertTo-EnhancedHTML @params |
    Out-File -FilePath $filepath
}

Create-HTMLReport -AVReport $testAVReport -Path "C:\Scripts\AVReport\" -Verbose

Well, we know the module works because we can see the CSS style being applied in the final HTML. From there, it’s up to the browser to render the HTML. Have you tried this in a different browser? I copied this into a static HTML file and it’s working fine in Safari.

Yeah, the HTML looks fine… And yes, I see the same results in Chrome and IE. Still can’t get Firefox to run the javascript. Even copying/pasting into a static html file gives me the same results. Chrome and Safari on a Mac do the same thing.

I’m pretty confident the module is working, but I was curious if anyone else had seen this kind of behavior.

So, when I tested, I removed the SCRIPT tags. It’s possible the browsers aren’t liking loading those from a local path like that. You might try that as a troubleshooting step. In FF and Safari, and in IE with Dev Tools on, you can also right-click one of those rows and select “Inspect Element.” It’s a way to se where the styling is being applied from. Takes some getting used to (and not something I can teach well), but I’ve used it a lot.

Right. Forgot to mention that I had done that in Chrome, and forgot what the results looked like. For whatever reason, starting with row 3, it has both classes listed for <tr>

<tr class=“even odd”><td class=" sorting_1">PGPWS</td></tr>
<tr class=“odd even”><td class=" sorting_1">SOD701221</td></tr>

Now I remember why I didn’t do much web programming…

Well, that’s why the formatting is whack. But I’m not sure what would make the module do that. You’d have to troubleshoot the bit where it walks the table and applies the class. It’s almost like it’s being fed to it twice or something.

So just to add to the fun…

  • if I remove the "'EvenRowCssClass'='even';" and "'OddRowCssClass'='odd';" lines from the $params hash table assignment and re-create the html, I get table rows with no classes assigned, but the even and odd rows are rendered differently, (i.e. even rows are grey, odd rows are white).
  • If I rename the .odd and .even classes in the stylesheet to .odd2 and .even2, for example, and re-create the html, I get table rows with no classes assigned, and the even and odd rows are NOT rendered differently, (i.e. all rows are white).
  • If I leave the classes renamed as .odd2 and .even2, change the colors to blue and pink, respectively, and then add the EvenRowCssClass and OddRowCssClass lines back to the hash table using .odd2 and .even2 class names, it works as expected. (I get odd lines that are blue and even ones that are pink)

I got to doing a little digging into jquerydatatable.js and then on the DataTables website and found that DataTables automagically uses the .odd and .even classes to style the rows. (See Striping on http://datatables.net/styling/custom_classes)

So now it at least makes sense! I have no idea why your example worked when you wrote the book and didn’t work this time, but at least I know why. If you want to use the same even and odd row styles for all DataTables on a page, then you can use the .odd and .even classes and there is no need to use the OddRowCssClass and EvenRowCssClass params for the ConvertTo-EnhancedHTMLFragment function. If however you are going to use different styles for different DataTables on the same page, make sure that you don’t have any classes named .odd and .even and use the OddRowCssClass and EvenRowCssClass params.

And I don’t guess I ever mentioned it, but I really like the module and the ebook! This is my first time to use it, (obviously), and it’s so much easier to use the module you created than to try and hack out the HTML myself. Also, I wouldn’t have put enough effort into it to have the pretty DataTables and javascript that your module provides! Thanks very much!

So, I should point out that the dynamic datatable thing does its own coloring. That might be what you’re running into. And I think it might use class names odd/even to do so.

Yeah… you were about 12 mins too late on that pick up… :wink:

FYI, I found a little bug in the EnhancedHTML module. Just a couple of minor tweaks to fix it, and it may have broken something else…

In some further testing, I found that the highlighting didn’t work if you had a list, (‘AS’=‘list’), before a table, (‘As’=‘table’). When I looked at the rendered HTML for the list, I noticed that the TD tags for the $value property were weird. No cell classes were specified, but the TD tags were getting class attributes with a value of "class=“list”. That was putting an extra pair of quotes on the first line, and that messed up the rest of the html. Also, there was no <tbody> tag for the list, and there was no <thead> row for the list.

<div id="divSummary" style="display:none;">
<table class="list" id="tableSummary">
<tr><td>AllADMachines :</td><td class="class="list"">500</td></tr>
... clip...
</tbody></table></div>

Here’s the modified code in the ConvertTo-EnhancedHTMLFragment function:

#CMD - had to add table header with 2 columns to get even/odd row css to work
			if ($As -eq 'list') {
				Write-Output "<tr><th></th><th></th></tr><tbody>"
			}
            foreach ($prop in $properties) {
                Write-Verbose "Processing property"
                $name = $null
                $value = $null
                $cell_css = ''
                if ($prop -is [string]) {
                    Write-Verbose "Property $prop"
                    $name = $Prop
                    $value = $object.($prop)
                } elseif ($prop -is [hashtable]) {
                    Write-Verbose "Property hashtable"
                    if ($prop.ContainsKey('cssclass')) { $cell_css = $Object | ForEach $prop['cssclass'] }
                    if ($prop.ContainsKey('css')) { $cell_css = $Object | ForEach $prop['css'] }
                    if ($prop.ContainsKey('n')) { $name = $prop['n'] }
                    if ($prop.ContainsKey('name')) { $name = $prop['name'] }
                    if ($prop.ContainsKey('label')) { $name = $prop['label'] }
                    if ($prop.ContainsKey('l')) { $name = $prop['l'] }
                    if ($prop.ContainsKey('e')) { $value = $Object | ForEach $prop['e'] }
                    if ($prop.ContainsKey('expression')) { $value = $tObject | ForEach $prop['expression'] }
                    if ($name -eq $null -or $value -eq $null) {
                        Write-Error "Hashtable missing Name and/or Expression key"
                    }
                } else {
                    Write-Warning "Unhandled property $prop"
                }
                if ($As -eq 'table') {
                    Write-Verbose "Adding $name to header and $value to row"
                    $headerrow += "<th>$name</th>"
                    $datarow += "<td$(if ($cell_css -ne '') { ' class="'+$cell_css+'"' })>$value</td>"
                } else {
                    $wrote_first_line = $true
                    $headerrow = ""
					#CMD - using $css was causing some weird quotation mark results in class tags
                    #$datarow = "<td$(if ($cell_css -ne '') { ' class="'+$cell_css+'"' })>$name :</td><td$(if ($css -ne '') { ' class="'+$css+'"' })>$value</td>"
					$datarow = "<td$(if ($cell_css -ne '') { ' class="'+$cell_css+'"' })>$name :</td><td$(if ($cell_css -ne '') { ' class="'+$cell_css+'"' })>$value</td>"
                    Write-Output "<tr$(if ($row_css -ne '') { ' class="'+$row_css+'"' })>$datarow</tr>"
                }
            }

And the new HTML:

<div id="divSummary" style="display:none;">
<table class="list" id="tableSummary">
<thead><tr><th></th><th></th></tr></thead><tbody>
<tr><td>AllADMachines :</td><td>500</td></tr>
... clip...
</tbody></table></div>

I know that the module was a teaching tool and not necessarily a “production” module, but hopefully this will help someone else down the line. It was frustrating as crap to get through this, but it was a good learning experience and a little fun troubleshooting something I didn’t write!

Thanks for the help!

I’m not sure I ever intended alternate-row coloring to work with the “-As List” mode, to be honest. I’m actually looking to rewrite the entire module to make it a bit easier to use - I’d like it to auto-assign some of those IDs, for example, rather than making you supply them, somehow - and I’ll keep this conversation in mind for when I do. The new module will be a big part of some classes I’m teaching, and will definitely be more production-class. It’ll go out with a revision of the ebook at some point.

No worries. And realize that the automatic alternate-row coloring didn’t work anywhere on the page if the “-As List” table was first. If the table header isn’t up there, I guess it messes up DataTables processing…

Anyway, I’ll still use the module in this and several other projects, and I’ll look forward to the new one!

Hello Guys,
Was wondering about using EnhancedHTML2 and having a collapsible/expandable or fixed height+scrollable right column in final report (ie, left column would contain verbose info, therefore, needs to be “minimized” until clicked or fixed height scrollable…).