Visio to PHPWeathermap

It’s been awhile, but I haven’t been too lazy! I’ve got some projects currently in the works and a new server that I’m getting ready.

In the mean time though, check out this super handy (to me at least) Visio to PHPWeathermap converter. At this time, it only gets network nodes and links them based on what’s in the Visio file. It does not yet know how to create links using the VIA config or how to differentiate between straight lines and curved….yet

To get a shape to show in Weathermap, you have to set the shape’s IP address (found under shape data) or manually add “Node” and “Label” to User-defined cells for things like internet clouds.

After converting the file, you’ll need to manually add icons, targets, and anything else you’ll want done.

<#
.SYNOPSIS
Convert Visio network map to a PHP Weathermap config file.
.Description
Visio is required to run.

Sends resulting config to STDOUT.

.Parameter VisioMap
Path of the Visio map to convert.
#>
param(
    $VisioMap
)

if($host.Name -imatch "ise") {
    #for testing in ISE
    $VisioMap = $env:visiomap
} else {
    if(!$VisioMap) { 
        $VisioMap = Read-Host -Prompt "Filepath";
    }
}

#get all child nodes of a shape if they have an ipaddress or node value set.
function getNodes {
    param($shape);
    
    $rtn = @();
    if($shape.shapes) {
        $rtn += $shape.shapes | %{ getNodes $_; }
    }
    if($shape.CellExists) {
        if(([bool]$shape.CellExists("Prop.IPAddress",1)) -or ([bool]$shape.CellExists("User.Node",1))) {
             $rtn += $shape;
        }
    }
    return $rtn;
}

#target shape not have an ipaddress or node cell? find out if a parent does!
#returns false if there is no parent with those cells.
function getParent {
    param($shape)
    
    try {
        if(([bool]$shape.CellExists("Prop.IPAddress",1)) -or ([bool]$shape.CellExists("User.Node",1))) {
            return $shape;
        } else {
            return (getParent $shape.ContainingShape);
        }
    }
    catch {
        return $false;
    }
}

try {
    #for when I'm testing.
    if($application -eq $null) {
        $application = New-Object -ComObject Visio.Application
        $doc = $application.Documents.Open($VisioMap);
    }
    $height = [math]::Ceiling($doc.Pages.Item(1).PageSheet.cells("PageHeight").ResultIU * 100)
    $width = [math]::Ceiling($doc.Pages.Item(1).PageSheet.cells("PageWidth").ResultIU * 100)

    "HEIGHT " + $height
    "WIDTH " + $width
    
    $ioi = (getNodes $doc.Pages.Item(1)) | ?{$_.name} | %{ $_ }

    $ntpl = @"
NODE node{@id}
	LABEL {@label}
	POSITION {@x} {@y}
"@;
    foreach($i in $ioi) {
        try {
            $rv = @{
                "id" = "";
                "ipaddress" = "";
                "label" = "";
            };
            
            if([bool]$i.CellExistsU("Prop.IPAddress",0)) {
                $ipaddress = [net.ipaddress]::Parse($i.cells("Prop.IPAddress").formula.trim('"'));
                
                $rv["label"] = $i.Cells("Prop.NetworkName").formula.trim('"');
                if($i.Cells("Prop.NetworkName").formula.trim('"').length -eq 0) {
                    $rv["label"] = $ipaddress.ToString();
                }
                
                $rv['id'] = $ipaddress.address;
                $rv["ipaddress"] = $ipaddress.ToString();
            } elseif([bool]$i.CellExistsU("User.Node",0) -and [bool]$i.CellExistsU("User.Label",0)) {
                $rv["id"] = $i.name;
                
                $rv["label"] = $i.Cells("User.Label").formula.trim('"');
                if($i.Cells("User.Label").formula.trim('"').length -eq 0) {
                    $rv["label"] = $i.Name;
                }
            }
            $rv.Add("x", [math]::Ceiling(($i.Cells("PinX").ResultIU * 100)))
            $rv.Add("y", [math]::Ceiling(($i.Cells("PinY").ResultIU * 100)))
            
            
            $node = $ntpl;
            foreach($k in $rv.Keys) {
                $node = $node.Replace("{@$k}", $rv[$k]);
            }
            $node
        } catch {
            $err = $_;
            $err;
            $i.name | Write-Debug;
        }
    }

    $ltpl = @"
LINK {@fromNodeId}-{@toNodeId}
    #from: {@fromLabel}
    #to: {@toLabel}
	WIDTH 5
	ARROWSTYLE compact
	NODES {@fromNodeId} {@toNodeId}
"@
    foreach($wire in $doc.Pages.item(1).Shapes | where {$_.connects.count -gt 0}) {
        try {
            $rv = @{};
            
            $from = $wire.Connects.Item(1).tocell.shape;
            $to = $wire.Connects.Item(2).tocell.shape;
            
            #Find the parent.
            if(![bool]$from.CellExists("Prop.IPAddress",1) -or
                ![bool]$from.CellExists("User.Node",1)) {
                $from = getParent $from;
            }
            
            if(![bool]$to.CellExists("Prop.IPAddress",1) -or
                ![bool]$to.CellExists("User.Node",1)) {
                $to = getParent $to;
            }    
            
            if([bool]$from.CellExists("Prop.IPAddress",1)) {
                $fromIpaddress = [net.ipaddress]::Parse($from.cells("Prop.IPAddress").formula.trim('"'));
                
                $rv.Add("fromNodeId", "node" + $fromIpaddress.Address)
                $rv.Add("fromLabel", $fromIpaddress.tostring())
            } elseif([bool]$from.CellExists("User.Node",1)) {
            
                $rv.Add("fromNodeId", "node" + $from.Name)
                try {
                    $rv.Add("fromLabel", $from.cells("User.Label").formula.trim('"'));
                } catch {
                    $rv.Add("fromLabel", $from.Name)
                }
            } else {
                $rv.Add("fromNodeId", "node" + $from.name)
                $rv.Add("fromLabel", $from.name)
            }
            
            if([bool]$to.CellExists("Prop.IPAddress",1)) {
                $toIpaddress = [net.ipaddress]::Parse($to.cells("Prop.IPAddress").formula.trim('"'));
                
                $rv.Add("toNodeId", "node" + $toIpaddress.Address)
                $rv.Add("toLabel", $toIpaddress.tostring())
            } elseif([bool]$to.CellExists("User.Node",1)) {
            
                $rv.Add("toNodeId", "node" + $to.name)
                try {
                    $rv.Add("toLabel", $to.cells("User.Label").formula.trim('"'));
                } catch {
                    $rv.Add("toLabel", $to.name)
                }
            } else {
                $rv.Add("toNodeId", "node" + $to.name)
                $rv.Add("toLabel", $to.name)
            }
            
            #$rv.Count | Write-Debug;
            $link = $ltpl;
            foreach($k in $rv.Keys) {
                "{@$k} = " + $rv[$k] | Write-Debug;
                $link = $link.Replace("{@$k}", $rv[$k]);
            }
            $link
        }catch{
            $_;
            $wire.name | Write-Debug
        }
    }
}
catch {
    $_
} finally {
    #not testing? quit!
    if(!($Host.Name -imatch "ise")) {
        $application.Quit();
        $application = $null
    } 
}

[Edit] Forgot to set $VisioMap with Read-Host if it were empty!


Comments

7 responses to “Visio to PHPWeathermap”

Leave your response
  1. dan says:

    I am very interested about this script but no instruction how to use it. can you add how to 🙂
    thanks,

    • snoj says:

      Hey Dan, I’m sorry I don’t have much for instruction beside what is in the post and script. Plus I haven’t had to run use this code in quite a while, so i’m pretty rusty myself.

      What are you having trouble with?

      • dan says:

        thanks for the response,I have few basic question, first your cacti running on windows platform? not sure is that matter or not and the script should run on Cacti server or on your pc where the visio located. thanks!!!

        • snoj says:

          You really should use weathermap’s built in editor to further enhance your map and make sure it works in your cacti environment.

          The script was only meant for one way and one time usage. Really, it’s just a way to easily setup a basic weathermap based on an existing Visio document. Since this script uses the Visio.Application com object, it has to be ran on a computer with Visio installed.

          • dan says:

            yes, I am normally using the editor and happy with it, but recently got 10 visio drawing to put on Weathermap so actually I am looking one time transfer, if I can save time 🙂 do I have to edit any part of the script other than the file path? I am not power-shell guy so bare with me. if the process not saved me time then I will do it manually. thanks again!!!

          • snoj says:

            I don’t believe there would need to be any editing of the script itself. Just save it as “somethingsomething.ps1” and run it.

            Example:
            somethingsomething.ps1 /path/to/visio/map.vsd | out-file /path/to/weathermap.conf -encoding ascii

  2. dan says:

    thank much Josh, that exactly I need, I will figure out the rest.