PSWriteHTML
PSWriteHTML copied to clipboard
Control New-DiagramLink arrow width
Dear Przemyslaw
Is it possible to control the width of an arrow between two nodes? I have written a little function that visualizes AD Site configuration and would like to have different arrow sizes based on site costs. Later I also want to add also option to click on a site / site link to get additional information. But that is a different topic;-)
The code currently looks like this:
`Import-Module PSWriteHTML -Force
New-HTML -TitleText 'AD Sites' -Online -FilePath $PSScriptRoot\ADSites.html {
New-HTMLSection {
New-HTMLDiagram -Height 800 {
New-DiagramOptionsPhysics -StabilizationEnabled $true -Solver repulsion
Get-ADReplicationSite -filter * |
ForEach-Object {
$Site = $_
Switch -Regex ($_.Name) {
"^Default-First-Site-Name$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
"^(MainSite-0|MainSite-2)$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
Default {New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" }
}
}
Get-ADReplicationSiteLink -filter * |
ForEach-Object {
If ( $_.SitesIncluded.count -lt 2 ) {
Write-Warning $( "Sitelink {0} has {1} sites included." -f $_.Name, $_.SitesIncluded.Count )
}
# Create all possible links
for ($i = 0; $i -lt $_.SitesIncluded.count; $i++) {
for ($n = ($i + 1); $n -lt $_.SitesIncluded.count; $n++) {
New-DiagramLink -From $_.SitesIncluded[$i] -To $_.SitesIncluded[$n] -Label $_.Name
}
}
}
} #-DisableLoadingBar
}
} -ShowHTML`
Thank you for your support. Patrick
Cool you could improve my Show-WinADSites

The way I usually deal with "costs" is to use hierarchical diagram. You then tell it the Level you want it on. 0,1,2,3,4,5,6 and so on. This way its much more readable. You could probably control width on non-hierarchical diagram but I am afraid things would get ugly.
I had a quick look into your new function. Think it gathers too much information when using it in large environments. It takes a long time. Of course it shows quite valuable information. But I would be first intersted in the connections:

Then, when selecting a site, the table could show me all subnets related to the site or all DCs responsible for this site. The reason I would like to have different line weights is to quickly show if one link is more costly than another. I could do this also by color I guess. First get all costs, see how many different costs there are and then assign a color to each. From Green with low costs to red with high costs. Bad for color blind people, but at least some indicator.
Is it possible to hide / unhide information in the graphic on click?
I did a quick rewrite of my version of the script to include your data table. It^s not ideal yet, like schedules is not resovled etc, and missing Subnets, but it took few seconds to build instead of, well, your version is still trying to show something ;-) Its a decission between speed and informations. I will look later in your version. I know you have example where you hide or show table information based on clicking the graphic. Would you mind pointing me to one?
Import-Module PSWriteHTML -Force
$Sites = Get-ADReplicationSite -filter *
$SiteLinks = Get-ADReplicationSiteLink -filter *
New-HTML -TitleText 'AD Sites' -Online -FilePath $PSScriptRoot\ADSites.html {
New-HTMLSectionStyle -BorderRadius 0px -HeaderBackGroundColor Grey -RemoveShadow
New-HTMLTableOption -DataStore HTML
New-HTMLTabStyle -BorderRadius 0px -TextTransform capitalize -BackgroundColorActive SlateGrey
New-HTMLTabPanel {
New-HTMLTab -TabName 'Standard' {
New-HTMLSection -HeaderText 'Organization Diagram' {
New-HTMLDiagram -Height 800 {
New-DiagramOptionsPhysics -StabilizationEnabled $true -Solver repulsion
$Sites |
ForEach-Object {
$Site = $_
Switch -Regex ($_.Name) {
"^Default-First-Site-Name$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
"^(MainSite-0|MainSite-2)$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
Default {New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" }
}
}
$SiteLinks |
ForEach-Object {
If ( $_.SitesIncluded.count -lt 2 ) {
Write-Warning $( "Sitelink {0} has {1} sites included." -f $_.Name, $_.SitesIncluded.Count )
}
# Create all possible links
for ($i = 0; $i -lt $_.SitesIncluded.count; $i++) {
for ($n = ($i + 1); $n -lt $_.SitesIncluded.count; $n++) {
New-DiagramLink -From $_.SitesIncluded[$i] -To $_.SitesIncluded[$n] -Label $_.Name
}
}
}
}
}
}
}
New-HTMLSection -Title "Information about Sites" {
New-HTMLTable -DataTable $Sites -Filtering {
if (-not $DisableBuiltinConditions) {
New-TableCondition -BackgroundColor MediumSeaGreen -ComparisonType number -Value 0 -Name SubnetsCount -Operator gt
New-TableCondition -BackgroundColor CoralRed -ComparisonType number -Value 0 -Name SubnetsCount -Operator eq
}
if ($Conditions) {
& $Conditions
}
} -DataTableID 'DT-StandardSites' -DataStore JavaScript
}
New-HTMLTable -DataTable $Replication -Filtering {
if (-not $DisableBuiltinConditions) {
New-TableCondition -BackgroundColor MediumSeaGreen -ComparisonType number -Value 0 -Name SubnetsCount -Operator gt
New-TableCondition -BackgroundColor CoralRed -ComparisonType number -Value 0 -Name SubnetsCount -Operator eq
}
if ($Conditions) {
& $Conditions
}
} -DataTableID 'DT-StandardSites1' -DataStore JavaScript
# }
} -ShowHTML
You should read this:
- https://evotec.xyz/nested-tabs-diagram-updates-diagram-events-calendar-object-and-more-in-pswritehtml/ - there's level + width shown
- https://evotec.xyz/advanced-html-reporting-using-powershell/ - shows table events for charts
Import-Module .\PSWriteHTML.psd1 -Force
$Processes = Get-Process | Select-Object -First 3 -Property Name, ProcessName, Id, FileVersion, WorkingSet
New-HTML -TitleText 'My Title' -Online -FilePath $PSScriptRoot\Example30-LinkedTableToTable02.html -ShowHTML {
New-HTMLTableOption -DataStore Javascript
New-HTMLSection -Invisible {
New-HTMLPanel {
New-HTMLTable -DataTable $Processes -DataTableID 'RandomID1' {
New-TableEvent -ID 'RandomID2' -SourceColumnID 0 -TargetColumnId 0
New-TableEvent -ID 'RandomID3' -SourceColumnID 0 -TargetColumnId 0
}
}
New-HTMLPanel {
New-HTMLTable -DataTable $Processes -DataTableID 'RandomID2'
}
}
New-HTMLPanel {
New-HTMLTable -DataTable $Processes -DataTableID 'RandomID3'
}
}
I played a little bit more around and it now looks quite good. Still I would be happy to be able to have different arrow weights ;-)
It is not yet ideal and it doesn't yet fit into your ADEssentials module, but let me know what you think. If possible I would like to hide the DNs, but I need them as unique reference. Sometimes the filter from last created HTML file is also used on a freshly opened document. The comparison of the \A0DEL to verify if a deleted object is referenced breaks the first table.
Import-Module PSWriteHTML -Force
$Subnets = Get-ADReplicationSubnet -Filter * | Select @{n='Site';e={ $_.Site -replace 'CN=(.*?),.*','$1' }}, @{n='Subnet';e={ $_.Name}}, Location, @{ n='SiteDN';e={$_.Site}}
$SubnetsHash = @{}
$Subnets | %{ if ( $SubnetsHash.ContainsKey($_.SiteDN) ) { $SubnetsHash[$_.SiteDN] += $_.Subnet } else { $SubnetsHash.Add( $_.SiteDN,@(,$_.Subnet) ) } }
$Sites = Get-ADReplicationSite -filter * |
Select-Object Name, Description,
@{ n="InterSiteTopologyGenerator";e={
if ( $_.InterSiteTopologyGenerator -match "\\0ADEL" ) {
$_.InterSiteTopologyGenerator } else {
try { Get-ADObject -searchbase "$($_.InterSiteTopologyGenerator -replace '.*?,(.*)$','$1' )" -SearchScope Base -Filter * -Properties dnsHostName | Select-Object -ExpandProperty dnsHostName } catch { } }
}},
@{ n='SubnetCount';e={ $SubnetsHash[$_.DistinguishedName].count } },
ManagedBy,
@{ n='hasSchedule';e={ if( $_.ReplicationSchedule ) {$true} else {$false} }},UniversalGroupCachingRefreshSite,
DistinguishedName
$SiteLinks = Get-ADReplicationSiteLink -filter * | Select-Object Name, Cost, ReplicationFrequencyInMinutes, SitesIncluded, DistinguishedName
$CostGroup = $SiteLinks | Group Cost -NoElement
$Script:LinkToSite = @()
New-HTML -TitleText 'AD Sites' -Online -FilePath $PSScriptRoot\ADSites.html {
New-HTMLSectionStyle -BorderRadius 0px -HeaderBackGroundColor Grey -RemoveShadow
New-HTMLTableOption -DataStore HTML
New-HTMLTabStyle -BorderRadius 0px -TextTransform capitalize -BackgroundColorActive SlateGrey
New-HTMLTabPanel {
New-HTMLTab -TabName 'Standard' {
New-HTMLSection -HeaderText 'Organization Diagram' {
New-HTMLDiagram -Height 800 {
New-DiagramOptionsPhysics -StabilizationEnabled $true -Solver repulsion
$Sites |
ForEach-Object {
$Site = $_
Switch -Regex ($_.Name) {
"^Default-First-Site-Name$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
"^(CHBS-0|USEH-0|INKL-0|SGSG-0)$" { New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" -ColorBackground Amber }
Default {New-DiagramNode -Label "$($Site.Name)" -Id "$($Site.DistinguishedName)" }
}
}
New-DiagramEvent -ID 'DT-Sites' -ColumnID 7
New-DiagramEvent -ID 'DT-Subnets' -ColumnID 3
New-DiagramEvent -ID 'DT-SiteLinks' -ColumnID 5
$SiteLinks |
ForEach-Object {
$SiteLink = $_
If ( $_.SitesIncluded.count -lt 2 ) {
Write-Warning $( "Sitelink {0} has {1} sites included." -f $_.Name, $_.SitesIncluded.Count )
$Script:LinkToSite += New-Object PSObject -Property ( [ordered] @{
linkedFrom = $_.SitesIncluded[0] -replace 'CN=(.*?),.*','$1'
linkedTo = ''
linkName = $_.Name
Cost = $_.Cost
ReplicationFrequencyInMinutes = $_.ReplicationFrequencyInMinutes
linkDN = $_.SitesIncluded[0]
} )
}
# Create all possible links
for ($i = 0; $i -lt $_.SitesIncluded.count; $i++) {
for ($n = ($i + 1); $n -lt $_.SitesIncluded.count; $n++) {
New-DiagramLink -From $_.SitesIncluded[$i] -To $_.SitesIncluded[$n] -Label $_.Name
$Script:LinkToSite += New-Object PSObject -Property ( [ordered] @{
linkedFrom = $_.SitesIncluded[$i] -replace 'CN=(.*?),.*','$1'
linkedTo = $_.SitesIncluded[$n] -replace 'CN=(.*?),.*','$1'
linkName = $_.Name
Cost = $_.Cost
ReplicationFrequencyInMinutes = $_.ReplicationFrequencyInMinutes
linkDN = $_.SitesIncluded[$i]
} )
# To be able to select either site, the link information needs to be added twice
$Script:LinkToSite += New-Object PSObject -Property ( [ordered] @{
linkedFrom = $_.SitesIncluded[$i] -replace 'CN=(.*?),.*','$1'
linkedTo = $_.SitesIncluded[$n] -replace 'CN=(.*?),.*','$1'
linkName = $_.Name
Cost = $_.Cost
ReplicationFrequencyInMinutes = $_.ReplicationFrequencyInMinutes
linkDN = $_.SitesIncluded[$n]
} )
}
}
}
}
}
}
}
New-HTMLSection -Title "Information about Sites" {
New-HTMLTable -DataTable $Sites -Filtering {
New-TableColumnOption -Hidden $true -ColumnIndex 1
if (-not $DisableBuiltinConditions) {
New-TableCondition -BackgroundColor MediumSeaGreen -ComparisonType number -Value 0 -Name SubnetCount -Operator gt
New-TableCondition -BackgroundColor CoralRed -ComparisonType number -Value 0 -Name SubnetCount -Operator eq
# New-TableCondition -BackgroundColor MediumSeaGreen -ComparisonType string -Value '*\0ADEL*' -Name InterSiteTopologyGenerator -Operator notlike
# New-TableCondition -BackgroundColor CoralRed -ComparisonType string -Value '*\0ADEL*' -Name InterSiteTopologyGenerator -Operator like
}
if ($Conditions) {
& $Conditions
}
} -DataTableID 'DT-Sites' -DataStore JavaScript
New-HTMLTable -DataTable $Subnets -Filtering {
# New-TableColumnOption -Hidden $true -ColumnIndex 0
} -DataTableID 'DT-Subnets' -DataStore JavaScript
New-HTMLTable -DataTable $Script:LinkToSite -Filtering {
# New-TableColumnOption -Hidden $true -ColumnIndex 2
} -DataTableID 'DT-SiteLinks' -DataStore JavaScript
}
} -ShowHTML