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
    }
}