WakeUp-Machines – A PowerShell script for Wake On LAN

 

These days, I give a lot of presentations and demos on Windows Server 2012. Of course, many involve Hyper-V related demos. Although I run most demos from PowerShell, since now I can, I modify a lot in my demo environment. And since I frequently use my environment I need to be able to prepare my start my environment, prepare it, run the demos, revert to the state it was in when I started and finally shut down my environment.

At least the start, preparation (including tests), reverting and shutting down are all done using PowerShell scripts. Sometimes I have only 15 minutes to connect my machines to power and network. In that time, I don’t have time to manually start everything and use a document to follow what needs to be done. And what about some basic tests to verify everything is working correctly?

Think about it: starting the machines, waiting until they are alive, connecting through RDP to some of them and some virtual machines, starting VMconnect sessions, starting Hyper-V Manager, Server Manager, PowerShell console, configuring networks, etc, etc. Quite easy to forget some steps and hit issues during demos.

I normally don’t connect my presentation machine to the external monitor (large screen, beamer, etc.) until the environment is ready. But to show the power of automation, I did show a technical audience once how I start my environment (up to the point when it is ready). People were obviously impressed with the amount of automation I used.

Last month I presented at a large Microsoft event and got some questions from colleagues as well on how I started my machines without touching them. The script used Wake On LAN, something most machines support these days and which is on most of them on by default. I simply connect my machines to my switch and turn them on from my presentation machine.

In this post, I share my script for others to use. The script follows some PowerShell best practices:

· The name of the script is in the Verb-Noun form.

· The script is documented with comment based help.

The only thing you need to get it to work is the Wake On LAN tool. Other than that, you should be able to use it right away, once you have created the CSV file with machine names.

So how does it work?

The script uses a CSV file with machines you want to wake up. It starts with the first and works its way down the list. Not only does it wake the machines, it also sends echo requests to verify IP connectivity. It continues to send requests (number configurable) and then goes on to the next machine with wake up. I have developed a progress bar which displays progress on the wake up, the echo request and remaining phase of sending/receiving echo requests/replies.

    

WakeUp-Machines

  1. #######################################################
  2. ##
  3. ## WakeUp-Machines.ps1, v1.0, 2012
  4. ##
  5. ## Created by Matthijs ten Seldam, Microsoft
  6. ##
  7. #######################################################
  8.  
  9. <#
  10. .SYNOPSIS
  11. Starts a list of physical machines by using Wake On LAN.
  12.  
  13. .DESCRIPTION
  14. WakeUp-Machines starts a list of servers using a Wake On LAN tool. It then sends echo requests to verify that the machine has TCP/IP connectivity. It waits for a specified amount of echo replies before starting the next machine in the list.
  15.  
  16. .PARAMETER Machines
  17. The name of the file containing the machines to wake.
  18.  
  19. .PARAMETER Interface
  20. The IP address of the interface to use to wake up the machines.
  21.  
  22. .PARAMETER Subnet
  23. The subnet mask of the interface to use to wake up the machines.
  24.  
  25. .EXAMPLE
  26. WakeUp-Machines machines.csv 192.168.0.1 255.255.255.0
  27.  
  28. .EXAMPLE
  29. WakeUp-Machines c:\tools\machines.csv 192.168.0.1 255.255.255.0
  30.  
  31. .INPUTS
  32. None
  33.  
  34. .OUTPUTS
  35. None
  36.  
  37. .NOTES
  38. Make sure the Wake On LAN command line tool is available in the same location as the script!
  39.  
  40. The CSV file with machines must be outlined using Name, MAC Address and IP Address with the first line being Name,MacAddress,IpAddress.
  41. See below for an example of a properly formatted CSV file.
  42.  
  43. Name,MacAddress,IpAddress
  44. Host1,A0DEF169BE02,192.168.0.11
  45. Host3,AC1708486CA2,192.168.0.12
  46. Host2,FDDEF15D5401,192.168.0.13
  47.  
  48. .LINK
  49. https://blogs.technet.com/matthts
  50. #>
  51.  
  52.  
  53. param(
  54.     [Parameter(Mandatory=$true, HelpMessage="Provide the path to the CSV file containing the machines to wake.")]
  55.     [string] $Machines,
  56.     [Parameter(Mandatory=$true, HelpMessage="Provide the IP address of the interface to use for Wake On LAN.")]
  57.     [string] $Interface,
  58.     [Parameter(Mandatory=$true, HelpMessage="Provide the subnet mask of the interface to use for Wake On LAN.")]
  59.     [string] $Subnet
  60.     )
  61.  
  62.  
  63. ## Predefined variables
  64. $WolCmd=".\wolcmd.exe"
  65. $TimeOut = 30
  66. $Replies = 10
  67.  
  68. clear;Write-Host
  69.  
  70. ## Verify if WOL tool exists
  71. try
  72. {
  73.     Get-ChildItem $WolCmd | Out-Null
  74. }
  75. Catch
  76. {
  77.     Write-Host "$WolCmd file not found!";Write-Host
  78.     exit
  79. }
  80.  
  81. ## Read CSV file with machine names
  82. try
  83. {
  84.     $File=Import-Csv $Machines
  85. }
  86. Catch
  87. {
  88.     Write-Host "$Machines file not found!";Write-Host
  89.     exit
  90. }
  91.  
  92.  
  93. $i=1
  94. foreach($Machine in $File)
  95. {
  96.     $Name=$Machine.Name
  97.     $MAC=$Machine.MacAddress
  98.     $IP=$Machine.IpAddress
  99.  
  100.     ## Send magic packet to wake machine
  101.     Write-Progress -ID 1 -Activity "Waking up machine $Name" -PercentComplete ($i*100/$file.Count)
  102.     Invoke-Expression "$WolCmd $MAC $Interface $Subnet" | Out-Null
  103.  
  104.     $j=1
  105.     ## Go into loop until machine replies to echo
  106.     $Ping = New-Object System.Net.NetworkInformation.Ping
  107.     do
  108.     {
  109.         $Echo = $Ping.Send($IP)
  110.         Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete ($j*100/$TimeOut)
  111.         sleep 1
  112.         
  113.         if ($j -eq $TimeOut)
  114.         {
  115.             Write-Host "Time out expired, aborting.";Write-Host
  116.             exit
  117.         }
  118.         $j++
  119.     }
  120.     while ($Echo.Status.ToString() -ne "Success" )
  121.  
  122.     ## Machine is alive, keep sending for $Replies amount
  123.     for ($k = 1; $k -le $Replies; $k++)
  124.     {
  125.        Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete (100)
  126.        Write-Progress -Id 3 -ParentId 2 -Activity "Receiving echo reply"  -PercentComplete ($k*100/$Replies)
  127.        sleep 1
  128.     }
  129.     $i++
  130.     Write-Progress -Id 3 -Completed $true
  131.     $Ping=$null
  132. }

   

You can download the script, tool and sample machine.csv here.

 

#######################################################

Update, June 3rd 2012

I have updated my script to be able to do without the wolcmd tool. As pointed out in the comments, it is possible to do this from within PowerShell. So I did some research in MSDN and rewrote my script.

The switches have changed as well. You can now provide the time out, repeat and number of magic packets to send. Run Get-Help .\WakeUp-Machines.ps1 to get additional help (-detailed, –examples, –full all supported).

  

WakeUp-Machines

  1. #######################################################
  2. ##
  3. ## WakeUp-Machines.ps1, v1.1, 2012
  4. ##
  5. ## Created by Matthijs ten Seldam, Microsoft
  6. ##
  7. #######################################################
  8.  
  9. <#
  10. .SYNOPSIS
  11. Starts a list of physical machines by using Wake On LAN.
  12.  
  13. .DESCRIPTION
  14. WakeUp-Machines starts a list of servers using Wake On LAN magic packets. It then sends echo requests to verify that the machine has TCP/IP connectivity. It waits for a specified amount of echo replies before starting the next machine in the list.
  15.  
  16. .PARAMETER Machines
  17. The name of the file containing the machines to wake.
  18.  
  19. .PARAMETER TimeOut
  20. The number of seconds to wait for an echo reply before continuing with the next machine.
  21.  
  22. .PARAMETER Repeat
  23. The number of echo requests to send before continuing with the next machine.
  24.  
  25. .EXAMPLE
  26. WakeUp-Machines machines.csv
  27.  
  28. .EXAMPLE
  29. WakeUp-Machines c:\tools\machines.csv
  30.  
  31. .INPUTS
  32. None
  33.  
  34. .OUTPUTS
  35. None
  36.  
  37. .NOTES
  38. Make sure the MAC addresses supplied don't contain "-" or ".".
  39.  
  40. The CSV file with machines must be outlined using Name, MAC Address and IP Address with the first line being Name,MacAddress,IpAddress.
  41. See below for an example of a properly formatted CSV file.
  42.  
  43. Name,MacAddress,IpAddress
  44. Host1,A0DEF169BE02,192.168.0.11
  45. Host3,AC1708486CA2,192.168.0.12
  46. Host2,FDDEF15D5401,192.168.0.13
  47.  
  48. .LINK
  49. https://blogs.technet.com/matthts
  50. #>
  51.  
  52.  
  53. param(
  54.     [Parameter(Mandatory=$true, HelpMessage="Path to the CSV file containing the machines to wake.")]
  55.     [string] $Machines,
  56.     [Parameter(Mandatory=$false, HelpMessage="Number of unsuccesful echo requests before continuing.")]
  57.     [int] $TimeOut=30,
  58.     [Parameter(Mandatory=$false, HelpMessage="Number of successful echo requests before continuing.")]
  59.     [int] $Repeat=10,
  60.     [Parameter(Mandatory=$false, HelpMessage="Number of magic packets to send to the broadcast address.")]
  61.     [int] $Packets=2
  62.     )
  63.  
  64.  
  65. Set-StrictMode -Version Latest
  66.  
  67. clear;Write-Host
  68.  
  69. ## Read CSV file with machine names
  70. try
  71. {
  72.     $File=Import-Csv $Machines
  73. }
  74. Catch
  75. {
  76.     Write-Host "$Machines file not found!";Write-Host
  77.     exit
  78. }
  79.  
  80. function Send-Packet([string]$MacAddress, [int]$Packets)
  81. {
  82.     <#
  83.     .SYNOPSIS
  84.     Sends a number of magic packets using UDP broadcast.
  85.  
  86.     .DESCRIPTION
  87.     Send-Packet sends a specified number of magic packets to a MAC address in order to wake up the machine.  
  88.  
  89.     .PARAMETER MacAddress
  90.     The MAC address of the machine to wake up.
  91.  
  92.     .PARAMETER
  93.     The number of packets to send.
  94.     #>
  95.  
  96.     try
  97.     {
  98.         $Broadcast = ([System.Net.IPAddress]::Broadcast)
  99.  
  100.         ## Create UDP client instance
  101.         $UdpClient = New-Object Net.Sockets.UdpClient
  102.  
  103.         ## Create IP endpoints for each port
  104.         $IPEndPoint1 = New-Object Net.IPEndPoint $Broadcast, 0
  105.         $IPEndPoint2 = New-Object Net.IPEndPoint $Broadcast, 7
  106.         $IPEndPoint3 = New-Object Net.IPEndPoint $Broadcast, 9
  107.  
  108.         ## Construct physical address instance for the MAC address of the machine (string to byte array)
  109.         $MAC = [Net.NetworkInformation.PhysicalAddress]::Parse($MacAddress)
  110.  
  111.         ## Construct the Magic Packet frame
  112.         $Frame = [byte[]]@(255,255,255, 255,255,255);
  113.         $Frame += ($MAC.GetAddressBytes()*16)
  114.  
  115.         ## Broadcast UDP packets to the IP endpoints of the machine
  116.         for($i = 0; $i -lt $Packets; $i++) {
  117.             $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint1) | Out-Null
  118.             $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint2) | Out-Null
  119.             $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint3) | Out-Null
  120.             sleep 1;
  121.         }
  122.     }
  123.     catch
  124.     {
  125.         $Error | Write-Error;
  126.     }
  127. }
  128.  
  129. $i=1
  130. foreach($Machine in $File)
  131. {
  132.     $Name=$Machine.Name
  133.     $MacAddress=$Machine.MacAddress
  134.     $IPAddress=$Machine.IpAddress
  135.  
  136.     ## Send magic packet to wake machine
  137.     Write-Progress -ID 1 -Activity "Waking up machine $Name" -PercentComplete ($i*100/$file.Count)
  138.     Send-Packet $MacAddress $Packets
  139.  
  140.     $j=1
  141.     ## Go into loop until machine replies to echo
  142.     $Ping = New-Object System.Net.NetworkInformation.Ping
  143.     do
  144.     {
  145.         $Echo = $Ping.Send($IPAddress)
  146.         Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete ($j*100/$TimeOut)
  147.         sleep 1
  148.         
  149.         if ($j -eq $TimeOut)
  150.         {
  151.             Write-Host "Time out expired, aborting.";Write-Host
  152.             exit
  153.         }
  154.         $j++
  155.     }
  156.     while ($Echo.Status.ToString() -ne "Success" )
  157.  
  158.     ## Machine is alive, keep sending for $Replies amount
  159.     for ($k = 1; $k -le $Repeat; $k++)
  160.     {
  161.        Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete (100)
  162.        Write-Progress -Id 3 -ParentId 2 -Activity "Receiving echo reply"  -PercentComplete ($k*100/$Repeat)
  163.        sleep 1
  164.     }
  165.     $i++
  166.     Write-Progress -Id 3 -Completed $true
  167.     $Ping=$null
  168. }