Public/Export-LMTopologyMap.ps1

Function Export-LMTopologyMap {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory, ParameterSetName = 'Id')]
        [Int]$Id,

        [Parameter(Mandatory, ParameterSetName = 'Name')]
        [String]$Name,

        [Boolean]$IncludeUndiscoveredDevices = $false,

        [Boolean]$IncludeDataTable = $false,

        [Boolean]$EnablePhysics = $false,

        [Boolean]$FixedLMMapLocation = $false,

        [String]$BackgroundImage = ""
    )
    #Check if we are logged in and have valid api creds
    If ($global:LMAuth.Valid) {
        #Grab Topology Map data so we can build our HTML map
        If ($Name) {
            $TopoData = Get-LMTopologyMapData -Name $Name
            $TopoLayout = (Get-LMTopologyMap -Name $Name).layout.vertices
        }
        ElseIf ($Id) {
            $TopoData = Get-LMTopologyMapData -Id $Id
            $TopoLayout = (Get-LMTopologyMap -Id $Id).layout.vertices
        }
        
        #Loop through edges and match up to verticies to build our custom object
        $TopoObject = @()
        If ($TopoData) {
            foreach ($edge in $TopoData.edges) {
                $vToIndex = $TopoData.vertices.id.IndexOf($edge.to)
                $vFromIndex = $TopoData.vertices.id.IndexOf($edge.from)
                #We found a match in our vertices list so we continue building our object
                If ($vToIndex -ne -1 -and $vFromIndex -ne -1) {
                    $fromLayoutIndex = $TopoLayout.id.IndexOf($edge.from)
                    $toLayoutIndex = $TopoLayout.id.IndexOf($edge.to)
                    $TopoObject += [PSCustomObject]@{
                        fromId   = $TopoData.vertices[$vFromIndex].id
                        fromName = $TopoData.vertices[$vFromIndex].LMResources[0].name
                        fromType = $TopoData.vertices[$vFromIndex].type
                        fromX    = [Int][Math]::Round([Math]::Ceiling($TopoLayout[$fromLayoutIndex].x)) * .75
                        fromY    = [Int][Math]::Round([Math]::Ceiling($TopoLayout[$fromLayoutIndex].y)) * .75
                        toId     = $TopoData.vertices[$vToIndex].id
                        toName   = $TopoData.vertices[$vToIndex].LMResources[0].name
                        toType   = $TopoData.vertices[$vToIndex].type
                        toX      = [Int][Math]::Round([Math]::Ceiling($TopoLayout[$toLayoutIndex].x)) * .75
                        toY      = [Int][Math]::Round([Math]::Ceiling($TopoLayout[$toLayoutIndex].y)) * .75
                        edgeType = $edge.type
                    }
                }
            }

            If ($IncludeUndiscoveredDevices) {
                $TopoNodeGroups = $TopoObject | Group-Object fromId
            }
            Else {
                $TopoNodeGroups = $TopoObject | Where-Object { $_.fromType -ne "undiscovered" -and $_.toType -ne "undiscovered" } | Group-Object fromId
            }

            $NodeIcons = [PSCustomObject]@{
                HyperVisor        = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/HyperVisor-focus.svg'
                HyperVisorCluster = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/HyperVisorCluster-focus.svg'
                Switch            = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Switch-focus.svg'
                Undiscovered      = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Device-focus.svg'
                Unknown           = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Device-focus.svg'
                NotMonitored      = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/notmonitored-focus.svg'
                Cluster           = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Cluster-focus.svg'
                Firewall          = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Firewall-focus.svg'
                PhysicalServer    = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/PhysicalServer-focus.svg'
                VirtualMachine    = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/VirtualMachine-focus.svg'
                Service           = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Service-focus.svg'
                Pod               = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Pod-focus.svg'
                Container         = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/Container-focus.svg'
                VMDatastore       = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/VMDatastore-focus.svg'
                VirtualDisk       = 'https://static-prod.logicmonitor.com/sbui148-1/commons/images/icons/use-for-topology/VirtualDisk-focus.svg'
            }

            New-HTML -TitleText 'LogicMonitor TopologyMap'  -FilePath $PSScriptRoot\Example-LM.html {
                New-HTMLSection -HeaderText "LogicMonitor TopologyMap $Id$Name" -CanCollapse {
                    New-HTMLPanel {
                        New-HTMLDiagram -Height "900px" {
                            New-DiagramOptionsPhysics -Enabled $EnablePhysics
                            New-DiagramOptionsInteraction -Hover $true
                            New-DiagramOptionsLayout -RandomSeed 500
                            New-DiagramOptionsLinks -ArrowsToEnabled $true -Color BlueViolet -ArrowsToType arrow -ArrowsFromEnabled $false
                            New-DiagramOptionsNodes -BorderWidth 1 -FontColor Black -Size 20 -FontMulti true
                            Foreach ($group in $TopoNodeGroups) {
                                Foreach ($to in $group.Group) {

                                    New-DiagramNode -Id $to.toId -Label $to.toName -Image $(If ($NodeIcons.$($to.toType)) { $NodeIcons.$($to.toType) }Else { $NodeIcons.Unknown }) -X $to.toX -Y $to.toY -FixedX $useCoordinatesFromLM -FixedY $useCoordinatesFromLM
                                    #Write-Host "Id:$($to.toId) | Label: $($to.toName)"
                                }
                                New-DiagramNode -Id $group.Group[0].fromId -Label $group.Group[0].fromName -To $($group.Group.toId -Join ",").Split(",") -Image $(If ($NodeIcons.$($group.Group[0].fromType)) { $NodeIcons.$($group.Group[0].fromType) }Else { $NodeIcons.Unknown }) -X $group.Group[0].fromX -Y $group.Group[0].fromY -FixedX $useCoordinatesFromLM -FixedY $useCoordinatesFromLM
                                #Write-Host "Id:$($group.Group[0].fromId) | Label: $($group.Group[0].fromName) | To: $($group.Group.toId -Join ",")"
                            }
                        } -BackGroundImage $BackgroundImage
                    }
                    If ($IncludeDataTable) {
                        New-HTMLPanel {
                            New-HTMLTable -DataTable $(If (!$IncludeUndiscoveredDevices) { $TopoObject | Where-Object { $_.fromType -ne "undiscovered" -and $_.toType -ne "undiscovered" } | Select-Object -ExcludeProperty fromX, fromY, toX, toY }Else { $TopoObject | Select-Object -ExcludeProperty fromX, fromY, toX, toY }) -PagingLength 30 -DefaultSortIndex 1
                        }
                    }
                }
            } -ShowHTML -Online
        }
        Else {
            Write-Host "Unable to retrieve topology data for give id/name, please check spelling and try again" -ForegroundColor Yellow
            Return
        }
    }
    Else {
        Write-Host "Please ensure you are logged in before running any comands, use Connect-LMAccount to login and try again." -ForegroundColor Yellow
    }
}