Src/Private/Get-AbrVb365Diagram.ps1
|
function Get-AbrVb365Diagram { <# .SYNOPSIS Diagram the configuration of Veeam Backup for Microsoft 365 infrastructure in PDF/SVG/DOT/PNG formats using PSGraph and Graphviz. .DESCRIPTION Diagram the configuration of Veeam Backup for Microsoft 365 infrastructure in PDF/SVG/DOT/PNG formats using PSGraph and Graphviz. .NOTES Version: 0.4.0 Author(s): Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux Credits: Kevin Marquette (@KevinMarquette) - PSGraph module Credits: Prateek Singh (@PrateekKumarSingh) - AzViz module .LINK https://github.com/rebelinux/ https://github.com/KevinMarquette/PSGraph https://github.com/PrateekKumarSingh/AzViz #> begin { # Used for DiagramDebug if ($Options.EnableDiagramDebug) { $EdgeDebug = @{style = 'filled'; color = 'red' } $SubGraphDebug = @{style = 'dashed'; color = 'red' } $NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' } $NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' } $IconDebug = $true } else { $EdgeDebug = @{style = 'invis'; color = 'red' } $SubGraphDebug = @{style = 'invis'; color = 'gray' } $NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' } $NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' } $IconDebug = $false } # Used to set diagram theme if ($Options.DiagramTheme -eq 'Black') { $MainGraphBGColor = 'Black' $TableBorderColor = 'White' $Edgecolor = 'White' $Fontcolor = 'White' $NodeFontcolor = 'White' $EdgeArrowSize = 1 $EdgeLineWidth = 3 $BackupServerBGColor = 'Black' $BackupServerFontColor = 'White' } elseif ($Options.DiagramTheme -eq 'Neon') { $MainGraphBGColor = 'grey14' $TableBorderColor = 'gold2' $Edgecolor = 'gold2' $Fontcolor = 'gold2' $NodeFontcolor = 'gold2' $EdgeArrowSize = 1 $EdgeLineWidth = 3 $BackupServerBGColor = 'grey14' $BackupServerFontColor = 'gold2' } elseif ($Options.DiagramTheme -eq 'White') { $MainGraphBGColor = 'White' $TableBorderColor = '#71797E' $Edgecolor = '#71797E' $Fontcolor = '#565656' $NodeFontcolor = 'Black' $EdgeArrowSize = 1 $EdgeLineWidth = 3 $BackupServerBGColor = switch ($NewIcons) { $true { '#dbdddf' } $false { '#ceedc4' } } $BackupServerFontColor = switch ($NewIcons) { $true { '#565656' } $false { '#007F49' } } } } process { #-----------------------------------------------------------------------------------------------# # Graphviz Node Section # # Nodes are Graphviz elements used to define a object entity # # Nodes can have attribues like Shape, HTML Labels, Styles etc.. # # PSgraph: https://psgraph.readthedocs.io/en/latest/Command-Node/ # # Graphviz: https://graphviz.org/doc/info/shapes.html # #-----------------------------------------------------------------------------------------------# $ServerVersion = if ($script:VBOversion) { $script:VBOversion } else { (Get-VBOVersion).ProductVersion } $ServerInfo = @{ 'Version' = switch ([string]::IsNullOrEmpty($ServerVersion)) { $true { 'Unknown' } $false { $ServerVersion } default { 'Unknown' } } } $ServerConfigRestAPI = if ($script:ServerConfigRestAPI) { $script:ServerConfigRestAPI } else { Get-VBORestAPISettings } if ($ServerConfigRestAPI.IsServiceEnabled) { $ServerInfo.Add('RestAPI Port', $ServerConfigRestAPI.HTTPSPort) } # VB365 Server Object Node VB365Server @{Label = Add-NodeIcon -AditionalInfo $ServerInfo -ImagesObj $Images -Name $VeeamBackupServer -IconType 'VB365_Server' -Align 'Center' -IconDebug $IconDebug -FontSize 24 -FontColor $Fontcolor -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor; shape = 'plain'; fillColor = 'transparent'; fontsize = 24 } $RestorePortal = if ($script:RestorePortal) { $script:RestorePortal } else { Get-VBORestorePortalSettings } if ($RestorePortal.IsServiceEnabled) { $RestorePortalURL = @{ 'Portal URI' = $RestorePortal.PortalUri } Node VB365RestorePortal @{Label = Add-NodeIcon -AditionalInfo $RestorePortalURL -ImagesObj $Images -Name 'Self-Service Portal' -IconType 'VB365_Restore_Portal' -Align 'Center' -IconDebug $IconDebug -FontSize 24 -FontColor $Fontcolor -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor; shape = 'plain'; fillColor = 'transparent'; fontsize = 18; url = $RestorePortal.PortalUri } } # Proxy Graphviz Cluster try { $ProxiesInfo = @() if ($script:Proxies) { $Proxies = $script:Proxies } else { $Proxies = Get-VBOProxy -WarningAction SilentlyContinue | Sort-Object -Property Hostname $script:Proxies = $Proxies } $Proxies | ForEach-Object { $inobj = [PSCustomObject] [ordered] @{ 'Type' = $_.Type 'Port' = "TCP/$($_.Port)" 'OS' = $_.OperatingSystemKind } $ProxiesInfo += $inobj } $ProxyNodes = Node Proxies @{Label = (Add-HtmlNodeTable -Name 'Proxies' -ImagesObj $Images -inputObject ($Proxies.HostName | ForEach-Object { $_.split('.')[0] }) -Align 'Center' -iconType 'VB365_Proxy_Server' -ColumnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $ProxiesInfo -Subgraph -SubgraphIconType 'VB365_Proxy' -SubgraphLabel 'Backup Proxies' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphLabelFontSize 28 -FontSize 24 -SubgraphFontBold -FontColor $Fontcolor -SubgraphLabelFontColor $Fontcolor -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } } catch { Write-PScriboMessage -Message 'Error: Unable to create Proxies Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } if ($Proxies -and $ProxyNodes) { $ProxyNodes } else { SubGraph ProxyServer -Attributes @{Label = (Add-HtmlLabel -ImagesObj $Images -Label 'Backup Proxies' -IconType 'VB365_Proxy' -SubgraphLabel -IconDebug $IconDebug); fontsize = 24; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { Node -Name Proxies -Attributes @{Label = 'No Backup Proxies'; shape = 'rectangle'; labelloc = 'c'; fixedsize = $true; width = '3'; height = '2'; fillColor = 'transparent'; penwidth = 0 } } } # Proxy Pools Graphviz Cluster try { if ($script:ProxyPools) { $ProxyPools = $script:ProxyPools } else { $ProxyPools = Get-VBOProxyPool -WarningAction SilentlyContinue | Sort-Object -Property Name $script:ProxyPools = $ProxyPools } $ProxyPoolNodes = foreach ($ProxyPool in $ProxyPools) { Add-HtmlTable -Name ('ProxyPool_{0}' -f ([regex]::Replace([string] $ProxyPool.Name, '[^A-Za-z0-9_]+', '_').Trim('_'))) -ImagesObj $Images -Rows ($ProxyPool.Proxies.Hostname | ForEach-Object { $_.Split('.')[0] }) -ALIGN 'Center' -ColumnSize 2 -IconDebug $IconDebug -Subgraph -SubgraphIconType 'VB365_Proxy_Server' -SubgraphLabel $ProxyPool.Name -SubgraphLabelPos 'top' -FontColor $Fontcolor -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphTableStyle 'dashed,rounded' -NoFontBold -SubgraphLabelFontsize 28 -FontSize 24 -SubgraphFontBold -SubgraphFontColor $Fontcolor -TableBackgroundColor $MainGraphBGColor } } catch { Write-PScriboMessage -Message 'Error: Unable to create Proxies Pool Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } if ($ProxyPools -and $ProxyPoolNodes) { $ProxyPoolSubgraphNode = Node -Name 'ProxyPools' -Attributes @{Label = (Add-HtmlSubGraph -Name 'ProxyPools' -ImagesObj $Images -TableArray $ProxyPoolNodes -Align 'Center' -IconDebug $IconDebug -IconType 'VB365_Proxy' -Label 'Backup Proxy Pools' -LabelPos 'top' -FontColor $Fontcolor -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 2 -FontSize 28 -FontBold -TableBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } if ($ProxyPoolSubgraphNode) { $ProxyPoolSubgraphNode } } # Restore Operator Graphviz Cluster try { if ($script:RestoreOperators) { $RestoreOperators = $script:RestoreOperators } else { $script:RestoreOperators = try { Get-VBORbacRole | Sort-Object -Property Name } catch { Out-Null } $RestoreOperators = $script:RestoreOperators } if ($RestoreOperators) { $RestoreOperatorOrganizations = if ($script:Organizations) { $script:Organizations } else { Get-AbrVb365OrganizationInventory } $RestoreOperatorsInfo = @() $RestoreOperators | ForEach-Object { $OrgId = $_.OrganizationId $inobj = @{ 'Organization' = switch ([string]::IsNullOrEmpty(($RestoreOperatorOrganizations | Where-Object { $_.Id -eq $OrgId }))) { $true { 'Unknown' } $false { ($RestoreOperatorOrganizations | Where-Object { $_.Id -eq $OrgId }).Name } default { 'Unknown' } } } $RestoreOperatorsInfo += $inobj } $RestoreOperatorsNodes = Node RestoreOperators @{Label = (Add-HtmlNodeTable -Name 'RestoreOperators' -ImagesObj $Images -inputObject $RestoreOperators.Name -Align 'Center' -iconType 'VB365_User' -ColumnSize 2 -IconDebug $IconDebug -MultiIcon -AditionalInfo $RestoreOperatorsInfo -Subgraph -SubgraphIconType 'VB365_User' -SubgraphLabel 'Restore Operators' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -FontColor $Fontcolor -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphFontBold -SubgraphLabelFontColor $Fontcolor -SubgraphLabelFontSize 28 -FontSize 24 -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } } } catch { Write-PScriboMessage -Message 'Error: Unable to create RestoreOperators Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } if ($RestoreOperators -and $RestoreOperatorsNodes) { $RestoreOperatorsNodes } else { SubGraph RestoreOp -Attributes @{Label = (Add-HtmlLabel -ImagesObj $Images -Label 'Restore Operators' -IconType 'VB365_User_Group' -SubgraphLabel -IconDebug $IconDebug); fontsize = 24; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { Node -Name RestoreOperators -Attributes @{Label = 'No Restore Operators'; shape = 'rectangle'; labelloc = 'c'; fixedsize = $true; width = '3'; height = '2'; fillColor = 'transparent'; penwidth = 0 } } } # Repositories Graphviz Cluster try { $Repositories = Get-AbrVb365BackupRepositoryInventory $RepositoriesInfo = @() foreach ($Repository in $Repositories) { if ($Repository.ObjectStorageRepository.Name) { $ObjStorage = $Repository.ObjectStorageRepository.Name } else { $ObjStorage = 'None' } $inobj = [PSCustomObject] [ordered] @{ # 'Path' = $Repository.Path 'Capacity' = ConvertTo-FileSizeString $Repository.Capacity 'Free Space' = ConvertTo-FileSizeString $Repository.FreeSpace 'ObjectStorage' = $ObjStorage } $RepositoriesInfo += $inobj } $RepositoriesNodes = Node Repositories @{Label = (Add-HtmlNodeTable -Name 'Repositories' -ImagesObj $Images -inputObject $Repositories.Name -Align 'Center' -iconType 'VB365_Repository' -ColumnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $RepositoriesInfo -Subgraph -SubgraphIconType 'Veeam_Repository' -SubgraphLabel 'Backup Repositories' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -FontColor $Fontcolor -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphFontBold -SubgraphLabelFontColor $Fontcolor -SubgraphLabelFontSize 28 -FontSize 24 -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } } catch { Write-PScriboMessage -Message 'Error: Unable to create Repositories Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } if ($Repositories -and $RepositoriesNodes) { $RepositoriesNodes } else { SubGraph Repos -Attributes @{Label = (Add-HtmlLabel -ImagesObj $Images -Label 'Backup Repositories' -IconType 'Veeam_Repository' -SubgraphLabel -IconDebug $IconDebug -TableBackgroundColor $MainGraphBGColor); fontsize = 24; penwidth = 1.5; labelloc = 'b'; style = 'dashed,rounded' } { Node -Name Repositories -Attributes @{Label = 'No Backup Repositories'; shape = 'rectangle'; labelloc = 'c'; fixedsize = $true; width = '3'; height = '2'; fillColor = 'transparent'; penwidth = 0 } } } # Object Repositories Graphviz Cluster try { $ObjectRepositories = Get-AbrVb365ObjectStorageRepository $ObjectRepositoriesInfo = @() $ORIconType = @() $ObjectRepositories | ForEach-Object { $inobj = [PSCustomObject] [ordered] @{ 'Type' = $_.Type 'Folder' = $_.Folder 'Immutability' = $_.EnableImmutability } $ObjectRepositoriesInfo += $inobj $ORIconType += switch ($_.Type) { 'AmazonS3' { 'VBR365_Amazon_S3' } 'AmazonS3Compatible' { 'VBR365_Amazon_S3_Compatible' } 'AzureBlob' { 'VBR365_Azure_Blob' } default { 'VBR365_Amazon_S3_Compatible' } } } $ObjectRepositoriesNodes = Node ObjectRepositories @{Label = (Add-HtmlNodeTable -Name 'ObjectRepositories' -ImagesObj $Images -inputObject $ObjectRepositories.Name -Align 'Center' -iconType $ORIconType -ColumnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $ObjectRepositoriesInfo -Subgraph -SubgraphIconType 'VB365_Object_Support' -SubgraphLabel 'Object Repositories' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -FontColor $Fontcolor -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphFontBold -SubgraphLabelFontColor $Fontcolor -SubgraphLabelFontSize 28 -FontSize 24 -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } } catch { Write-PScriboMessage -Message 'Error: Unable to create ObjectRepositories Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } if ($ObjectRepositories -and $ObjectRepositoriesNodes) { $ObjectRepositoriesNodes } else { SubGraph ObjectRepos -Attributes @{Label = (Add-HtmlLabel -ImagesObj $Images -Label 'Object Repositories' -IconType 'VB365_Object_Support' -SubgraphLabel -IconDebug $IconDebug -TableBackgroundColor $MainGraphBGColor); fontsize = 24; penwidth = 1.5; labelloc = 't'; style = 'dashed,rounded' } { Node -Name ObjectRepositories -Attributes @{Label = 'No Object Repositories'; shape = 'rectangle'; labelloc = 'c'; fixedsize = $true; width = '3'; height = '2'; fillColor = 'transparent'; penwidth = 0 } } } # Organization Graphviz Cluster try { $Organizations = Get-AbrVb365OrganizationInventory $OrganizationsInfo = @() ($Organizations | Where-Object { $_.Type -eq 'OnPremises' }) | ForEach-Object { $inobj = [PSCustomObject] [ordered] @{ 'Users' = "Licensed: $($_.LicensingOptions.LicensedUsersCount) - Trial: $($_.LicensingOptions.TrialUsersCount)" 'BackedUp' = ConvertTo-TextYN $_.IsBackedUp } $OrganizationsInfo += $inobj } if ($OrganizationsInfo) { $OnPremisesNode = Add-HtmlNodeTable -Name 'OnPremisesOrganizations' -ImagesObj $Images -inputObject ($Organizations | Where-Object { $_.Type -eq 'OnPremises' }).Name -Align 'Center' -iconType 'Datacenter' -ColumnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $OrganizationsInfo -Subgraph -SubgraphIconType 'VB365_On_Premises' -SubgraphLabel 'On-premises' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -FontColor $Fontcolor -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphFontBold -SubgraphLabelFontColor $Fontcolor -SubgraphLabelFontSize 28 -FontSize 24 -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor } } catch { Write-PScriboMessage -Message 'Error: Unable to create OnPremises Organization Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } try { $OrganizationsInfo = @() ($Organizations | Where-Object { $_.Type -eq 'Office365' }) | ForEach-Object { $inobj = [PSCustomObject] [ordered] @{ 'Users' = "Licensed: $($_.LicensingOptions.LicensedUsersCount) - Trial: $($_.LicensingOptions.TrialUsersCount)" 'BackedUp' = ConvertTo-TextYN $_.IsBackedUp } $OrganizationsInfo += $inobj } if ($OrganizationsInfo) { $Microsoft365Node = Add-HtmlNodeTable -Name 'Microsoft365Organizations' -ImagesObj $Images -inputObject ($Organizations | Where-Object { $_.Type -eq 'Office365' }).Name -Align 'Center' -iconType 'Microsoft_365' -ColumnSize 3 -IconDebug $IconDebug -MultiIcon -AditionalInfo $OrganizationsInfo -Subgraph -SubgraphIconType 'VB365_Microsoft_365' -SubgraphLabel 'Microsoft 365' -SubgraphLabelPos 'top' -SubgraphTableStyle 'dashed,rounded' -FontColor $Fontcolor -TableBorderColor $Edgecolor -TableBorder '1' -SubgraphFontBold -SubgraphLabelFontColor $Fontcolor -SubgraphLabelFontSize 28 -FontSize 24 -TableBackgroundColor $MainGraphBGColor -CellBackgroundColor $MainGraphBGColor } } catch { Write-PScriboMessage -Message 'Error: Unable to create Microsoft365 Organization Objects. Disabling the section' Write-PScriboMessage -Message "Error Message: $($_.Exception.Message)" } $OrganizationsInfo = @() # On-Premises Organization Graphviz Cluster if (($Organizations | Where-Object { $_.Type -eq 'OnPremises' }) -and $OnPremisesNode) { $OrganizationsInfo += $OnPremisesNode } # Microsoft 365 Organization Graphviz Cluster if (($Organizations | Where-Object { $_.Type -eq 'Office365' }) -and $Microsoft365Node) { $OrganizationsInfo += $Microsoft365Node } if ($OrganizationsInfo) { $OrganizationNode = Node -Name 'Organizations' -Attributes @{Label = (Add-HtmlSubGraph -Name 'Organizations' -ImagesObj $Images -TableArray $OrganizationsInfo -Align 'Center' -IconDebug $IconDebug -IconType 'VB365_On_Premises' -Label 'Organizations' -LabelPos 'top' -FontColor $Fontcolor -TableStyle 'dashed,rounded' -TableBorderColor $Edgecolor -TableBorder '1' -ColumnSize 3 -FontSize 28 -FontBold -TableBackgroundColor $MainGraphBGColor); shape = 'plain'; fillColor = 'transparent'; fontsize = 18; fontname = 'Segoe Ui' } if ($OrganizationNode) { $OrganizationNode } } if ($Options.DiagramTheme -eq 'Black') { $NodeFillColor = 'White' } elseif ($Options.DiagramTheme -eq 'Neon') { $NodeFillColor = 'Gold2' } else { $NodeFillColor = '#71797E' } # Veeam VB365 elements point of connection (Dummy Nodes!) $Node = @('VB365ServerPointSpace', 'VB365ProxyPoint', 'VB365ProxyPointSpace', 'VB365RepoPoint') Node $Node -NodeScript { $_ } @{Label = { $_ } ; fontcolor = $NodeDebug.color; fillColor = $NodeFillColor; shape = $NodeDebug.shape } $NodeStartEnd = @('VB365StartPoint', 'VB365EndPointSpace') Node $NodeStartEnd -NodeScript { $_ } @{Label = { $_ } ; fillColor = $NodeFillColor; fontcolor = $NodeDebug.color; shape = 'point'; fixedsize = 'true'; width = .2 ; height = .2 } #---------------------------------------------------------------------------------------------# # Graphviz Rank Section # # Rank allow to put Nodes on the same group level # # PSgraph: https://psgraph.readthedocs.io/en/stable/Command-Rank-Advanced/ # # Graphviz: https://graphviz.org/docs/attrs/rank/ # #---------------------------------------------------------------------------------------------# # Put the dummy node in the same rank to be able to create a horizontal line Rank VB365ServerPointSpace, VB365ProxyPoint, VB365ProxyPointSpace, VB365RepoPoint, VB365StartPoint, VB365EndPointSpace if ($RestorePortal.IsServiceEnabled) { # Put the VB365Server and the VB365RestorePortal in the same level to align it horizontally Rank VB365RestorePortal, VB365Server } #---------------------------------------------------------------------------------------------# # Graphviz Edge Section # # Edges are Graphviz elements use to interconnect Nodes # # Edges can have attribues like Shape, Size, Styles etc.. # # PSgraph: https://psgraph.readthedocs.io/en/latest/Command-Edge/ # # Graphviz: https://graphviz.org/docs/edges/ # #---------------------------------------------------------------------------------------------# # Connect the Dummy Node in a straight line # VB365StartPoint --- VB365ServerPointSpace --- VB365ProxyPoint --- VB365ProxyPointSpace --- VB365RepoPoint --- VB365EndPointSpace Edge -From VB365StartPoint -To VB365ServerPointSpace @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VB365ServerPointSpace -To VB365ProxyPoint @{minlen = 18; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VB365ProxyPoint -To VB365ProxyPointSpace @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VB365ProxyPointSpace -To VB365RepoPoint @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } Edge -From VB365RepoPoint -To VB365EndPointSpace @{minlen = 12; arrowtail = 'none'; arrowhead = 'none'; style = 'filled' } # Connect Veeam Backup server to the Dummy line Edge -From VB365Server -To VB365ServerPointSpace @{minlen = 4; arrowtail = 'dot'; arrowhead = 'none'; style = 'dashed' } # Connect Veeam Backup server to RetorePortal if ($RestorePortal.IsServiceEnabled -and $RestoreOperatorsNodes) { Edge -From VB365Server -To VB365RestorePortal @{minlen = 4; arrowtail = 'dot'; arrowhead = 'normal'; style = 'dashed'; color = '#DF8c42' } } # Connect Veeam Backup Server to Organization Graphviz Cluster if ($OrganizationNode) { Edge -To VB365Server -From Organizations @{minlen = 4; arrowtail = 'dot'; arrowhead = 'normal'; style = 'dashed'; color = '#DF8c42' } } # Connect Veeam RestorePortal to the Restore Operators Edge -From VB365ServerPointSpace -To RestoreOperators @{minlen = 4; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } # Connect Veeam Proxies Server to the Dummy line Edge -From VB365ProxyPoint -To Proxies @{minlen = 4; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } if ($ProxyPools -and $ProxyPoolNodes) { Edge -From Proxies -To ProxyPools @{minlen = 2; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } } # Connect Veeam Repository to the Dummy line Edge -From VB365RepoPoint -To Repositories @{minlen = 4; arrowtail = 'none'; arrowhead = 'dot'; style = 'dashed' } # Connect Veeam Object Repository to the Dummy line Edge -To VB365RepoPoint -From ObjectRepositories @{minlen = 4; arrowtail = 'dot'; arrowhead = 'none'; style = 'dashed' } # End results example # #------------------------------------------------------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------------------------------------------------------ # |---------------------------------------------------| ^ # | |---------------------------------------------| | | # | | Subgraph Logo | Organization | | | # | |---------------------------------------------| | MainGraph Cluster Board # ----------------------o| | Onpremise Table | Microsoft 365 Table | | # | | |---------------------------------------------| | # | |---------------------------------------------------| # | Organization Graphviz Cluster # | # \-/ # | # |--------------| # | ICON | # |--------------| # | VB365 Server | <--- Graphviz Node Example # |--------------| # | Version: | # |--------------| # O Dummy Nodes # | | # | | # | \|/ # VB365StartPoint --- VB365ServerPointSpace --- VB365ProxyPoint --- VB365ProxyPointSpace --- VB365RepoPoint --- VB365EndPointSpace # | # | <--- Graphviz Edge Example # | # O # |------------------------------------| # | |------------------------------| | # | | ICON | ICON | | # | |------------------------------| | # | | Proxy Server | Proxy Server | | <--- Graphviz Cluster Example # | |------------------------------| | # | | Subgraph Logo | Backup Proxy | | # | |------------------------------| | # |------------------------------------| # Proxy Graphviz Cluster # #-------------------------------------------------------------------------------------------------------------------------------------- # |---------------------------| # |--------- | # | | Author Name | # Signature -----> | Logo | | # | | Company Name | # |--------- | # |---------------------------| #-------------------------------------------------------------------------------------------------------------------------------------- # ^ # | # | # OUTERDRAWBOARD1 Cluster Board } } |