Powershell: Wake up on Lan 0.3

Nick asked, “This script looks good. Would you mind adding comments to it to describe its logic? Also, it doesn’t appear to like having colons in MAC addresses even though colons is pretty standard. Thanks for sharing your script!” (link).

Well Nick, here you are! I hope it helps!

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 {
    #Convert -network and -subnet to Net.IPAddress objects if necessary.
    if($network.gettype().equals([string])) {
        $network = [net.ipaddress]::Parse($network);
    }
    if($subnet.gettype().equals([string])) {
        $subnet = [net.ipaddress]::Parse($subnet);
    }
    
    #find the broadcast address for the -network
    #eg. the broadcast address for the ip 192.168.1.101/255.255.255.0 is 192.168.1.255.
    $broadcast = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $subnet.address -bor $network.address))
    
    #attempt to figure out if the first value is an ip or mac address.
    #if we do this: wol.ps1 192.168.1.255
    #instead of this: wol.ps1 -targetIP 192.168.1.255
    try {
        $targetIP = [net.ipaddress]::Parse($targetMac.toupper()).tostring() # | Out-Null;
    } catch {
        #$_;
        try {
            [Net.NetworkInformation.PhysicalAddress]::Parse($targetMac.toupper().replace(".","").replace(":","").replace("-","")) | Out-Null;
        } catch {
            #$_;
        }
    }
    
    #Find our target mac address.
    #$targetIP isn't set in the above try..catch if it's a mac address.
    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(".","").replace(":","").replace("-",""))
    
    <#"targetmac: " + $targetMac;
    "targetip: " + $targetip;
    "mac: " + $mac;#>
    
    #Setup 3 different endpoints for the common WOL ports.
    $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
    
    #setup the payload.
    #6 bytes of 255 followed by the target mac 16 times.
    $payload = [byte[]]@(255,255,255,255,255,255);
    $payload += ($mac.GetAddressBytes()*16)
    
    #send it out a few times.
    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;
}
#Win32_NetworkAdapter
#Win32_OperatingSystem
#Win32_NetworkClient
#Win32_SystemNetworkConnections

Comments

2 responses to “Powershell: Wake up on Lan 0.3”

Leave your response
  1. Nick says:

    Awesome! Thank you very much! I think my last question is why does the payload have to be sent multiple times? Isn’t one enough?

  2. snoj says:

    I’m glad you like!

    Well, UDP is unreliable. We can’t assume that the message was actually forwarded on by the switches/hubs, or even received by the target machine. By sending multiple packets, we increase the chances that at least 1 will make it to where it needs to go.

    Now modern networks are really fast, and way better then the ones you’d find even a decade ago, so just one wol packet would likely be enough. However, we still need to live by the same principles as they did back then, that is, the network is inherently unreliable.