The Surly Admin

Father, husband, IT Pro, cancer survivor

New Scripts – Bandwidth Report and Google Charts

Got a couple of new scripts I recently wrote, here’s some quick thoughts on them.

Bandwidth Report

This script was originally inspired by this script, and I first wanted to talk to the original author to make sure he was cool with me porting to PowerShell, and to find out how he did a couple of things.  He gave me his full blessing and it was time to begin working on the script.

The actual measuring of time for the Mbps calculation would be really easy as I would just wrap a Copy-Item cmdlet in a Measure-Command object.  I’ve done that kind of testing many times for performance testing so it would be great to actually use it in a production script!  Now I needed a file of about 200mb.  Turns out this is a bit more difficult to find than I anticipated though I did eventually find something on Microsoft that as about 241mb.  The problem here was I wanted it to be easy to find so anyone could do it, maybe even have the script automatically download it.  But software links on the Internet are notorious for constantly changing and I began to realize this approach wouldn’t work.  So how to create a dummy file of the right size?  With a little Google-fu I discovered a Windows utility called FSUTIL.  Perfect!  I could now create a dummy file of any size and it’s fast.

I couldn’t quite decipher how to calculate Mbps from the Python script so I did another Google search and found this, but the numbers I was getting just didn’t seem right.  I am on a 54mbps wireless network and I was seeing transfer speeds of 150mbs+ in speed?!  So I consulted a good networking friend of mine–he hasn’t posted to his blog in a long time, maybe we can get him a few hits and he’ll get back into it–who lives and breaths this stuff and he thought the calculation was sound, except that instead of using 1,000,000 to do the change from bps to Mbps I should use 1,048,576 (which is 1024 x 1024).  This made sense since it was a Mega-Byte per second.  But didn’t explain why my number was coming up wonky.  Until I noticed I was converting my dummy file to bits TWICE (Total Size * 8 * 8).  Oops!  Fix that and suddenly the numbers start making sense.  Here’s the calculation I ended up using:

$Mbps = (($DummyFileSizeInBytes * 8) / $CopyTime.TotalSeconds) / 1048576

After this the rest of the script came together pretty easily.  Unfortunately the script was trying so hard to be all things to all people that I began to wonder if I was doing it right.

We need to spend some time apart…

One major tenet of PowerShell is reusability.  This is why there’s such a heavy focus on using objects, so you can use your script with any cmdlet, or even other people’s scripts!  That’s why ConvertTo-AdvHTML even works!  I had a lot of extra code in the script that allowed the output to be just an object–as well as text, HTML and CSV!–but the script was getting big and awkward at this point.  Time to split it in two!  Interesting, a couple of days after making this decision the conversation came up at the Spiceworks forum.

This really simplified the first script.  Once I could focus on just delivering an object I was able to streamline and get the script written quickly.  There’s nothing really ground breaking about the script itself so I won’t go into details about how it works, but here’s the final code:

Test-NetworkSpeed.ps1

So the much more interesting script (at least to me, I guess I’m a report wonk!) was the HTML to follow.  First I needed to save the data for historical purposes.  The obvious choice would be to use Export-CSV for this, but I don’t like how CSV flattens all of the fields to a string, forcing you to convert everything back to their native variable types when you read the data back in.  To avoid this I like use Export-Clixml, which saves the data in XML format and retains all of the variable types and properties.  So easy to just Export/Import the objects!  After that it’s a matter of adding some Google charts, and using my ConvertTo-AdvHTML function and you end up with:

Network Bandwidth Report

New-NetworkSpeedHTML

 

 

 

 

New-NetworkSpeedHTML2

 

 

 

 

 

 

 

 

Test-NetworkSpeed

 

 

 

 

Speaking of Charts

But after creating this report I began to think it’d be cool to create a function that allowed anyone to create a chart and add it to their HTML.  And after some thinking, I think I came up with a good way of accomplishing this.  The problem is there are two distinct and completely separate procedures that have to be done to bring a Google visualization to an HTML page.  First you need the JavaScript (jScript) that defines the data array and submits to Google, and then the HTML portion where you define where the image will be located.  This is done by using a class ID that the jScript generates.  There’s simply no way I can do the HTML portion as I have no way of knowing how the HTML will be built.  Using ConvertTo-HTML?  ConvertTo-AdvHTML?  Just building it using here-strings?  I’ll have to leave that to the scripter to handle.  The only part that’s fairly steady is the jScript itself, so this script will have to create the jScript and also pass back the class ID needed to reference the Google chart.

Turns out this script is almost entirely string manipulation.  The JavaScript required by Google is almost identical for a Line chart and a Bar chart too so I was able to include both in the same function.  I won’t go into boring details of how it works.  Again, it’s all strings.

The key to the script though is the way it returns an object with two properties.  The first property, “jscript” holds the JavaScript which you have to include in your <head> section.  The second property is “id” which hold the class ID you need to include in your HTML to reference the Google chart.  I usually use a DIV tag for this.  In the below example I use a small data set to create 2 charts and a table on an HTML page.  Here’s the sample data I use for this example:



Date Frogs Eagles Pigs
1/10 10 35 4
1/11 3 44 8
1/12 8 12 12
1/13 1 2 3
1/14 13 35 10
1/15 18 44 22

view raw

ChartData.csv

hosted with ❤ by GitHub

From there I pipe the object into the New-GoogleChart function with the properties I want to use:


$Chart1 = $CSV | New-GoogleChart XAxis Date YAxis Frogs,Eagles,Pigs Title "Sales To Date" LegendLocation Right ChartType LineSoft Verbose
$Chart2 = $CSV | New-GoogleChart XAxis Date YAxis Frogs,Pigs,Eagles Title "More Sales" LegendLocation Bottom ChartType Bar ChartNumber 1

Then it’s time to create the <HEAD> section.  Since I’m planning on using ConvertTo-HTML to create my HTML I don’t have to do the full section, but I do want to add my Style sheet and the JavaScript from the function.


$Header = @"
<style>
H1 {color: #000099;}
TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse; clear:both;}
TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #6495ED;font-size:1.5em;}
TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
DIV {float: left;}
</style>
$($Chart1.jscript)
$($Chart2.jscript)
"@

I want my two charts to be side by side, and the data table to be on a new line.  To do this I use “float: left;” on the DIV tag to get the charts to be side by side.  In the table tag I use “clear: both;” to make the table start on a new line.  After the </style> tag I add the JavaScript.  I have two chart objects $Chart1 and $Chart2 and simply put the JavaScript property right in there.  After that I just use ConvertTo-HTML and the -Body parameter to put the chart in there.  I use <DIV> tags with ID to the class ID created by the function ($Chart1.id and $Chart2.id), this ties the HTML to the JavaScript and makes the magic happen.


$CSV | ConvertTo-Html Head $Header Body "<div id=""$($Chart1.id)""></div><div id=""$($Chart2.id)""></div>" | Out-File c:\Dropbox\Test\testchart.html Encoding ASCII

And here’s what it looks like:

new-googlechart

If you ever end up using this function, please let me know!  I want to see what you did with it!

New-GoogleChart

Advertisement

April 2, 2014 - Posted by | PowerShell - HTML Reporting | , , , , ,

4 Comments »

  1. If there is historical data preset, the following error is returned, If the xml file is removed, the script runs fine and generates a report.

    Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.
    At C:\bandwidth_report.ps1:279 char:5
    + $Data += & $ScriptPath -Path $Path | Select Server,TimeStamp,Status,WriteMbp …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    (https://gallery.technet.microsoft.com/scriptcenter/An-Array-of-PowerShell-069c30aa)

    Comment by Mark | November 21, 2014 | Reply

  2. Love the network report. But I want to do this on a development network that has no access to the Internet. Its an internal network. Do you know of something other than google visualzation to accomplish this?

    Comment by Michael B | March 1, 2016 | Reply

    • Nothing specifically, no. There are definitely some jQuery stuff and there are bootstrap templates that support charting. You could also split the script up, so have the first one save the data somewhere and then have a second script make the visualization (that has access to the Internet).

      Comment by Martin9700 | March 1, 2016 | Reply

  3. Hi,
    Great script but I need to run it with Powershell v2. Is there any changes I can do to have it running fine on v 2?
    Regards and tnx for sharing.
    Red.

    Comment by Red | May 27, 2016 | Reply


Leave a Reply to Martin9700 Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: