Src/Public/New-VeeamDiagram.ps1

function New-VeeamDiagram {
    <#
    .SYNOPSIS
        Generates comprehensive diagrams of Veeam Backup & Replication (VBR) infrastructure in multiple formats using PSGraph and Graphviz.
 
    .DESCRIPTION
        This script automates the creation of detailed visual diagrams representing the architecture and relationships within a Veeam Backup & Replication environment. It supports various diagram types and output formats, enabling administrators to visualize backup infrastructure components, their connections, and data flows. Customization options include layout direction, themes, node and section separation, edge styles, and branding elements such as logos and watermarks.
 
    .PARAMETER DiagramType
        Specifies the type of Veeam VBR diagram to generate.
        Supported values:
            - 'Backup-to-Sobr'
            - 'Backup-to-vSphere-Proxy'
            - 'Backup-to-HyperV-Proxy'
            - 'Backup-to-Repository'
            - 'Backup-to-WanAccelerator'
            - 'Backup-to-Tape'
            - 'Backup-to-File-Proxy'
            - 'Backup-to-ProtectedGroup'
            - 'Backup-Infrastructure'
 
    .PARAMETER Target
        One or more IP addresses or FQDNs of Veeam VBR servers to connect to.
        Multiple targets can be specified, separated by commas.
 
    .PARAMETER Port
        Optional. The port number for connecting to the Veeam VBR Service.
        Default: 9392
 
    .PARAMETER Credential
        A PSCredential object containing the username and password for authentication to the target system.
 
    .PARAMETER Username
        The username for authenticating to the target system. Used if Credential is not provided.
 
    .PARAMETER Password
        The password for authenticating to the target system. Used if Credential is not provided.
 
    .PARAMETER Format
        Specifies one or more output formats for the generated diagram.
        Supported values: PDF, PNG, DOT, SVG
        Multiple formats can be specified, separated by commas.
 
    .PARAMETER Direction
        Sets the layout direction of the diagram.
        Supported values: 'top-to-bottom', 'left-to-right'
        Default: 'top-to-bottom'
 
    .PARAMETER Theme
        Sets the visual theme of the diagram.
        Supported values: 'Black', 'White', 'Neon'
        Default: 'White'
 
    .PARAMETER NodeSeparation
        Adjusts the spacing between nodes in the diagram.
        Default: 0.60
 
    .PARAMETER SectionSeparation
        Adjusts the spacing between sections (subgraphs) in the diagram.
        Default: 0.75
 
    .PARAMETER EdgeType
        Defines the style of edge lines connecting nodes.
        Supported values: 'polyline', 'curved', 'ortho', 'line', 'spline'
        Default: 'spline'
        See: https://graphviz.org/docs/attrs/splines/
 
    .PARAMETER OutputFolderPath
        The directory path where the generated diagram files will be saved.
 
    .PARAMETER Filename
        The base filename for the generated diagram files.
 
    .PARAMETER EnableEdgeDebug
        Switch. Enables debugging visualization for edges (e.g., dummy edge and node lines).
 
    .PARAMETER EnableSubGraphDebug
        Switch. Enables debugging visualization for subgraphs (e.g., subgraph boundary lines).
 
    .PARAMETER EnableErrorDebug
        Switch. Enables detailed error debugging output.
 
    .PARAMETER AuthorName
        The name of the author to include in the diagram footer signature.
 
    .PARAMETER CompanyName
        The company name to include in the diagram footer signature.
 
    .PARAMETER Logo
        Path to a custom logo image to replace the default Veeam logo.
        Recommended size: 400px x 100px or smaller.
 
    .PARAMETER SignatureLogo
        Path to a custom signature logo image for the diagram footer.
        Recommended size: 120px x 130px or smaller.
 
    .PARAMETER Signature
        Switch. Adds a footer signature to the diagram. Requires AuthorName and CompanyName.
 
    .PARAMETER WatermarkText
        Text to be used as a watermark on the output image (not supported for SVG format).
 
    .PARAMETER WatermarkColor
        The color of the watermark text.
        Default: 'Green'
 
    .PARAMETER ColumnSize
        Sets the number of columns in the node table layout.
        Default: 4
 
    .EXAMPLE
        New-VeeamDiagram -DiagramType 'Backup-Infrastructure' -Target 'vbr01.contoso.com' -Format 'PDF,PNG' -Theme 'Neon' -OutputFolderPath 'C:\Diagrams'
 
    .NOTES
        Requires PSGraph and Graphviz to be installed and available in the system path.
        For best results, ensure all image assets meet the recommended size guidelines.
 
    .NOTES
        Version: 0.6.29
        Author(s): Jonathan Colon
        Twitter: @jcolonfzenpr
        Github: rebelinux
        Credits: Kevin Marquette (@KevinMarquette) - PSGraph module
                        Prateek Singh (@PrateekKumarSingh) - AzViz module
 
    .LINK
        https://github.com/rebelinux/Veeam.Diagrammer
        https://github.com/KevinMarquette/PSGraph
        https://github.com/PrateekKumarSingh/AzViz
    #>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Scope = "Function")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "", Scope = "Function")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "", Scope = "Function")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope = "Function")]

    [CmdletBinding(
        PositionalBinding = $false,
        DefaultParameterSetName = 'Credential'
    )]

    #Requires -Version 5.1
    #Requires -PSEdition Desktop
    #Requires -RunAsAdministrator

    param (

        [Parameter(
            Position = 0,
            Mandatory = $true,
            HelpMessage = 'Please provide the IP/FQDN of the system'
        )]
        [ValidateNotNullOrEmpty()]
        [Alias('Server', 'IP')]
        [String[]] $Target,

        [Parameter(
            Position = 1,
            Mandatory = $true,
            HelpMessage = 'Please provide credentials to connect to the system',
            ParameterSetName = 'Credential'
        )]
        [ValidateNotNullOrEmpty()]
        [PSCredential] $Credential,

        [Parameter(
            Position = 2,
            Mandatory = $true,
            HelpMessage = 'Please provide the username to connect to the target system',
            ParameterSetName = 'UsernameAndPassword'
        )]
        [ValidateNotNullOrEmpty()]
        [String] $Username,

        [Parameter(
            Position = 3,
            Mandatory = $false,
            HelpMessage = 'Please provide the password to connect to the target system',
            ParameterSetName = 'UsernameAndPassword'
        )]
        [ValidateNotNullOrEmpty()]
        [String] $Password,

        [Parameter(
            Position = 4,
            Mandatory = $false,
            HelpMessage = 'Please provide the diagram output format'
        )]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('pdf', 'svg', 'png', 'dot', 'base64', 'jpg')]
        [Array] $Format = 'pdf',

        [Parameter(
            Position = 5,
            Mandatory = $false,
            HelpMessage = 'TCP Port of target Veeam Backup Server'
        )]
        [string] $Port = '9392',

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Use it to set the diagram theme. (Black/White/Neon)'
        )]
        [ValidateSet('Black', 'White', 'Neon')]
        [string] $DiagramTheme = 'White',

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Direction in which resource are plotted on the visualization'
        )]
        [ValidateSet('left-to-right', 'top-to-bottom')]
        [string] $Direction = 'top-to-bottom',

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Please provide the path to the diagram output file'
        )]
        [ValidateScript( {
                if (Test-Path -Path $_) {
                    $true
                } else {
                    throw "Path $_ not found!"
                }
            })]
        [string] $OutputFolderPath = [System.IO.Path]::GetTempPath(),

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Please provide the path to the custom logo used for Signature'
        )]
        [ValidateScript( {
                if (Test-Path -Path $_) {
                    $true
                } else {
                    throw "File $_ not found!"
                }
            })]
        [string] $SignatureLogo,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Please provide the path to the custom logo'
        )]
        [ValidateScript( {
                if (Test-Path -Path $_) {
                    $true
                } else {
                    throw "File $_ not found!"
                }
            })]
        [string] $Logo,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Specify the Diagram filename'
        )]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
                if (($Format | Measure-Object).count -lt 2) {
                    $true
                } else {
                    throw "Format value must be unique if Filename is especified."
                }
            })]
        [String] $Filename,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Controls how edges lines appear in visualization'
        )]
        [ValidateSet('polyline', 'curved', 'ortho', 'line', 'spline')]
        [string] $EdgeType = 'spline',

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Controls Node separation ratio in visualization'
        )]
        [ValidateSet(0, 1, 2, 3)]
        [string] $NodeSeparation = .60,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Controls Section (Subgraph) separation ratio in visualization'
        )]
        [ValidateSet(0, 1, 2, 3)]
        [string] $SectionSeparation = .75,

        [Parameter(
            Mandatory = $true,
            HelpMessage = 'Controls type of Veeam VBR generated diagram'
        )]
        [ValidateSet('Backup-to-Tape', 'Backup-to-File-Proxy', 'Backup-to-HyperV-Proxy', 'Backup-to-vSphere-Proxy', 'Backup-to-Repository', 'Backup-to-Sobr', 'Backup-to-WanAccelerator', 'Backup-to-ProtectedGroup', 'Backup-Infrastructure')]
        [string] $DiagramType,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to enable edge debugging ( Dummy Edge and Node lines)'
        )]
        [Switch] $EnableEdgeDebug = $false,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to enable subgraph debugging ( Subgraph Lines )'
        )]
        [Switch] $EnableSubGraphDebug = $false,
        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to enable error debugging'
        )]
        [Switch] $EnableErrorDebug = $false,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to set footer signature Author Name'
        )]
        [string] $AuthorName,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to set footer signature Company Name'
        )]
        [string] $CompanyName,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow the creation of footer signature'
        )]
        [Switch] $Signature = $false,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to add a watermark to the output image (Not supported in svg format)'
        )]
        [string] $WaterMarkText,

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to specified the color used for the watermark text'
        )]
        [string] $WaterMarkColor = 'Green',

        [Parameter(
            Mandatory = $false,
            HelpMessage = 'Allow to specified the size of the node column size'
        )]
        [ValidateScript( {
                if ($_ -gt 0) {
                    $true
                } else {
                    throw "ColumnSize must be a positive integer greater than zero."
                }
            })]
        [int] $ColumnSize = 4
    )

    begin {

        if ($psISE) {
            Write-Error -Message "You cannot run this script inside the PowerShell ISE. Please execute it from the PowerShell Command Window."
            break
        }


        $Verbose = if ($PSBoundParameters.ContainsKey('Verbose')) {
            $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent
        } else {
            $false
        }

        if ($EnableErrorDebug) {
            $global:VerbosePreference = 'Continue'
            $global:DebugPreference = 'Continue'
        } else {
            $global:VerbosePreference = 'SilentlyContinue'
            $global:DebugPreference = 'SilentlyContinue'
        }

        #@tpcarman
        # If Username and Password parameters used, convert specified Password to secure string and store in $Credential
        if ($Username) {
            if (-not $Password) {
                # If the Password parameter is not provided, prompt for it securely
                $SecurePassword = Read-Host "Password for user '$Username'" -AsSecureString
            } else {
                # If the Password parameter is provided, convert it to secure string
                $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
            }
            $Credential = New-Object System.Management.Automation.PSCredential ($Username, $SecurePassword)
        }

        if (($Format -ne "base64") -and !(Test-Path $OutputFolderPath)) {
            Write-Error "OutputFolderPath '$OutputFolderPath' is not a valid folder path."
            break
        }

        if ($Signature -and (([string]::IsNullOrEmpty($AuthorName)) -or ([string]::IsNullOrEmpty($CompanyName)))) {
            throw "New-VeeamDiagram : AuthorName and CompanyName must be defined if the Signature option is specified"
        }

        $MainGraphLabel = Switch ($DiagramType) {
            'Backup-to-Sobr' { 'Scale-Out Backup Repository Diagram' }
            'Backup-to-File-Proxy' { 'File Backup Proxy Diagram' }
            'Backup-to-vSphere-Proxy' { 'VMware Backup Proxy Diagram' }
            'Backup-to-HyperV-Proxy' { 'HyperV Backup Proxy Diagram' }
            'Backup-to-Repository' { 'Backup Repository Diagram' }
            'Backup-to-WanAccelerator' { 'Wan Accelerators Diagram' }
            'Backup-to-Tape' { 'Tape Infrastructure Diagram' }
            'Backup-to-ProtectedGroup' { 'Physical Infrastructure Diagram' }
            'Backup-Infrastructure' { 'Backup Infrastructure Diagram' }
        }
        if ($Format -ne 'Base64') {
            Write-ColorOutput -Color 'Green' -String ("Please wait while the '{0}' is being generated." -f $MainGraphLabel)
            Write-ColorOutput  -Color 'White' -String "- Please refer to the Veeam.Diagrammer github website for more detailed information about this project."
            Write-ColorOutput  -Color 'White' -String "- Documentation: https://github.com/rebelinux/Veeam.Diagrammer"
            Write-ColorOutput  -Color 'White' -String "- Issues or bug reporting: https://github.com/rebelinux/Veeam.Diagrammer/issues"
            Write-ColorOutput  -Color 'White' -String "- This project is community maintained and has no sponsorship from Veeam, its employees or any of its affiliates."


            # Check the current Veeam.Diagrammer module
            Try {
                $InstalledVersion = Get-Module -ListAvailable -Name Veeam.Diagrammer -ErrorAction SilentlyContinue | Sort-Object -Property Version -Descending | Select-Object -First 1 -ExpandProperty Version

                if ($InstalledVersion) {
                    Write-ColorOutput  -Color 'White' -String "- Veeam.Diagrammer $($InstalledVersion.ToString()) is currently installed."
                    $LatestVersion = Find-Module -Name Veeam.Diagrammer -Repository PSGallery -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Version
                    if ([version]$InstalledVersion -lt [version]$LatestVersion) {
                        Write-ColorOutput  -Color 'Red' -String " - Veeam.Diagrammer $($LatestVersion.ToString()) update is available."
                        Write-ColorOutput  -Color 'Red' -String " - Run 'Update-Module -Name Veeam.Diagrammer -Force' to install the latest version."
                    }
                }
            } Catch {
                Write-Warning $_.Exception.Message
            }
        }

        $IconDebug = $false

        if ($EnableEdgeDebug) {
            $script:EdgeDebug = @{style = 'filled'; color = 'red' }
            $IconDebug = $true
        } else { $script:EdgeDebug = @{style = 'invis'; color = 'red' } }

        if ($EnableSubGraphDebug) {
            $script:SubGraphDebug = @{style = 'dashed'; color = 'red' }
            $script:NodeDebug = @{color = 'black'; style = 'red'; shape = 'plain' }
            $script:NodeDebugEdge = @{color = 'black'; style = 'red'; shape = 'plain' }
            $IconDebug = $true
        } else {
            $script:SubGraphDebug = @{style = 'invis'; color = 'gray' }
            $script:NodeDebug = @{color = 'transparent'; style = 'transparent'; shape = 'point' }
            $script:NodeDebugEdge = @{color = 'transparent'; style = 'transparent'; shape = 'none' }
        }

        # Used to set diagram theme
        if ($DiagramTheme -eq 'Black') {
            $MainGraphBGColor = 'Black'
            $Edgecolor = 'White'
            $Fontcolor = 'White'
            $NodeFontcolor = 'White'
            $EdgeArrowSize = 1
            $EdgeLineWidth = 3
            $BackupServerBGColor = 'Black'
            $BackupServerFontColor = 'White'
        } elseif ($DiagramTheme -eq 'Neon') {
            $MainGraphBGColor = 'grey14'
            $Edgecolor = 'gold2'
            $Fontcolor = 'gold2'
            $NodeFontcolor = 'gold2'
            $EdgeArrowSize = 1
            $EdgeLineWidth = 3
            $BackupServerBGColor = 'grey14'
            $BackupServerFontColor = 'gold2'
        } elseif ($DiagramTheme -eq 'White') {
            $MainGraphBGColor = 'White'
            $Edgecolor = '#71797E'
            $Fontcolor = '#565656'
            $NodeFontcolor = 'Black'
            $EdgeArrowSize = 1
            $EdgeLineWidth = 3
            $BackupServerBGColor = '#ceedc4'
            $BackupServerFontColor = '#005f4b'
        }

        $RootPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
        $IconPath = Join-Path $RootPath 'icons'

        if ($DiagramType -eq 'Backup-Infrastructure') {

            $Dir = 'TB'
        } else {
            $Dir = switch ($Direction) {
                'top-to-bottom' { 'TB' }
                'left-to-right' { 'LR' }
            }
        }

        # Validate Custom logo
        if ($Logo) {
            $CustomLogo = Test-Logo -LogoPath (Get-ChildItem -Path $Logo).FullName -IconPath $IconPath -ImagesObj $Images
        } else {
            $CustomLogo = "VBR_Logo"
        }
        # Validate Custom Signature Logo
        if ($SignatureLogo) {
            $CustomSignatureLogo = Test-Logo -LogoPath (Get-ChildItem -Path $SignatureLogo).FullName -IconPath $IconPath -ImagesObj $Images
        }

        # Validate Veeam Powershell Module
        Get-VbrRequiredModule -Name 'Veeam.Backup.PowerShell' -Version '1.0'

        $MainGraphAttributes = @{
            pad = 1.0
            rankdir = $Dir
            overlap = 'false'
            splines = $EdgeType
            penwidth = 1.5
            fontname = "Segoe Ui Black"
            fontcolor = $Fontcolor
            fontsize = 32
            style = "dashed"
            labelloc = 't'
            imagepath = $IconPath
            nodesep = $NodeSeparation
            ranksep = $SectionSeparation
            bgcolor = $MainGraphBGColor

        }
    }

    process {

        foreach ($System in $Target) {

            if (Select-String -InputObject $System -Pattern "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") {
                throw "Please use the Fully Qualified Domain Name (FQDN) instead of an IP address when connecting to the Backup Server: $System"
            }

            Get-VbrServerConnection -Port $Port

            try {

                $script:VBRServer = Get-VBRServer -Type Local

            } Catch { throw "Unable to get Veeam Backup & Replication Server information: $System" }

            Get-VBRBackupServerInfo

            if ($BackupServerInfo) {
                Write-Verbose "Backup Server Information collected"
            } else {
                throw "No Backup Server Information available to diagram"
            }

            $script:Graph = Graph -Name VeeamVBR -Attributes $MainGraphAttributes {
                # Node default theme
                Node @{
                    label = ''
                    shape = 'none'
                    labelloc = 't'
                    style = 'filled'
                    fillColor = 'transparent'
                    fontsize = $NodeFontSize
                    imagescale = $true
                    fontcolor = $NodeFontcolor
                }
                # Edge default theme
                Edge @{
                    style = 'dashed'
                    dir = 'both'
                    arrowtail = 'dot'
                    color = $Edgecolor
                    penwidth = $EdgeLineWidth
                    arrowsize = $EdgeArrowSize
                    fontcolor = $Edgecolor
                }

                if ($Signature) {
                    Write-Verbose "Generating diagram signature"
                    if ($CustomSignatureLogo) {
                        $Signature = (Get-DiaHtmlSignatureTable -ImagesObj $Images -Rows "Author: $($AuthorName)", "Company: $($CompanyName)" -TableBorder 2 -CellBorder 0 -Align 'left' -Logo $CustomSignatureLogo -IconDebug $IconDebug)
                    } else {
                        $Signature = (Get-DiaHtmlSignatureTable -ImagesObj $Images -Rows "Author: $($AuthorName)", "Company: $($CompanyName)" -TableBorder 2 -CellBorder 0 -Align 'left' -Logo "VBR_LOGO_Footer" -IconDebug $IconDebug)
                    }
                } else {
                    Write-Verbose "No diagram signature specified"
                    $Signature = " "
                }

                SubGraph OUTERDRAWBOARD1 -Attributes @{Label = $Signature; fontsize = 24; penwidth = 1.5; labelloc = 'b'; labeljust = "r"; style = $SubGraphDebug.style; color = $SubGraphDebug.color } {
                    SubGraph MainGraph -Attributes @{Label = (Get-DiaHTMLLabel -ImagesObj $Images -Label $MainGraphLabel -IconType $CustomLogo -IconDebug $IconDebug -IconWidth 300 -IconHeight 54 -fontName "Segoe Ui Black" -fontColor $Fontcolor -Fontsize 28); fontsize = 24; penwidth = 0; labelloc = 't'; labeljust = "c" } {

                        Get-DiagBackupServer

                        if ($DiagramType -eq 'Backup-to-HyperV-Proxy') {
                            $BackuptoHyperVProxy = Get-DiagBackupToHvProxy | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoHyperVProxy) {
                                $BackuptoHyperVProxy
                            } else {
                                throw "No HyperV Proxy Infrastructure available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-vSphere-Proxy') {
                            $BackuptovSphereProxy = Get-DiagBackupToViProxy | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptovSphereProxy) {
                                $BackuptovSphereProxy
                            } else {
                                throw "No vSphere Proxy Infrastructure available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-File-Proxy') {
                            $BackuptoFileProxy = Get-DiagBackupToFileProxy | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoFileProxy) {
                                $BackuptoFileProxy
                            } else {
                                throw "No File Proxy Infrastructure available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-WanAccelerator') {
                            $BackuptoWanAccelerator = Get-DiagBackupToWanAccel | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoWanAccelerator) {
                                $BackuptoWanAccelerator
                            } else {
                                throw "No Wan Accelerators available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-Repository') {
                            $BackuptoRepository = Get-DiagBackupToRepo | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoRepository) {
                                $BackuptoRepository
                            } else {
                                throw "No Backup Repository available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-ProtectedGroup') {
                            $BackuptoProtectedGroup = Get-DiagBackupToProtectedGroup | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoProtectedGroup) {
                                $BackuptoProtectedGroup
                            } else {
                                throw "No Backup Protected Group available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-Tape') {
                            $BackupToTape = Get-DiagBackupToTape | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackupToTape) {
                                $BackupToTape
                            } else {
                                throw "No Tape Infrastructure available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-to-Sobr') {
                            $BackuptoSobr = Get-DiagBackupToSobr | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackuptoSobr) {
                                $BackuptoSobr
                            } else {
                                throw "No Scale-Out Backup Repository available to diagram"
                            }
                        } elseif ($DiagramType -eq 'Backup-Infrastructure') {
                            $BackupInfra = Get-VbrInfraDiagram | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch
                            if ($BackupInfra) {
                                $BackupInfra
                            } else {
                                throw "No Backup Infrastructure available to diagram"
                            }
                        }
                    }
                }
            }
        }
    }
    end {
        if ($Graph) {
            #Export Diagram
            foreach ($OutputFormat in $Format) {

                $OutputDiagram = Export-Diagrammer -GraphObj ($Graph | Select-String -Pattern '"([A-Z])\w+"\s\[label="";style="invis";shape="point";]' -NotMatch) -ErrorDebug $EnableErrorDebug -Format $OutputFormat -Filename $Filename -OutputFolderPath $OutputFolderPath -WaterMarkText $WaterMarkText -WaterMarkColor $WaterMarkColor -IconPath $IconPath -Verbose:$Verbose -Rotate $Rotate

                if ($OutputDiagram) {
                    if ($OutputFormat -ne 'Base64') {
                        # If not Base64 format return image path
                        Write-ColorOutput -Color 'White' -String ("Diagrammer diagram '{0}' has been saved to '{1}'" -f $OutputDiagram.Name, $OutputDiagram.Directory)
                    } else {
                        Write-Verbose "Displaying Base64 string"
                        # Return Base64 string
                        $OutputDiagram
                    }
                }
            }
        }

        if ($EnableErrorDebug) {
            $global:VerbosePreference = 'SilentlyContinue'
            $global:DebugPreference = 'SilentlyContinue'
        }
    }
}