New Module VMware-vCD-TenantReport
This Module Creates a nice HTML Report for vCD Customers. Report Contains Objects like Users, Catalogs, VDCs, vApps, VMs, Edge Gateways
This commit is contained in:
30
Modules/VMware-vCD-TenantReport/README.md
Normal file
30
Modules/VMware-vCD-TenantReport/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
VMware-vCD-TenantReport PowerShell Module
|
||||||
|
=============
|
||||||
|
|
||||||
|
# About
|
||||||
|
|
||||||
|
## Project Owner:
|
||||||
|
|
||||||
|
Markus Kraus [@vMarkus_K](https://twitter.com/vMarkus_K)
|
||||||
|
|
||||||
|
MY CLOUD-(R)EVOLUTION [mycloudrevolution.com](http://mycloudrevolution.com/)
|
||||||
|
|
||||||
|
## Project WebSite:
|
||||||
|
|
||||||
|
[mycloudrevolution.com](http://mycloudrevolution.com/)
|
||||||
|
|
||||||
|
## Project Documentation:
|
||||||
|
|
||||||
|
[Read the Docs](http://readthedocs.io/)
|
||||||
|
|
||||||
|
## Project Description:
|
||||||
|
|
||||||
|
The 'VMware-vCD-TenantReport' PowerShell Module creates with the Fuction 'Get-VcdTenantReport' a HTML Report of your vCloud Director Objects.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Big thanks to [Timothy Dewin](https://twitter.com/tdewin) for his great [PowerStartHTML](https://github.com/tdewin/randomsamples/tree/master/powerstarthtml) PowerShell Module which is used to generate the Report for this Module.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
122
Modules/VMware-vCD-TenantReport/VMware-vCD-TenantReport.psd1
Normal file
122
Modules/VMware-vCD-TenantReport/VMware-vCD-TenantReport.psd1
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#
|
||||||
|
# Modulmanifest für das Modul "VMware-vCD-TenantReport"
|
||||||
|
#
|
||||||
|
# Generiert von: Markus Kraus
|
||||||
|
#
|
||||||
|
# Generiert am: 8/22/2017
|
||||||
|
#
|
||||||
|
|
||||||
|
@{
|
||||||
|
|
||||||
|
# Die diesem Manifest zugeordnete Skript- oder Binärmoduldatei.
|
||||||
|
# RootModule = 'VMware-vCD-TenantReport.psm1'
|
||||||
|
|
||||||
|
# Die Versionsnummer dieses Moduls
|
||||||
|
ModuleVersion = '1.0.2'
|
||||||
|
|
||||||
|
# ID zur eindeutigen Kennzeichnung dieses Moduls
|
||||||
|
GUID = '21a71eaa-d259-48c5-8482-643ba152af76'
|
||||||
|
|
||||||
|
# Autor dieses Moduls
|
||||||
|
Author = 'Markus'
|
||||||
|
|
||||||
|
# Unternehmen oder Hersteller dieses Moduls
|
||||||
|
CompanyName = 'mycloudrevolution.com'
|
||||||
|
|
||||||
|
# Urheberrechtserklärung für dieses Modul
|
||||||
|
Copyright = '(c) 2017 Markus Kraus. Alle Rechte vorbehalten.'
|
||||||
|
|
||||||
|
# Beschreibung der von diesem Modul bereitgestellten Funktionen
|
||||||
|
# Description = ''
|
||||||
|
|
||||||
|
# Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Moduls
|
||||||
|
# PowerShellVersion = ''
|
||||||
|
|
||||||
|
# Der Name des für dieses Modul erforderlichen Windows PowerShell-Hosts
|
||||||
|
# PowerShellHostName = ''
|
||||||
|
|
||||||
|
# Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Hosts
|
||||||
|
# PowerShellHostVersion = ''
|
||||||
|
|
||||||
|
# Die für dieses Modul mindestens erforderliche Microsoft .NET Framework-Version
|
||||||
|
# DotNetFrameworkVersion = ''
|
||||||
|
|
||||||
|
# Die für dieses Modul mindestens erforderliche Version der CLR (Common Language Runtime)
|
||||||
|
# CLRVersion = ''
|
||||||
|
|
||||||
|
# Die für dieses Modul erforderliche Prozessorarchitektur ("Keine", "X86", "Amd64").
|
||||||
|
# ProcessorArchitecture = ''
|
||||||
|
|
||||||
|
# Die Module, die vor dem Importieren dieses Moduls in die globale Umgebung geladen werden müssen
|
||||||
|
# RequiredModules = @()
|
||||||
|
|
||||||
|
# Die Assemblys, die vor dem Importieren dieses Moduls geladen werden müssen
|
||||||
|
# RequiredAssemblies = @()
|
||||||
|
|
||||||
|
# Die Skriptdateien (PS1-Dateien), die vor dem Importieren dieses Moduls in der Umgebung des Aufrufers ausgeführt werden.
|
||||||
|
# ScriptsToProcess = @()
|
||||||
|
|
||||||
|
# Die Typdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
|
||||||
|
# TypesToProcess = @()
|
||||||
|
|
||||||
|
# Die Formatdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
|
||||||
|
# FormatsToProcess = @()
|
||||||
|
|
||||||
|
# Die Module, die als geschachtelte Module des in "RootModule/ModuleToProcess" angegebenen Moduls importiert werden sollen.
|
||||||
|
NestedModules = @( "modules/PowerStartHTML/PowerStartHTML.psd1",
|
||||||
|
"functions/Get-VcdTenantReport.psm1" )
|
||||||
|
|
||||||
|
# Aus diesem Modul zu exportierende Funktionen
|
||||||
|
FunctionsToExport = '*'
|
||||||
|
|
||||||
|
# Aus diesem Modul zu exportierende Cmdlets
|
||||||
|
CmdletsToExport = '*'
|
||||||
|
|
||||||
|
# Die aus diesem Modul zu exportierenden Variablen
|
||||||
|
VariablesToExport = '*'
|
||||||
|
|
||||||
|
# Aus diesem Modul zu exportierende Aliase
|
||||||
|
AliasesToExport = '*'
|
||||||
|
|
||||||
|
# Aus diesem Modul zu exportierende DSC-Ressourcen
|
||||||
|
# DscResourcesToExport = @()
|
||||||
|
|
||||||
|
# Liste aller Module in diesem Modulpaket
|
||||||
|
# ModuleList = @()
|
||||||
|
|
||||||
|
# Liste aller Dateien in diesem Modulpaket
|
||||||
|
# FileList = @()
|
||||||
|
|
||||||
|
# Die privaten Daten, die an das in "RootModule/ModuleToProcess" angegebene Modul übergeben werden sollen. Diese können auch eine PSData-Hashtabelle mit zusätzlichen von PowerShell verwendeten Modulmetadaten enthalten.
|
||||||
|
PrivateData = @{
|
||||||
|
|
||||||
|
PSData = @{
|
||||||
|
|
||||||
|
# 'Tags' wurde auf das Modul angewendet und unterstützt die Modulermittlung in Onlinekatalogen.
|
||||||
|
# Tags = @()
|
||||||
|
|
||||||
|
# Eine URL zur Lizenz für dieses Modul.
|
||||||
|
# LicenseUri = ''
|
||||||
|
|
||||||
|
# Eine URL zur Hauptwebsite für dieses Projekt.
|
||||||
|
# ProjectUri = ''
|
||||||
|
|
||||||
|
# Eine URL zu einem Symbol, das das Modul darstellt.
|
||||||
|
# IconUri = ''
|
||||||
|
|
||||||
|
# 'ReleaseNotes' des Moduls
|
||||||
|
# ReleaseNotes = ''
|
||||||
|
|
||||||
|
} # Ende der PSData-Hashtabelle
|
||||||
|
|
||||||
|
} # Ende der PrivateData-Hashtabelle
|
||||||
|
|
||||||
|
# HelpInfo-URI dieses Moduls
|
||||||
|
# HelpInfoURI = ''
|
||||||
|
|
||||||
|
# Standardpräfix für Befehle, die aus diesem Modul exportiert werden. Das Standardpräfix kann mit "Import-Module -Prefix" überschrieben werden.
|
||||||
|
# DefaultCommandPrefix = ''
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
function Get-VcdTenantReport {
|
||||||
|
<#
|
||||||
|
.NOTES
|
||||||
|
===========================================================================
|
||||||
|
Created by: Markus Kraus
|
||||||
|
Twitter: @VMarkus_K
|
||||||
|
Private Blog: mycloudrevolution.com
|
||||||
|
===========================================================================
|
||||||
|
Changelog:
|
||||||
|
1.0.0 - Inital Release
|
||||||
|
1.0.1 - Removed "Test-IP" Module
|
||||||
|
1.0.2 - More Detailed Console Log
|
||||||
|
===========================================================================
|
||||||
|
External Code Sources:
|
||||||
|
Examle Usage of BOOTSTRAP with PowerShell
|
||||||
|
https://github.com/tdewin/randomsamples/tree/master/powershell-veeamallstat
|
||||||
|
BOOTSTRAP with PowerShell
|
||||||
|
https://github.com/tdewin/randomsamples/tree/master/powerstarthtml
|
||||||
|
===========================================================================
|
||||||
|
Tested Against Environment:
|
||||||
|
vCD Version: 8.20
|
||||||
|
PowerCLI Version: PowerCLI 6.5.1
|
||||||
|
PowerShell Version: 5.0
|
||||||
|
OS Version: Windows 8.1
|
||||||
|
Keyword: VMware, vCD, Report, HTML
|
||||||
|
===========================================================================
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This Function creates a HTML Report for your vCloud Director Organization.
|
||||||
|
|
||||||
|
This Function is fully tested as Organization Administrator.
|
||||||
|
With lower permissions a unexpected behavior is possible.
|
||||||
|
|
||||||
|
.Example
|
||||||
|
Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Credential $MyCedential
|
||||||
|
|
||||||
|
.Example
|
||||||
|
Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Path "C:\Temp\Report.html"
|
||||||
|
|
||||||
|
.PARAMETER Server
|
||||||
|
The FQDN of your vCloud Director Endpoint.
|
||||||
|
|
||||||
|
.PARAMETER Org
|
||||||
|
The Organization Name.
|
||||||
|
|
||||||
|
.PARAMETER Credential
|
||||||
|
PowerShell Credentials to access the Eénvironment.
|
||||||
|
|
||||||
|
.PARAMETER Path
|
||||||
|
The Path of the exported HTML Report.
|
||||||
|
|
||||||
|
#>
|
||||||
|
#Requires -Version 5
|
||||||
|
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.5.1.0"}
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$True, ValueFromPipeline=$False)]
|
||||||
|
[ValidateNotNullorEmpty()]
|
||||||
|
[String] $Server,
|
||||||
|
[Parameter(Mandatory=$True, ValueFromPipeline=$False)]
|
||||||
|
[ValidateNotNullorEmpty()]
|
||||||
|
[String] $Org,
|
||||||
|
[Parameter(Mandatory=$False, ValueFromPipeline=$False)]
|
||||||
|
[ValidateNotNullorEmpty()]
|
||||||
|
[PSCredential] $Credential,
|
||||||
|
[Parameter(Mandatory=$false, ValueFromPipeline=$False)]
|
||||||
|
[ValidateNotNullorEmpty()]
|
||||||
|
[String] $Path = ".\Report.html"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
|
||||||
|
# Start Connection to vCD
|
||||||
|
|
||||||
|
if ($global:DefaultCIServers) {
|
||||||
|
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Disconnect existing vCD Server ..."
|
||||||
|
$Trash = Disconnect-CIServer -Server * -Force:$true -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Connect vCD Server ..."
|
||||||
|
if ($Credential) {
|
||||||
|
$Trash = Connect-CIServer -Server $Server -Org $Org -Credential $Credential -ErrorAction Stop
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$Trash = Connect-CIServer -Server $Server -Org $Org -ErrorAction Stop
|
||||||
|
}
|
||||||
|
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Create HTML Report..."
|
||||||
|
|
||||||
|
# Init HTML Report
|
||||||
|
$ps = New-PowerStartHTML -title "vCD Tenant Report"
|
||||||
|
|
||||||
|
#Set CSS Style
|
||||||
|
$ps.cssStyles['.bgtitle'] = "background-color:grey"
|
||||||
|
$ps.cssStyles['.bgsubsection'] = "background-color:#eee;"
|
||||||
|
|
||||||
|
# Processing Data
|
||||||
|
## Get Main Objects
|
||||||
|
[Array] $OrgVdcs = Get-OrgVdc
|
||||||
|
[Array] $Catalogs = Get-Catalog
|
||||||
|
[Array] $Users = Get-CIUser
|
||||||
|
|
||||||
|
## Add Header to Report
|
||||||
|
$ps.Main().Add("div","jumbotron").N()
|
||||||
|
$ps.Append("h1","display-3",("vCD Tenant Report" -f $OrgVdcs.Count)).Append("p","lead","Organization User Count: {0}" -f $Users.Count).Append("p","lead","Organization Catalog Count: {0}" -f $Catalogs.Count).Append("p","lead","Organization VDC Count: {0}" -f $OrgVdcs.Count).Append("hr","my-4").Append("p","font-italic","This Report lists the most important objects in your vCD Environmet. For more details contact your Service Provider").N()
|
||||||
|
|
||||||
|
## add Org Users to Report
|
||||||
|
$ps.Main().Append("h2",$null,"Org Users").N()
|
||||||
|
|
||||||
|
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"User Name").Append("th",$null,"Locked").Append("th",$null,"DeployedVMCount").Append("th",$null,"StoredVMCount").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
|
||||||
|
foreach ($User in $Users) {
|
||||||
|
$ps.Append("td",$null,$User.Name).N()
|
||||||
|
$ps.Append("td",$null,$User.Locked).N()
|
||||||
|
$ps.Append("td",$null,$User.DeployedVMCount).N()
|
||||||
|
$ps.Append("td",$null,$User.StoredVMCount).N()
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
## add Org Catalogs to Report
|
||||||
|
$ps.Main().Append("h2",$null,"Org Catalogs").N()
|
||||||
|
|
||||||
|
foreach ($Catalog in $Catalogs) {
|
||||||
|
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Catalog Name").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$Catalog.Name).Up().N()
|
||||||
|
|
||||||
|
$ps.Add("td","bgsubsection").N()
|
||||||
|
$ps.Add("table","table bgcolorsub").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
|
||||||
|
$headers = @("Item")
|
||||||
|
foreach ($h in $headers) {
|
||||||
|
$ps.Append("th",$null,$h).N()
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
### add Itens of the Catalog to the Report
|
||||||
|
[Array] $Items = $Catalog.ExtensionData.CatalogItems.CatalogItem
|
||||||
|
|
||||||
|
foreach ($Item in $Items) {
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$Item.Name).N()
|
||||||
|
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$ps.Up().Up().N()
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
## add Org VDC`s to the Report
|
||||||
|
$ps.Main().Append("h2",$null,"Org VDCs").N()
|
||||||
|
|
||||||
|
foreach ($OrgVdc in $OrgVdcs) {
|
||||||
|
$ps.Main().Add('table','table table-striped table-inverse').Add("tr").Append("th",$null,"VDC Name").Append("th",$null,"Enabled").Append("th",$null,"CpuUsedGHz").Append("th",$null,"MemoryUsedGB").Append("th",$null,"StorageUsedGB").Up().N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$OrgVdc.Name).Append("td",$null,$OrgVdc.Enabled).Append("td",$null,$OrgVdc.CpuUsedGHz).Append("td",$null,$OrgVdc.MemoryUsedGB).Append("td",$null,[Math]::Round($OrgVdc.StorageUsedGB,2)).Up().N()
|
||||||
|
|
||||||
|
### add Edge Gateways of this Org VDC to Report
|
||||||
|
$ps.Main().Append("h3",$null,"Org VDC Edge Gateways").N()
|
||||||
|
[Array] $Edges = Search-Cloud -QueryType EdgeGateway -Filter "Vdc==$($OrgVdc.Id)"
|
||||||
|
|
||||||
|
foreach ($Edge in $Edges) {
|
||||||
|
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Edge Name").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$Edge.Name).Up().N()
|
||||||
|
|
||||||
|
$ps.Add("td","bgsubsection").N()
|
||||||
|
$ps.Add("table","table bgcolorsub").N()
|
||||||
|
$ps.Append("tr").Append("td","font-weight-bold","HaStatus").Append("td",$null,($Edge.HaStatus)).N()
|
||||||
|
$ps.Append("td","font-weight-bold","AdvancedNetworkingEnabled").Append("td",$null,$Edge.AdvancedNetworkingEnabled).N()
|
||||||
|
$ps.Append("tr").Append("td","font-weight-bold","NumberOfExtNetworks").Append("td",$null,($Edge.NumberOfExtNetworks)).N()
|
||||||
|
$ps.Append("td","font-weight-bold","NumberOfOrgNetworks").Append("td",$null,$Edge.NumberOfOrgNetworks).N()
|
||||||
|
|
||||||
|
$ps.Up().Up().N()
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
### add Org Networks of this Org VDC to Report
|
||||||
|
$ps.Main().Append("h3",$null,"Org VDC Networks").N()
|
||||||
|
[Array] $Networks = $OrgVdc | Get-OrgVdcNetwork
|
||||||
|
|
||||||
|
foreach ($Network in $Networks) {
|
||||||
|
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Network Name").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$Network.Name).Up().N()
|
||||||
|
|
||||||
|
$ps.Add("td","bgsubsection").N()
|
||||||
|
$ps.Add("table","table bgcolorsub").N()
|
||||||
|
$ps.Append("tr").Append("td","font-weight-bold","DefaultGateway").Append("td",$null,($Network.DefaultGateway)).N()
|
||||||
|
$ps.Append("td","font-weight-bold","Netmask").Append("td",$null,$Network.Netmask).N()
|
||||||
|
$ps.Append("tr").Append("td","font-weight-bold","NetworkType").Append("td",$null,($Network.NetworkType)).N()
|
||||||
|
$ps.Append("td","font-weight-bold","StaticIPPool").Append("td",$null,$Network.StaticIPPool).N()
|
||||||
|
|
||||||
|
$ps.Up().Up().N()
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
### add vApps of this Org VDC to Report
|
||||||
|
$ps.Main().Append("h3",$null,"Org VDC vApps").N()
|
||||||
|
|
||||||
|
[Array] $Vapps = $OrgVdc | Get-CIVApp
|
||||||
|
|
||||||
|
foreach ($Vapp in $Vapps) {
|
||||||
|
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"vApp Name").Append("th",$null,"Owner").Up().N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$Vapp.Name).Append("td",$null,$Vapp.Owner).Up().N()
|
||||||
|
|
||||||
|
#### add VMs of this vApp to Report
|
||||||
|
$ps.Add("td","bgsubsection").N()
|
||||||
|
$ps.Add("table","table bgcolorsub").N()
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
|
||||||
|
$headers = @("Name","Status","GuestOSFullName","CpuCount","MemoryGB")
|
||||||
|
foreach ($h in $headers) {
|
||||||
|
$ps.Append("th",$null,$h).N()
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
[Array] $VMs = $Vapp | Get-CIVM
|
||||||
|
|
||||||
|
foreach ($VM in $VMs) {
|
||||||
|
$ps.Add("tr").N()
|
||||||
|
$ps.Append("td",$null,$VM.Name).N()
|
||||||
|
$ps.Append("td",$null,$VM.Status).N()
|
||||||
|
$ps.Append("td",$null,$VM.GuestOSFullName).N()
|
||||||
|
$ps.Append("td",$null,$VM.CpuCount).N()
|
||||||
|
$ps.Append("td",$null,$VM.MemoryGB).N()
|
||||||
|
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
}
|
||||||
|
$ps.Up().Up().N()
|
||||||
|
|
||||||
|
}
|
||||||
|
$ps.Up().N()
|
||||||
|
|
||||||
|
}
|
||||||
|
$ps.save($Path)
|
||||||
|
|
||||||
|
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Open HTML Report..."
|
||||||
|
Start-Process $Path
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Modules/VMware-vCD-TenantReport/media/Get-VcdTenantReport.png
Normal file
BIN
Modules/VMware-vCD-TenantReport/media/Get-VcdTenantReport.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
@@ -0,0 +1,237 @@
|
|||||||
|
class PowerStartHTML {
|
||||||
|
[string]$PowerStartHtmlTemplate = "<html><head><meta charset=`"UTF-8`"/><title></title><style></style></head><body><div/></body></html>"
|
||||||
|
[xml]$xmlDocument = $null
|
||||||
|
$onLoadJS = $null
|
||||||
|
$cssStyles= @{}
|
||||||
|
$lastEl = $null
|
||||||
|
$newEl = $null
|
||||||
|
$indentedOutput = $false
|
||||||
|
$bootstrapAtCompile = $false
|
||||||
|
PowerStartHTML([string]$title) {
|
||||||
|
$this.xmlDocument = $this.PowerStartHtmlTemplate
|
||||||
|
$this.xmlDocument.html.head.title = $title
|
||||||
|
$this.lastEl = $this.xmlDocument.html.body.ChildNodes[0]
|
||||||
|
$this.onLoadJS = New-Object System.Collections.Generic.List[System.String]
|
||||||
|
}
|
||||||
|
[string] GetHtml() {
|
||||||
|
$xmlclone = $this.xmlDocument.Clone()
|
||||||
|
$csb = [System.Text.StringBuilder]::new()
|
||||||
|
foreach ($cssStyle in $this.cssStyles.GetEnumerator()) {
|
||||||
|
$null = $csb.AppendFormat("{0} {{ {1} }}",$cssStyle.Name,$cssStyle.Value)
|
||||||
|
}
|
||||||
|
$this.xmlDocument.html.head.style = $csb.toString()
|
||||||
|
$this.AddBootStrapAtCompile()
|
||||||
|
if($this.onLoadJS.Count -gt 0) {
|
||||||
|
$this.onLoadJs.Insert(0,"`r`n`$(document).ready(function() {")
|
||||||
|
$this.onLoadJs.Add("})`r`n")
|
||||||
|
$el = $this.xmlDocument.CreateElement("script")
|
||||||
|
$el.AppendChild($this.xmlDocument.CreateTextNode([System.String]::Join("`r`n",$this.onLoadJs)))
|
||||||
|
$this.xmlDocument.html.body.AppendChild($el)
|
||||||
|
}
|
||||||
|
$ms = [System.IO.MemoryStream]::new()
|
||||||
|
$xmlWriter = [System.Xml.XmlTextWriter]::new($ms,[System.Text.Encoding]::UTF8)
|
||||||
|
if($this.indentedOutput) {
|
||||||
|
$xmlWriter.Formatting = [System.Xml.Formatting]::Indented
|
||||||
|
}
|
||||||
|
$this.xmlDocument.WriteContentTo($xmlWriter)
|
||||||
|
$xmlWriter.Flush()
|
||||||
|
$ms.Flush()
|
||||||
|
#make sure that everytime we do gethtml we keep it clean
|
||||||
|
$this.xmlDocument = $xmlclone
|
||||||
|
$ms.Position = 0;
|
||||||
|
$sr = [System.IO.StreamReader]::new($ms);
|
||||||
|
return ("<!DOCTYPE html>{0}`r`n" -f $sr.ReadToEnd())
|
||||||
|
}
|
||||||
|
Save($path) {
|
||||||
|
$this.GetHtml() | Set-Content -path $path -Encoding UTF8
|
||||||
|
}
|
||||||
|
|
||||||
|
AddAttr($el,$name,$value) {
|
||||||
|
$attr = $this.xmlDocument.CreateAttribute($name)
|
||||||
|
$attr.Value = $value
|
||||||
|
$el.Attributes.Append($attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
AddAttrs($el,$dict) {
|
||||||
|
foreach($a in $dict.GetEnumerator()) {
|
||||||
|
$this.AddAttr($el,$a.Name,$a.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[PowerStartHTML] AddBootStrap() {
|
||||||
|
$this.bootstrapAtCompile = $true
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
AddJSScript($href,$integrity) {
|
||||||
|
$el = $this.xmlDocument.CreateElement("script")
|
||||||
|
$attrs = @{
|
||||||
|
"src"="$href";
|
||||||
|
"integrity"="$integrity";
|
||||||
|
"crossorigin"="anonymous"
|
||||||
|
}
|
||||||
|
$this.AddAttrs($el,$attrs)
|
||||||
|
$el.AppendChild($this.xmlDocument.CreateTextNode(""))
|
||||||
|
$this.xmlDocument.html.body.AppendChild($el)
|
||||||
|
}
|
||||||
|
AddBootStrapAtCompile() { #Bootstrap script needs to be added at the end
|
||||||
|
if($this.bootstrapAtCompile) {
|
||||||
|
$el = $this.xmlDocument.CreateElement("link")
|
||||||
|
$attrs = @{
|
||||||
|
"rel"="stylesheet";
|
||||||
|
"href"='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css';
|
||||||
|
"integrity"="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M";
|
||||||
|
"crossorigin"="anonymous"
|
||||||
|
}
|
||||||
|
$this.AddAttrs($el,$attrs)
|
||||||
|
$el.AppendChild($this.xmlDocument.CreateTextNode(""))
|
||||||
|
$this.xmlDocument.html.head.AppendChild($el)
|
||||||
|
$this.AddJSScript('https://code.jquery.com/jquery-3.2.1.slim.min.js',"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN")
|
||||||
|
$this.AddJSScript('https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js',"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4")
|
||||||
|
$this.AddJSScript('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js',"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[PowerStartHTML] AddContainerAttrToMain() {
|
||||||
|
$this.AddAttr($this.xmlDocument.html.body.ChildNodes[0],"class","container")
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
[PowerStartHTML] Append($elType = "table",$className=$null,[string]$text=$null) {
|
||||||
|
$el = $this.xmlDocument.CreateElement($elType)
|
||||||
|
if($text -ne $null) {
|
||||||
|
$el.AppendChild($this.xmlDocument.CreateTextNode($text))
|
||||||
|
}
|
||||||
|
if($className -ne $null) {
|
||||||
|
$this.AddAttr($el,"class",$className)
|
||||||
|
}
|
||||||
|
$this.lastEl.AppendChild($el)
|
||||||
|
$this.newEl = $el
|
||||||
|
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
[PowerStartHTML] Append($elType = "table",$className=$null) { return $this.Append($elType,$className,$null) }
|
||||||
|
[PowerStartHTML] Append($elType = "table") { return $this.Append($elType,$null,$null) }
|
||||||
|
[PowerStartHTML] Add($elType = "table",$className=$null,[string]$text=$null) {
|
||||||
|
$this.Append($elType,$className,$text)
|
||||||
|
$this.lastEl = $this.newEl
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
[PowerStartHTML] Add($elType = "table",$className=$null) { return $this.Add($elType,$className,$null) }
|
||||||
|
[PowerStartHTML] Add($elType = "table") { return $this.Add($elType,$null,$null) }
|
||||||
|
[PowerStartHTML] Main() {
|
||||||
|
$this.lastEl = $this.xmlDocument.html.body.ChildNodes[0];
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
[PowerStartHTML] Up() {
|
||||||
|
$this.lastEl = $this.lastEl.ParentNode;
|
||||||
|
return $this
|
||||||
|
}
|
||||||
|
N() {}
|
||||||
|
}
|
||||||
|
class PowerStartHTMLPassThroughLine {
|
||||||
|
$object;$cells
|
||||||
|
PowerStartHTMLPassThroughLine($object) {
|
||||||
|
$this.object = $object;
|
||||||
|
$this.cells = new-object System.Collections.HashTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PowerStartHTMLPassThroughElement {
|
||||||
|
$name;$text;$element;$id
|
||||||
|
PowerStartHTMLPassThroughElement($name,$text,$element,$id) {
|
||||||
|
$this.name = $name; $this.text = $text; $this.element = $element;$this.id = $id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function New-PowerStartHTML {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$title,
|
||||||
|
[switch]$nobootstrap=$false
|
||||||
|
)
|
||||||
|
$pshtml = (new-object PowerStartHTML($title))
|
||||||
|
if(-not $nobootstrap) {
|
||||||
|
$pshtml.AddBootStrap().AddContainerAttrToMain().N()
|
||||||
|
}
|
||||||
|
return $pshtml
|
||||||
|
}
|
||||||
|
function Add-PowerStartHTMLTable {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]$object,
|
||||||
|
[PowerStartHTML]$psHtml,
|
||||||
|
[string]$tableTitle = $null,
|
||||||
|
[string]$tableClass = $null,
|
||||||
|
[string]$idOverride = $(if($tableTitle -ne $null) {($tableTitle.toLower() -replace "[^a-z0-9]","-") }),
|
||||||
|
[switch]$passthroughTable = $false,
|
||||||
|
[switch]$noheaders = $false
|
||||||
|
)
|
||||||
|
begin {
|
||||||
|
if($tableTitle -ne $null) {
|
||||||
|
$psHtml.Main().Append("h1",$null,$tableTitle).N()
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id","header-$idOverride")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$psHtml.Main().Add("table").N()
|
||||||
|
[int]$r = 0
|
||||||
|
[int]$c = 0
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride")
|
||||||
|
}
|
||||||
|
if($tableClass -ne $null) {
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"class",$tableClass)
|
||||||
|
}
|
||||||
|
[bool]$isFirst = $true
|
||||||
|
}
|
||||||
|
process {
|
||||||
|
$c = 0
|
||||||
|
|
||||||
|
$props = $object | Get-Member -Type Properties
|
||||||
|
if(-not $noheaders -and $isFirst) {
|
||||||
|
$psHtml.Add("tr").N()
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride-trh")
|
||||||
|
}
|
||||||
|
$props | % {
|
||||||
|
$n = $_.Name;
|
||||||
|
$psHtml.Append("th",$null,$n).N()
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$cellid = "table-$idOverride-td-$r-$c"
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id",$cellid)
|
||||||
|
}
|
||||||
|
$c++
|
||||||
|
}
|
||||||
|
$c = 0
|
||||||
|
$psHtml.Up().N()
|
||||||
|
}
|
||||||
|
|
||||||
|
$psHtml.Add("tr").N()
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride-tr-$r")
|
||||||
|
}
|
||||||
|
$pstableln = [PowerStartHTMLPassThroughLine]::new($object)
|
||||||
|
|
||||||
|
$props | % {
|
||||||
|
$n = $_.Name;
|
||||||
|
$psHtml.Append("td",$null,$object."$n").N()
|
||||||
|
$cellid = $null
|
||||||
|
if($idOverride -ne $null) {
|
||||||
|
$cellid = "table-$idOverride-td-$r-$c"
|
||||||
|
$psHtml.AddAttr($psHtml.newEl,"id",$cellid)
|
||||||
|
}
|
||||||
|
if($passthroughTable) {
|
||||||
|
$pstableln.cells.Add($n,[PowerStartHTMLPassThroughElement]::new($n,($object."$n"),$psHtml.newEl,$cellid))
|
||||||
|
}
|
||||||
|
|
||||||
|
$c++
|
||||||
|
}
|
||||||
|
if($passthroughTable) {
|
||||||
|
$pstableln
|
||||||
|
}
|
||||||
|
$psHtml.Up().N()
|
||||||
|
$isFirst = $false
|
||||||
|
$r++
|
||||||
|
}
|
||||||
|
end {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Export-ModuleMember -Function @('New-PowerStartHTML','Add-PowerStartHTMLTable')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
$moduleRoot = Resolve-Path "$PSScriptRoot\.."
|
||||||
|
$moduleName = "VMware-vCD-TenantReport"
|
||||||
|
|
||||||
|
Describe "General project validation: $moduleName" {
|
||||||
|
|
||||||
|
$scripts = Get-ChildItem $moduleRoot -Include *.ps1, *.psm1, *.psd1 -Recurse
|
||||||
|
|
||||||
|
# TestCases are splatted to the script so we need hashtables
|
||||||
|
$testCase = $scripts | Foreach-Object {@{file = $_}}
|
||||||
|
It "Script <file> should be valid powershell" -TestCases $testCase {
|
||||||
|
param($file)
|
||||||
|
|
||||||
|
$file.fullname | Should Exist
|
||||||
|
|
||||||
|
$contents = Get-Content -Path $file.fullname -ErrorAction Stop
|
||||||
|
$errors = $null
|
||||||
|
$null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)
|
||||||
|
$errors.Count | Should Be 0
|
||||||
|
}
|
||||||
|
|
||||||
|
It "Module '$moduleName' can import cleanly" {
|
||||||
|
{Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -force } | Should Not Throw
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user