Powershell: Wake up on Lan – redux

In this revision, I’ve added support for IP based wake ups. However, the IP needs to be in the local ARP table.

param (
    [parameter(Position=0,
        Mandatory = $true,
        ParameterSetName="bymac",
        HelpMessage="Wake up a machine by known mac address.")]
    [string]
    $targetMac,
    [parameter(Position=0,
        mandatory = $true,
        ParameterSetName="byip",
        HelpMessage="Wake up a machine by last known IP address.")]
    [Net.IPAddress]
    $targetIP,
    [parameter(Position=1)]
    $network = [net.ipaddress]::Broadcast,
    [parameter(Position=2)]
    $subnet = [net.ipaddress]::Broadcast
)

try {
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }
    
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))
    
    try {
        $targetIP = [net.ipaddress]::Parse($targetMac.toupper()).tostring() # | Out-Null;
        
        
    } catch {
        #$_;
        try {
            [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper()) | Out-Null;
        } catch {
            #$_;
        }
    }
    if($targetIP) {
        try {
            $nmac = (arp -a $targetIP | ? {$_ -imatch $targetIP}).split(" ") | ? {$_.trim().length -gt 0;} | %{ $_.trim(); };
            $targetMac = $nmac[1];
        }catch{
            throw "IP address is unknown.";
        }
    }
    
    $mac = [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".",""))
    
    $u = New-Object net.sockets.udpclient
    $ep = New-Object net.ipendpoint $broadcast, 0
    $ep2 = New-Object net.ipendpoint $broadcast, 7
    $ep3 = New-Object net.ipendpoint $broadcast, 9

    $payload = [byte[]]@(255,255,255,255,255,255);
    $payload += ($mac.GetAddressBytes()*16)

    for($i = 0; $i -lt 10; $i++) {
        $u.Send($payload, $payload.Length, $ep) | Out-Null
        $u.Send($payload, $payload.Length, $ep2) | Out-Null
        $u.Send($payload, $payload.Length, $ep3) | Out-Null
        "$(date) - WOL payload $($i+1)/10 sent to $targetMac on $broadcast/$subnet" | Write-Debug;
        sleep -Milliseconds 10;
    }
} catch {
    $_ | Write-Error;
}

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!