Building Better PowerShell Dashboards
First off, YUUGE props to Flynn Bundy for shining lights on the possibility with his post Making DSC BeautifulĀ and @Neeco of HTML5Up.com for these gorgeous HTML5 and CSS templates.
If you check out HTML5up.com, there are a ton of absolutely beautiful templates, for free! (Well, you have to leave a link to the site, unless you pay $20, then you can edit it to your heartās content).
Some of them REALLY lend themselves well to a dashboard system for consumption of data.
ā¦you know, PowerShell makes an excellent data collection and processing system.
It even has Ā native HTML capabilities, as weāve covered previously in our post:Ā Using ConvertTo-HTML and CSS to create useful web reports from PowerShell. Ā If youāre lost and donāt even know where to start, begin here. Ā Iāll bet we could make some REALLY cool looking dashboards using PowerShell and Neecoās templates!
Letās make a cool PowerShell Dashboard
So, Iāll start by finding a template that I like. Ā I choose the gorgeous Phantom, which is also the top one from the list. Ā Now, you might be asking yourself āFoxDeploy, did you even look at all of the templates first?ā to which I would respond: SURE.
Letās take a look at Phantom. Ā Itās got a nice set of fonts and a good layout, with a big title glob of text, then a smaller description below it. Ā Itās followed by a big element or DIV called Tiles, with colored squares inside of it, called articles.
Letās take a look into the code and see how this is represented.
A few things jump out at me here. Ā Looking back at the image of the template itself, I see the first three squares/cards/cubesĀ are red, blue and green. Ā Going back to the code, I donāt see the colors listed there but I DO see a style, a different one for each. Ā It looks like the color of the tile is controlled by the style property in itās declaration, like this:
<article class="style1">
<span class="image">
<img src="images/pic01.jpg" alt="" />
</span>
<a href="generic.html">
<h2>Magna</h2>
<div class="content">
<p>Sed nisl arcu euismod sit amet nisi lorem etiam dolor veroeros et feugiat.</p>
</div>
</a>
</article>
If you see a property like class= or id= within a HTML element, thatās a good clue that the Cascading Style Sheet (cascading meaning you can have a base one for the site, then special sub-sheets for specific pages, and overlap them all in a precise, cascading order)Ā CSS will do some special processing on it when itās displayed to the user.
Whatās CSS?
Ā If CSS is totally new to you, itās a great concept that allows us to pull the design and colors out of our HTML webpages. Ā Instead of specifying what font to use for this section of the page, and what color to make the background, we pull all of that style gunk out and leave behind just the meat and potatoes (the content, that is) of our site in HTML. Ā All style goes into the Cascading Style Sheetāthe CSS file.
As we saw in the screen shot, each of the squares had a different color, and looking at the code, the only real difference between each of the squaresĀ in code was that a different style was listed. So, weāll look into the CSS files and see what it says for coloring.
For this and all web design work, I like to use Visual Studio Code, by the incredible David Wilson [MSFT]. Ā Especially for CSS, it makes finding color assignments super easy, since it depicts the color in a little box next to it, you know, in case you donāt say things like āWife, your eyes are the most beautiful shade of #7eccfbā
The colors are down near line 2700. Ā (Hit Control+G to bring up the āGo to lineā box, and type in the number.)
So we can see that style1 is red, style2 is blue, style3 is green, etc. Ā Now I know what I want to doā¦
Time to Code
Iām going to make a dashboard to show the status of my Hyper-V VMs.
As I tend to do, first Iāll begin with a working PowerShell sample. Ā Iāll run Get-VM to see all of my VMs. Ā If the status of the VM is running, Iāll use the Green (style3) indicator. Ā If itās Stopped, Iāll use the Red (style1), and if itās something else, Iāll use style2. Ā This would include Critical or some other weird state.
$VMS = get-vm | sort State
ForEach ($VM in $VMS){
$Name=$vm.Name
if ($vm.State -eq 'Off'){
$style = 'style1'
}
elseif($vm.state -eq 'Running'){
$style = &quot;style3&quot;
}
else{
#VM is haunted or something else
$style = &quot;style2&quot;
}
#Now we know what state to pick
}
I know what I need to set for each square, but donāt know how toĀ add my squares to the actual index.html of this page.
And now, to do something unholy to the HTML
I use an unorthodox approach that totally works well. Ā Once we understand how the HTML in index.html is rendering the page, what weāll do here will make perfect sense.
Starting at the top of the document, letās visualize what each chunk of code represents when parsed by a browserā¦
So, thatās the top part. Ā After that, beginning with the <section class="tiles">
tag, we have a big repeating structure which gives us all of the squares/tiles.
Finally, beginning with the closing </section> tag, we have the bottom of the page, with itās contact forms and all of that.
To do this the easy way, letās just cut it into three files!
Iāll take the core file here (which is index.html) and Iāll break it into two chunks. Ā Everything from the top of the file including the line <section class="tiles"> goes into head.html. Ā Now, start at the bottom of the file and take the last line all the way up to and including the line </section> and save that as tail.html.
Now we need to make our cards
Structure of a card/tile/square
Letās look into the structure of one of these tiles for a moment.
I can see how this should look. Ā Iāve already got my code to say what style to use, so when Iām making a card for each VM, Iāll set the style to change the color of the square for On/Off/Other.
Next, instead of āMagnaā within the Header2 tags, I want my VM Name.
If the machine is turned on, Iād also like to see itās CPU usage and RAM pressure. Ā Finally, when I hover over the tile, a little section of text appearsā¦I think that would be a cool place to list where the machineās VHD files are, and itās uptime.
Iāll add another if{} scriptblock, and within this one, Iāll test to see if the VM was online. If it was, Iām going to recast itās $name property, to add a new line after the name, with RAM and CPU. Ā I reuse $name, so that no matter if the machine is on or off, I can have the same block of code make a square for me.
#if the VM is on, don't just show it's name, but it's RAM and CPU usage too if ($VM.State -eq 'Running'){
$Name="$($VM.Name)
RAM: $($VM.MemoryAssigned /1mb)
CPU: $($VM.CPUUsage)" }
I also want to have a little description of the VM, like where itās VHD files live, etc. So Iāll set the value of $description like this:
$description= @" Currently $($VM.Status.ToLower()) with a
state of $($VM.State)
It was created on $($VM.CreationTime)
Its files are found in $($VM.Path) "@
Weāve got all the bits we need to make a card, we can now just drop in the HTML for a card in a here-string, and put the variables weāve made here in place of the name and descrption.
$tile = @"
<article class="$style">
<span class="image">
<img src="images/pic01.jpg" alt="" />
</span>
<a href="generic.html">
<h2>$Name</h2>
<div class="content">
$($description)
</div>
</a>
</article>
"@
And now, repeat after meā¦
String concatenation isnāt ALWAYS evil.
Because thatās totally what weāre about to do. We broke the file into three bits. Now itās time to put it back together. To end the for-each scriptblock for each card, weāll add the current card to $main.
Then, we build our completed file, by adding $head + $main + $tail, and then we dump that into an HTML file. Easy peasey!
$main += $tile #EndOfForEach }
$html = $head + $main + $tail
$html > .\\VMReport.html
Final Touches
Now youāll probably want to open up head.html and replace the text there with your branding. Youāll also want to add in an image, most likely.
Adding the time
To add in the current time the report was generated, add in a string we can replae when importing the file. I added the string %4 to line 4 in head.html, like so:
<div class="inner">
<header>
<h1>FoxDeploy Health Monitoring Dashboard</h1>
At a glance monitoring of status of VMs in Hyper-V updated at %4 </header>
this gives me an easy anchor to replace when I import the file, so I can use -replace %4 with the current time, like this:
$head = (Get-Content .\\head.html) -replace '%4',(get-date).DateTime
Auto refreshing the page
Iād like to make the page automatically reload every 30 seconds, so add this line to your head.html page.
<meta http-equiv="refresh" content="20"; URL="path to your report.html">
Run forever
It would also be nice to have this automatically run until the end of time, so Iāll just add an open-ended for loop to the script, and then add a Start-Sleep timeout at the end. This way, the report will generate once every 15 seconds or so, and the browser will auto refresh every 20 seconds, so the two should be mostly in sync.
#Add to first line of the script For(;;){
#Last line of script Start-Sleep -Seconds 15}
And the finished product
Next Steps
Iāve not completed this part, but a KILLER next step would be to make these buttons work when you click them. Ā Currently, they all link to generic.html, but instead, you could use this same process to create a page for each VM and name it VMname.html. Ā Then when you build the card, add the appropriate link and bam, you have a fully functional VM dashboard.
If you go this route, consider adding a Windows Event view, or deeper VM statistics. Ā You could really go hog-wild here. Ā Another cool idea is to make use of the images provided in this template, and provide a background image for the tiles.
Iāve got you this far, time for you to make it your own.
Iām just scrolling till I see the word āDownloadā
Here you go, buddy :) Code Download