PowerShell

Meet Dashimo – PowerShell Generated Dashboard

Today I wanted to introduce a little product that I've created in the last few weeks called Dashimo. It doesn't cover everything I wanted from it (feature wise), but it already can be used in production. Therefore, I thought it would be a good idea to get some feedback on whether I should spend some more time on it or throw it in the dumpster. Dashimo joins it's older brother Statusimo of PowerShell modules allowing an easy way to build HTML output. If it will feel familiar, it's because it was inspired with Bradley Wyatt PowerShell script he did. It gave me the idea of how I would like to build something similar but in a bit different way then he did, with much more flexibility. Still, if it wasn't for him, the idea wouldn't be there, therefore you should send him your thanks.

Dashimo - What you get?

While I could probably spend time here, trying to explain what it is, but I know it will take much less time to give you a picture. If you decide it's not for you to feel free to explore my other scripts/modules or read some blogs. I did create some useful content in the last two years.

That page you see above is generated in less than 40 lines of code. See for yourself

Dashboard -Name 'Dashimo Test' -FilePath $PSScriptRoot\Dashboard.html {
    Tab -Name 'Forest' {
        Section -Name 'Forest Information' -Invisible {
            Section -Name 'Forest Information' {
                Table -HideFooter -DataTable $DataSetForest.ForestInformation
            }
            Section -Name 'FSMO Roles' {
                Table -HideFooter -DataTable $DataSetForest.ForestFSMO
            }

        }
        Section -Name 'Forest Domain Controllers' -Collapsable {
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestDomainControllers
            }
        }
        Section -Name 'Forest Optional Features / UPN Suffixes / SPN Suffixes' -Collapsable {

            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestOptionalFeatures -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestUPNSuffixes -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSPNSuffixes -Verbose
            }
        }
        Section -Name 'Sites / Subnets / SiteLinks' -Collapsable {
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSites -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSubnets -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSiteLinks -Verbose
            }
        }
    }
}

Well I know, I know. It's not really 40 lines. The code responsible for building HTML above is less than 40 lines, but the data in it requires a bit more code. Below is full code to generate four tabs of data.

Import-Module Dashimo -Force
Import-Module PSWinDocumentation.AD -Force
Import-Module PSWinReporting

if ($null -eq $DataSetForest) {
    $DataSetForest = Get-WinADForestInformation -Verbose
}
if ($null -eq $DataSetEvents) {
    $DataSetEvents = Find-Events -Report UserChangesDetailed, UserChanges, UserLockouts, UserStatus, GroupChanges -Servers 'AD1', 'AD2' -DatesRange Last7days -Quiet
}

Dashboard -Name 'Dashimo Test' -FilePath $PSScriptRoot\Dashboard.html {
    Tab -Name 'Forest' {
        Section -Name 'Forest Information' -Invisible {
            Section -Name 'Forest Information' {
                Table -HideFooter -DataTable $DataSetForest.ForestInformation
            }
            Section -Name 'FSMO Roles' {
                Table -HideFooter -DataTable $DataSetForest.ForestFSMO
            }

        }
        Section -Name 'Forest Domain Controllers' -Collapsable {
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestDomainControllers
            }
        }
        Section -Name 'Forest Optional Features / UPN Suffixes / SPN Suffixes' -Collapsable {

            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestOptionalFeatures -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestUPNSuffixes -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSPNSuffixes -Verbose
            }
        }
        Section -Name 'Sites / Subnets / SiteLinks' -Collapsable {
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSites -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSubnets -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSiteLinks -Verbose
            }
        }
    }
    
    foreach ($Domain in $DataSetForest.Domains) {
        Tab -Name $Domain {
            Section -Name 'Domain Controllers / FSMO Roles' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainControllers -Verbose
                }
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainFSMO -Verbose
                }
            }


            Section -Name 'Password Policies' -Invisible {
                Section -Name 'Default Password Policy' {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainDefaultPasswordPolicy -Verbose
                }

                Section -Name 'Domain Fine Grained Policies' {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainFineGrainedPolicies -Verbose
                }
            }
            Section -Name 'Users' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainUsers
                }
            }
            Section -Name 'Computers' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainComputers
                }
            }
            Section -Name 'Groups Priviliged' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainGroupsPriviliged
                }
                Panel {
                    #Chart -DataTable $DataSetForest.FoundDomains.'ad.evotec.xyz'.DomainGroupsPriviliged -DataNames 'Group Name' -DataCategories $DataSetForest.FoundDomains.'ad.evotec.xyz'.DomainGroupsPriviliged.'Members Count' -DataValues 'Members Count'
                }
            }
            Section -Name 'Organizational Units' {
                Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainOrganizationalUnits
            }
            Section -Name 'OU ACL Basic' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainOrganizationalUnitsBasicACL
                }
            }
            Section -Name 'OU ACL Extended' {
                Panel {
                    Table -HideFooter -DataTable $DataSetForest.FoundDomains.$Domain.DomainOrganizationalUnitsExtended
                }
            }

        }
    }
    Tab -Name 'Changes in Last 7 days' {
        Section -Name 'Group Changes' -Collapsable {
            Table -HideFooter -DataTable $DataSetEvents.GroupChanges
        }
        Section -Name 'User Status' -Collapsable {
            Table -HideFooter -DataTable $DataSetEvents.UserStatus
        }
        Section -Name 'User Changes' -Collapsable {
            Table -HideFooter -DataTable $DataSetEvents.GroupChanges
        }
        Section -Name 'User Lockouts' -Collapsable {
            Table -HideFooter -DataTable $DataSetEvents.UserStatus
        }
    }
}

That's exactly 123 lines of code that generated four tabs of data. Nice huh? It is, at least to me 🙂 Now of course, as you may notice above I'm using two additional PowerShell Modules that I've written. The first one is PSWinDocumentation.AD and the other one is PSWinReporting (unfortunately that version is 2.0 edition, which is released as Preview to PSGallery therefore if you would like to use it you will have to do some jumps). To make it clear. You don't need those PowerShell modules. You're free to work with your objects, the way you like it. AD documentation and Events shown on screens are there for demo purposes.

Small explanation on PSWinDocumentation

A few days ago I've decided to split PSWinDocumentation module into a couple of smaller modules allowing for easy use of some features. The idea here is that those smaller modules will be easier to use in standalone projects, will be easier to modify and release fixes, and I hope (a lot really) that some people may invest their time to help me and build what I call DataSets. That means in coming weeks/months I will be rebuilding PSWinDocumentation and you should expect it to look like  this:

PSWinDocumentation.Builder – PowerShell Module responsible for building documentation (just the important part)
PSWinDocumentation.O365 – PowerShell Module responsible for delivering Office 365 dataset
PSWinDocumentation.AD – PowerShell Module responsible for delivering Active Directory dataset
PSWinDocumentation – PowerShell Module bundling all other PSWindocumentation modules together. Kind of like meta-module.

There will be much smaller modules being part of PSWinDocumentation. I've started some work on ADConnect, but there's also the AWS edition. Wait and see or come and help out! I don't bite!

Dashimo Description

Dashimo is only having five functions for now and the idea is to add 6th function in the near future.

Dashboard – treat it as an opening block. You define its name, you define FilePath where to save the file. You can even add AutoRefresh in seconds if you have the need. I may give it some more options in the future, but the idea is that it shouldn't be overloaded.
Tab – well as the name suggests it adds tabs to your HTML page. You should only use it if you have large amounts of data or you want to split your data into tabs (obvious right?). If you add a tab you define its name and you simply open a block where your data will be. Anything that you put there will be put under that tab.
Section – is a function that allows you to structure your HTML. You can have it collapsable or hidden. Each section can have more sections or panels inside.
Panel– is a smaller version of Section. It allows you to structure Tables as you want them. The main difference is that the Panel doesn't have any header. It can be Invisible as well thou.
Table – last but not least is a way for you to display your data. As a table. That's it. It has the ability to sort, export to excel, CSV, or search.

And that's it. Below code is all you need to understand how Dashimo works. It's simple, direct. You can add multiple panels, and it will add more of them. If you add three, you will have three columns, and if you add just two, you will have two columns. If you add 5, you will get five columns. The same idea is for sections. You can have multiple sections per row but they merely look differently, and those give you an additional way to name your data by using Name. Remember you can always use Invisible switch if you want to further position your data, just like I did using first, invisible section.

Dashboard -Name 'Dashimo Test' -FilePath $PSScriptRoot\Dashboard.html {
    Tab -Name 'Forest' {
        Section -Name 'Forest Information' -Invisible {
            Section -Name 'Forest Information' {
                Table -HideFooter -DataTable $DataSetForest.ForestInformation
            }
            Section -Name 'FSMO Roles' {
                Table -HideFooter -DataTable $DataSetForest.ForestFSMO
            }

        }
        Section -Name 'Forest Domain Controllers' -Collapsable {
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestDomainControllers
            }
        }
        Section -Name 'Forest Optional Features / UPN Suffixes / SPN Suffixes' -Collapsable {

            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestOptionalFeatures -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestUPNSuffixes -Verbose
            }
            Panel {
                Table -HideFooter -DataTable $DataSetForest.ForestSPNSuffixes -Verbose
            }
        }
    }
}

The 6th function that I've planned is adding Charts. Charts are on their way but they require a bit more work as I need them to be easy to use, and just the way I want them. I am still experimenting with them, so it takes a little more time. I do have some charts that are ready (and you can see them below), but I haven't added all types that I wanted, and I am still struggling on data definitions for ease of use. But to keep you entertained some gallery is below.

Have I got you entertained? Most of those are generated with  1-4 lines of code depending on data you want to display. But like I said above it's not yet ready for Dashimo. Therefore it's only available as part of PSWriteHTML. Ah, that's right, I've almost forgotten. Dashimo is based on PSWriteHTML. PSWriteHTML is a ReportHTML fork that has gone thru a total redesign so if you fancy some experimenting feel free to see what I've cooked up on GitHub. There are about 15 examples to get you started.  The thing with PSWriteHTML thou is that I experiment with it a lot. That means changes of parameters, changes of order, changes of naming convention. The idea behind Dashimo and Statusimo is that whenever I change something in PSWriteHTML that impacts those modules, I update them as well so that functionality should change much (still dependant on feedback from YOU). Do you remember how I mentioned Brad in the beginning? Brad's work actually got me into exploring ReportHTML but when I tried to use it I found out small things could break HTML and display things in an unpredictable way. You had to care for opening content, closing content. But if it weren't for ReportHTML this wouldn't happen so you can thank ReportHTML author as well, right after Brad.

Following screenshots are generated with Dashimo, but the data is coming from PSWinDocumentation.AD module. You can install it from PSGallery and if you think you can bring something useful from Active Directory perspective feel free to do PR or merely open an issue and we'll get the ball rolling.

Install-Module PSWinDocumentation.AD -Force

The following data is based on PSWinReporting 2.0. Please keep in mind that what is released in PSGallery as production version doesn't contain that.

Please keep in mind that if you have PSWinDocumentation the old version it may be conflicting with PSWinDocumentation.AD on some commands. I will fix that in the upcoming release of PSWinDocumentation as described above. Until then you can simply use AllowClobber switch if you get complains about conflicting command names. Also, keep in mind that I've not displayed everything in Dashimo. There are many more data available. Also if you're using only some data you may want to limit the output of that command by using RequiredTypes.

Dashimo - How to Install

So you know how to use Dashimo? Well, this is how you install it.

Install-Module Dashimo -Force

That's it. Notice how I'm using Force. I use force because it actually redownloads Dashimo but also any required modules. You see when I update Dashimo, I often update PSWriteHTML and PSSharedGoods. When you do Update-Module Dashimo it won't auto-update required modules. Also if I will decide to split PSSharedGoods into smaller modules and change something about it Update-Module will also ignore this. That's why I prefer using Force switch and be prepared! You of course, should use it the way you want to!

This post was last modified on %s = human-readable time difference 22:29

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Upgrade Azure Active Directory Connect fails with unexpected error

Today, I made the decision to upgrade my test environment and update the version of…

1 month ago

Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster

Have you ever looked at your Active Directory and wondered, "Why do I still have…

2 months ago

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

7 months ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

11 months ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

1 year ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

1 year ago