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