Some of my friends (Hi Joe! Hi Tyler!) recently requested a script to both monitor and enable WOL for workstations at their clients. WOL stands for Wake-On-Lan and is used to boot machines without user intervention. There are two forms of WOL: OS based, to let a machine start up from standby or hibernation, and BIOS based to boot computers which are completely turned off.
With the current stress of everyone wanting to work from home via all sorts of tools, my friends found some devices that aren’t replying to WOL packets or machines that simply were not configured for WOL yet.
I figured this could be a pretty cool exercise, I’ve seen a bunch of people making very device specific scripts to enable WOL, but not a lot of manufacture specific scripts that would enable it for an entire line of devices. During my discoveries I’ve found that the three biggest manufactures all have a method to enable WOL directly with PowerShell. Two of them use a module, the other uses a WMI class.
The script will work for Dell, HP, and Lenovo. Disclaimer: I tested the script on a handful of devices, so no guarantees of course. 🙂
The monitoring script
The monitoring script only works with PowerShell 5.0 or higher. It will also update PowerShell Get and also download the correct module for the device. We match based on the device manufacture in WMI.
$PPNuGet = Get-PackageProvider -ListAvailable | Where-Object { $_.Name -eq "Nuget" } if (!$PPNuget) { Write-Host "Installing Nuget provider" -foregroundcolor Green Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force } $PSGallery = Get-PSRepository -Name PsGallery if (!$PSGallery) { Write-Host "Installing PSGallery" -foregroundcolor Green Set-PSRepository -InstallationPolicy Trusted -Name PSGallery } $PsGetVersion = (get-module PowerShellGet).version if ($PsGetVersion -lt [version]'2.0') { Write-Host "Installing latest version of PowerShellGet provider" -foregroundcolor Green install-module PowerShellGet -MinimumVersion 2.2 -Force Write-Host "Reloading Modules" -foregroundcolor Green Remove-Module PowerShellGet -Force Remove-module PackageManagement -Force Import-Module PowerShellGet -MinimumVersion 2.2 -Force Write-Host "Updating PowerShellGet" -foregroundcolor Green Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -force Write-Host "You must rerun the script to succesfully get the WOL status. PowerShellGet was found out of date." -ForegroundColor red exit 1 } Write-Host "Checking Manufacturer" -foregroundcolor Green $Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer if ($Manufacturer -like "*Dell*") { Write-Host "Manufacturer is Dell. Installing Module and trying to get WOL state" -foregroundcolor Green Write-Host "Installing Dell Bios Provider if needed" -foregroundcolor Green $Mod = Get-Module DellBIOSProvider if (!$mod) { Install-Module -Name DellBIOSProvider -Force } import-module DellBIOSProvider try { $WOLMonitor = get-item -Path "DellSmBios:\PowerManagement\WakeOnLan" -ErrorAction SilentlyContinue if ($WOLMonitor.currentvalue -eq "LanOnly") { $WOLState = "Healthy" } } catch { write-host "an error occured. Could not get WOL setting." } } if ($Manufacturer -like "*HP*" -or $Manufacturer -like "*Hewlett*") { Write-Host "Manufacturer is HP. Installing module and trying to get WOL State." -foregroundcolor Green Write-Host "Installing HP Provider if needed." -foregroundcolor Green $Mod = Get-Module HPCMSL if (!$mod) { Install-Module -Name HPCMSL -Force -AcceptLicense } import-module HPCMSL try { $WolTypes = get-hpbiossettingslist | Where-Object { $_.Name -like "*Wake On Lan*" } $WOLState = ForEach ($WolType in $WolTypes) { write-host "Setting WOL Type: $($WOLType.Name)" get-HPBIOSSettingValue -name $($WolType.name) -ErrorAction Stop } } catch { write-host "an error occured. Could not find WOL state" } } if ($Manufacturer -like "*Lenovo*") { Write-Host "Manufacturer is Lenovo. Trying to get via WMI" -foregroundcolor Green try { Write-Host "Getting BIOS." -foregroundcolor Green $currentSetting = (Get-WmiObject -ErrorAction Stop -class "Lenovo_BiosSetting" -namespace "root\wmi") | Where-Object { $_.CurrentSetting -ne "" } $WOLStatus = $currentSetting.currentsetting | ConvertFrom-Csv -Delimiter "," -Header "Setting", "Status" | Where-Object { $_.setting -eq "Wake on lan" } $WOLStatus = $WOLStatus.status -split ";" if ($WOLStatus[0] -eq "Primary") { $WOLState = "Healthy" } } catch { write-host "an error occured. Could not find WOL state" } } $NicsWithWake = Get-CimInstance -ClassName "MSPower_DeviceWakeEnable" -Namespace "root/wmi" | Where-Object { $_.Enable -eq $False } if (!$NicsWithWake) { $NICWOL = "Healthy - All NICs enabled for WOL within the OS." } else { $NICWOL = "Unhealthy - NIC does not have WOL enabled inside of the OS." } if (!$WOLState) { $NICWOL = "Unhealthy - Could not find WOL state" }
After running the script we can check the contents of $WOLState for the current state of the WOL setting in the BIOS. You can also check $NICWOL for the Operating System’s WOL state.
The remediation script
So on the remediation side we tackle enabling WOL in both the BIOS and inside of the Operating System. We always install the module in this case, as often module updates are released when newer systems are too.
$PPNuGet = Get-PackageProvider -ListAvailable | Where-Object { $_.Name -eq "Nuget" } if (!$PPNuget) { Write-Host "Installing Nuget provider" -foregroundcolor Green Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force } $PSGallery = Get-PSRepository -Name PsGallery if (!$PSGallery) { Write-Host "Installing PSGallery" -foregroundcolor Green Set-PSRepository -InstallationPolicy Trusted -Name PSGallery } $PsGetVersion = (get-module PowerShellGet).version if ($PsGetVersion -lt [version]'2.0') { Write-Host "Installing latest version of PowerShellGet provider" -foregroundcolor Green install-module PowerShellGet -MinimumVersion 2.2 -Force Write-Host "Reloading Modules" -foregroundcolor Green Remove-Module PowerShellGet -Force Remove-module PackageManagement -Force Import-Module PowerShellGet -MinimumVersion 2.2 -Force Write-Host "Updating PowerShellGet" -foregroundcolor Green Install-Module -Name PowerShellGet -MinimumVersion 2.2.3 -force write-host "You must rerun the script to succesfully set the WOL status. PowerShellGet was found out of date." -ForegroundColor red } Write-Host "Checking Manufacturer" -foregroundcolor Green $Manufacturer = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer if ($Manufacturer -like "*Dell*") { Write-Host "Manufacturer is Dell. Installing Module and trying to enable Wake on LAN." -foregroundcolor Green Write-Host "Installing Dell Bios Provider" -foregroundcolor Green Install-Module -Name DellBIOSProvider -Force import-module DellBIOSProvider try { set-item -Path "DellSmBios:\PowerManagement\WakeOnLan" -value "LANOnly" -ErrorAction Stop } catch { write-host "an error occured. Could not set BIOS to WakeOnLan. Please try setting WOL manually" } } if ($Manufacturer -like "*HP*" -or $Manufacturer -like "*Hewlett*") { Write-Host "Manufacturer is HP. Installing module and trying to enable WakeOnLan. All HP Drivers are required for this operation to succeed." -foregroundcolor Green Write-Host "Installing HP Provider" -foregroundcolor Green Install-Module -Name HPCMSL -Force -AcceptLicense import-module HPCMSL try { $WolTypes = get-hpbiossettingslist | Where-Object { $_.Name -like "*Wake On Lan*" } ForEach ($WolType in $WolTypes) { write-host "Setting WOL Type: $($WOLType.Name)" Set-HPBIOSSettingValue -name $($WolType.name) -Value "Boot to Hard Drive" -ErrorAction Stop } } catch { write-host "an error occured. Could not set BIOS to WakeOnLan. Please try manually" } } if ($Manufacturer -like "*Lenovo*") { Write-Host "Manufacturer is Lenovo. Trying to set via WMI. All Lenovo Drivers are required for this operation to succeed." -foregroundcolor Green try { Write-Host "Setting BIOS." -foregroundcolor Green (Get-WmiObject -ErrorAction Stop -class "Lenovo_SetBiosSetting" -namespace "root\wmi").SetBiosSetting('WakeOnLAN,Primary') | Out-Null Write-Host "Saving BIOS." -foregroundcolor Green (Get-WmiObject -ErrorAction Stop -class "Lenovo_SaveBiosSettings" -namespace "root\wmi").SaveBiosSettings() | Out-Null } catch { write-host "an error occured. Could not set BIOS to WakeOnLan. Please try manually" } } write-host "Setting NIC to enable WOL" -ForegroundColor Green $NicsWithWake = Get-CimInstance -ClassName "MSPower_DeviceWakeEnable" -Namespace "root/wmi" foreach ($Nic in $NicsWithWake) { write-host "Enabling for NIC" -ForegroundColor green Set-CimInstance $NIC -Property @{Enable = $true } }
Like I said in the start – This still is slightly experimental for me. I did not have a large stack of devices to test on other than Dell devices, so if you find any issues with Lenovo or HP devices, let me know and send me a transcript, maybe I can help you figure it out!
And that’s it. As always, Happy PowerShelling.
update: N-Central remediation AMP can be found here. The monitoring AMP can be found here.
Update 2: Fixed a small encoding issue that crashed the script in some cases.
Update 3: Added better detection logic for nuget which causes a script hang, fixed an import and install module issue. This has not been updated inside of the monitoring AMPs. Please copy and paste the latest script in there. 🙂
Hi Kelvin, Interesting project. I think it’s a bit late for some… Will the script set the BIOS to enable Wake-on -LAN ?
I don’t know for sure, but I imagine the PC will have to be ON for the script to work ?
I apologise for the naivety of the question, please cut me some slack !
Yeah the script’s been out for a while now, but I think a lot of people already covered it. 🙂
No worries about questions – We’re all in this to learn. The PC will have to be on, and the script will change the BIOS settings. 🙂
I had to change the values/settings the HP and Lenovo were using to get it to work on the two PCs I tested.
(Get-WmiObject -ErrorAction Stop -class “Lenovo_SetBiosSetting” -namespace “root\wmi”).SetBiosSetting(‘WakeOnLAN,Enable’) | Out-Null
‘WakeOnLAN,Enable’ instead of ‘WakeOnLAN,Primary’
on the HP Side
Set-HPBIOSSettingValue -name $($WOLType.name) -Value “Follow Boot Order” -ErrorAction Stop
“Follow Boot Order” instead of “Boot to Hard Drive”
Yeah that’s the issue with so many different models – Each option is named a little different. We customized this for the models we use most, but it will need more customization for your own fleet of devices, hence the experimental comment 🙂
Hello! Amazing work! I’m trying to know if it’s possible to listen an incoming WOL Packet using CMD or Powershell? You may knows, considering your experience. Could you help me? Thanks!
I just want to find a way to fire a task in Windows 10 when WOL Packet is received. Is that possible?
I have no clue to be honest, I know WireShark can detect Magic Packets, you could try something like https://devblogs.microsoft.com/scripting/packet-sniffing-with-powershell-getting-started/.
Thank you! I apreciate it! I’m reading that article.