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
- #######################################################
- ##
- ## WakeUp-Machines.ps1, v1.0, 2012
- ##
- ## Created by Matthijs ten Seldam, Microsoft
- ##
- #######################################################
- <#
- .SYNOPSIS
- Starts a list of physical machines by using Wake On LAN.
- .DESCRIPTION
- 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.
- .PARAMETER Machines
- The name of the file containing the machines to wake.
- .PARAMETER Interface
- The IP address of the interface to use to wake up the machines.
- .PARAMETER Subnet
- The subnet mask of the interface to use to wake up the machines.
- .EXAMPLE
- WakeUp-Machines machines.csv 192.168.0.1 255.255.255.0
- .EXAMPLE
- WakeUp-Machines c:\tools\machines.csv 192.168.0.1 255.255.255.0
- .INPUTS
- None
- .OUTPUTS
- None
- .NOTES
- Make sure the Wake On LAN command line tool is available in the same location as the script!
- The CSV file with machines must be outlined using Name, MAC Address and IP Address with the first line being Name,MacAddress,IpAddress.
- See below for an example of a properly formatted CSV file.
- Name,MacAddress,IpAddress
- Host1,A0DEF169BE02,192.168.0.11
- Host3,AC1708486CA2,192.168.0.12
- Host2,FDDEF15D5401,192.168.0.13
- .LINK
- https://blogs.technet.com/matthts
- #>
- param(
- [Parameter(Mandatory=$true, HelpMessage="Provide the path to the CSV file containing the machines to wake.")]
- [string] $Machines,
- [Parameter(Mandatory=$true, HelpMessage="Provide the IP address of the interface to use for Wake On LAN.")]
- [string] $Interface,
- [Parameter(Mandatory=$true, HelpMessage="Provide the subnet mask of the interface to use for Wake On LAN.")]
- [string] $Subnet
- )
- ## Predefined variables
- $WolCmd=".\wolcmd.exe"
- $TimeOut = 30
- $Replies = 10
- clear;Write-Host
- ## Verify if WOL tool exists
- try
- {
- Get-ChildItem $WolCmd | Out-Null
- }
- Catch
- {
- Write-Host "$WolCmd file not found!";Write-Host
- exit
- }
- ## Read CSV file with machine names
- try
- {
- $File=Import-Csv $Machines
- }
- Catch
- {
- Write-Host "$Machines file not found!";Write-Host
- exit
- }
- $i=1
- foreach($Machine in $File)
- {
- $Name=$Machine.Name
- $MAC=$Machine.MacAddress
- $IP=$Machine.IpAddress
- ## Send magic packet to wake machine
- Write-Progress -ID 1 -Activity "Waking up machine $Name" -PercentComplete ($i*100/$file.Count)
- Invoke-Expression "$WolCmd $MAC $Interface $Subnet" | Out-Null
- $j=1
- ## Go into loop until machine replies to echo
- $Ping = New-Object System.Net.NetworkInformation.Ping
- do
- {
- $Echo = $Ping.Send($IP)
- Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete ($j*100/$TimeOut)
- sleep 1
- if ($j -eq $TimeOut)
- {
- Write-Host "Time out expired, aborting.";Write-Host
- exit
- }
- $j++
- }
- while ($Echo.Status.ToString() -ne "Success" )
- ## Machine is alive, keep sending for $Replies amount
- for ($k = 1; $k -le $Replies; $k++)
- {
- Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete (100)
- Write-Progress -Id 3 -ParentId 2 -Activity "Receiving echo reply" -PercentComplete ($k*100/$Replies)
- sleep 1
- }
- $i++
- Write-Progress -Id 3 -Completed $true
- $Ping=$null
- }
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
- #######################################################
- ##
- ## WakeUp-Machines.ps1, v1.1, 2012
- ##
- ## Created by Matthijs ten Seldam, Microsoft
- ##
- #######################################################
- <#
- .SYNOPSIS
- Starts a list of physical machines by using Wake On LAN.
- .DESCRIPTION
- 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.
- .PARAMETER Machines
- The name of the file containing the machines to wake.
- .PARAMETER TimeOut
- The number of seconds to wait for an echo reply before continuing with the next machine.
- .PARAMETER Repeat
- The number of echo requests to send before continuing with the next machine.
- .EXAMPLE
- WakeUp-Machines machines.csv
- .EXAMPLE
- WakeUp-Machines c:\tools\machines.csv
- .INPUTS
- None
- .OUTPUTS
- None
- .NOTES
- Make sure the MAC addresses supplied don't contain "-" or ".".
- The CSV file with machines must be outlined using Name, MAC Address and IP Address with the first line being Name,MacAddress,IpAddress.
- See below for an example of a properly formatted CSV file.
- Name,MacAddress,IpAddress
- Host1,A0DEF169BE02,192.168.0.11
- Host3,AC1708486CA2,192.168.0.12
- Host2,FDDEF15D5401,192.168.0.13
- .LINK
- https://blogs.technet.com/matthts
- #>
- param(
- [Parameter(Mandatory=$true, HelpMessage="Path to the CSV file containing the machines to wake.")]
- [string] $Machines,
- [Parameter(Mandatory=$false, HelpMessage="Number of unsuccesful echo requests before continuing.")]
- [int] $TimeOut=30,
- [Parameter(Mandatory=$false, HelpMessage="Number of successful echo requests before continuing.")]
- [int] $Repeat=10,
- [Parameter(Mandatory=$false, HelpMessage="Number of magic packets to send to the broadcast address.")]
- [int] $Packets=2
- )
- Set-StrictMode -Version Latest
- clear;Write-Host
- ## Read CSV file with machine names
- try
- {
- $File=Import-Csv $Machines
- }
- Catch
- {
- Write-Host "$Machines file not found!";Write-Host
- exit
- }
- function Send-Packet([string]$MacAddress, [int]$Packets)
- {
- <#
- .SYNOPSIS
- Sends a number of magic packets using UDP broadcast.
- .DESCRIPTION
- Send-Packet sends a specified number of magic packets to a MAC address in order to wake up the machine.
- .PARAMETER MacAddress
- The MAC address of the machine to wake up.
- .PARAMETER
- The number of packets to send.
- #>
- try
- {
- $Broadcast = ([System.Net.IPAddress]::Broadcast)
- ## Create UDP client instance
- $UdpClient = New-Object Net.Sockets.UdpClient
- ## Create IP endpoints for each port
- $IPEndPoint1 = New-Object Net.IPEndPoint $Broadcast, 0
- $IPEndPoint2 = New-Object Net.IPEndPoint $Broadcast, 7
- $IPEndPoint3 = New-Object Net.IPEndPoint $Broadcast, 9
- ## Construct physical address instance for the MAC address of the machine (string to byte array)
- $MAC = [Net.NetworkInformation.PhysicalAddress]::Parse($MacAddress)
- ## Construct the Magic Packet frame
- $Frame = [byte[]]@(255,255,255, 255,255,255);
- $Frame += ($MAC.GetAddressBytes()*16)
- ## Broadcast UDP packets to the IP endpoints of the machine
- for($i = 0; $i -lt $Packets; $i++) {
- $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint1) | Out-Null
- $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint2) | Out-Null
- $UdpClient.Send($Frame, $Frame.Length, $IPEndPoint3) | Out-Null
- sleep 1;
- }
- }
- catch
- {
- $Error | Write-Error;
- }
- }
- $i=1
- foreach($Machine in $File)
- {
- $Name=$Machine.Name
- $MacAddress=$Machine.MacAddress
- $IPAddress=$Machine.IpAddress
- ## Send magic packet to wake machine
- Write-Progress -ID 1 -Activity "Waking up machine $Name" -PercentComplete ($i*100/$file.Count)
- Send-Packet $MacAddress $Packets
- $j=1
- ## Go into loop until machine replies to echo
- $Ping = New-Object System.Net.NetworkInformation.Ping
- do
- {
- $Echo = $Ping.Send($IPAddress)
- Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete ($j*100/$TimeOut)
- sleep 1
- if ($j -eq $TimeOut)
- {
- Write-Host "Time out expired, aborting.";Write-Host
- exit
- }
- $j++
- }
- while ($Echo.Status.ToString() -ne "Success" )
- ## Machine is alive, keep sending for $Replies amount
- for ($k = 1; $k -le $Repeat; $k++)
- {
- Write-Progress -ID 2 -ParentID 1 -Activity "Waiting for $Name to respond to echo" -PercentComplete (100)
- Write-Progress -Id 3 -ParentId 2 -Activity "Receiving echo reply" -PercentComplete ($k*100/$Repeat)
- sleep 1
- }
- $i++
- Write-Progress -Id 3 -Completed $true
- $Ping=$null
- }