Wake On Lan Magic Packet script

There are a bunch of these to be found on the Web (see the additional notes on Origins below) although sadly some of them are either incorrect or of very dubious style.  Here’s my take on the theme in PowerShell (naturally:-)

I use this a lot – especially these days with spiralling electricity costs – to wake suspended machines and servers.

Wake on Lan uses a “Magic Packet” that consists of six bytes of 0xFF (the physical layer broadcast address), followed by 16 copies of the 6-byte (48-bit) MAC address (see http://en.wikipedia.org/wiki/Wake-on-LAN).   This packet is sent via UDP to the LAN Broadcast address (255.255.255.255) on arbitrary Port 4000 – although the layer 3 baggage is actually largely irrelevant.  Construction of this packet in PowerShell is a breeze thanks to the array semantics in the language (“$Packet = [Byte[]](,0xFF*6)+($Mac*16)” – neat).

This script has a table of saved MAC addresses to allow aliases to be specified on the command line (the real addresses have been obfuscated here) and uses a regex to validate the resulting MAC address string.  It would be possible to use DNS and the ARP Cache to resolve MAC addresses but the ARP cache will only be populated with a valid entry for any given target adapter for a relative short period of time after the last use of the address (10 minutes or less depending on usage); ARP cannot be used to dynamically resolve the address of a suspended adapter.

Here’s the script:

WakeOnLan.ps1
  1. # Send Wake-on-Lan Magic Packet to specified Mac address
  2. [CmdletBinding()]
  3. Param ($MacString=$(Throw 'Mac address is required'))
  4.  
  5. $Table=@{
  6.     Hyperion  ='00-00-00-00-00-44';
  7.     Nova      ='00-00-00-00-00-C8';
  8.     Desktop   ='00-00-00-00-00-1B';
  9.     Laptop    ='00-00-00-00-00-18';
  10.     Playroom  ='00-00-00-00-00-5C';
  11.     Betty     ='00-00-00-00-00-32';
  12.     gr8       ='00-00-00-00-00-D7'
  13. }
  14. If ($Table.ContainsKey($MacString)) {$MacString=$Table[$MacString]}
  15.  
  16. Write-Verbose "Using MAC string $MacString"
  17.  
  18. If ($MacString -NotMatch '^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$') {
  19.     Throw 'Mac address must be 6 hex bytes separated by : or -'
  20. }
  21.  
  22. # Split and convert to array of bytes
  23. $Mac=$MacString.Split('-:')|%{[Byte]"0x$_"}
  24.  
  25. # Packet is byte array; first six bytes are 0xFF, followed by 16 copies of the MAC address
  26. $Packet = [Byte[]](,0xFF*6)+($Mac*16)
  27. Write-Verbose "Broadcast packet: $([BitConverter]::ToString($Packet))"
  28.  
  29. $UdpClient=New-Object System.Net.Sockets.UdpClient
  30. $UdpClient.Connect(([System.Net.IPAddress]::Broadcast),4000)
  31. [Void]$UdpClient.Send($Packet,$Packet.Length)
  32. $UdpClient.Close()
  33. Write-Verbose "Wake-on-Lan Packet sent to $MacString"

 

Origins

I’ve been using this script for a long time and while writing this post I wondered where the idea had come from.  As is often the case it would appear that, at least for the correct entries (including those from the like of Brandon http://social.technet.microsoft.com/Forums/en-US/ITCG/thread/51ef86e5-f3d4-459c-a08a-615c669aff2e and John Savill http://www.windowsitpro.com/article/networking/Q-How-can-I-easily-send-a-magic-packet-to-wake-a-machine-on-my-subnet-), MOW is involved(http://thepowershellguy.com/blogs/posh/archive/2007/04/01/powershell-wake-on-lan-script.aspx) – although in this particular case, his blog entry is not correct but the answer is provided in the blog comments by James Manning who used to have an MSDN blog and I imagine (used to?) work for Microsoft – although the blog hasn’t been updated since 2009.