86°F Knoxville
Mon–Fri 9–5 ETAnswered by a human
Automation · RESOLVED

After-Hours Patching Failed: Machines Asleep During Maintenance

Scheduled overnight patches couldn't run - 60% of workstations were powered off or sleeping. Enabled Wake-on-LAN across Dell, HP, and Lenovo fleet.

Incident

Law firm with 85 workstations, critical security patches that had to ship that week, and partners who bill in six-minute increments and lose their minds if a patch restart interrupts a redline. We scheduled the maintenance window for 2 AM to stay out of everybody's way. Morning-after report came in: 34 of 85 machines patched. The rest never phoned home because they were either powered off at the wall or asleep under the desk, and the RMM agent has no way to wake a machine that isn't online.

The challenge

Fleet was mixed vendor, which is where WoL gets annoying. Wake-on-LAN has two layers: the BIOS has to be configured to allow wake packets, and Windows has to be configured to let the NIC respond to them. Each vendor exposes BIOS settings differently, and none of them let you touch the BIOS through a regular Windows session without a vendor-specific tool. Doing 85 machines by hand with F2 at boot would have been a week of after-hours work.

  • Dell OptiPlex: 45 machines
  • HP EliteDesk: 28 machines
  • Lenovo ThinkCentre: 12 machines
  • WoL status: unknown across the fleet

Solution

We built one script that auto-detects the manufacturer via Win32_ComputerSystem and calls the right vendor tooling for each. Dell gets the DellBIOSProvider PowerShell module. HP gets the HP Client Management Script Library (CMSL). Lenovo gets direct WMI calls against the Lenovo_SetBiosSetting class. After BIOS is handled, the script configures Windows-side wake on all physical NICs using the MSPower_DeviceWakeEnable WMI class and enables the matching "Allow this device to wake the computer" and "Only allow a magic packet to wake the computer" settings.

wol_enable.ps1View on GitHub →
$ErrorActionPreference = 'Stop'

<#
██╗     ██╗███╗   ███╗███████╗██╗  ██╗ █████╗ ██╗    ██╗██╗  ██╗
██║     ██║████╗ ████║██╔════╝██║  ██║██╔══██╗██║    ██║██║ ██╔╝
██║     ██║██╔████╔██║█████╗  ███████║███████║██║ █╗ ██║█████╔╝
██║     ██║██║╚██╔╝██║██╔══╝  ██╔══██║██╔══██║██║███╗██║██╔═██╗
███████╗██║██║ ╚═╝ ██║███████╗██║  ██║██║  ██║╚███╔███╔╝██║  ██╗
╚══════╝╚═╝╚═╝     ╚═╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚══╝╚══╝ ╚═╝  ╚═╝
================================================================================
 SCRIPT   : Wake-on-LAN Enable                                           v1.0.3
 AUTHOR   : Limehawk.io
 DATE     : January 2026
 USAGE    : .\wol_enable.ps1
================================================================================
 FILE     : wol_enable.ps1
DESCRIPTION : Enables Wake-on-LAN settings for Ethernet adapters
--------------------------------------------------------------------------------
 README
--------------------------------------------------------------------------------
 PURPOSE

 Enables Wake-on-LAN (WOL) in both BIOS/UEFI and Windows NIC settings.
 Supports Dell, HP, and Lenovo systems with manufacturer-specific BIOS modules.
 Also enables WOL on all capable network adapters in Windows.

 DATA SOURCES & PRIORITY

 1) System manufacturer detection (CIM)
 2) Manufacturer-specific BIOS modules (Dell, HP, Lenovo)
 3) Windows NIC WOL settings (CIM)

 REQUIRED INPUTS

 None - script auto-detects manufacturer and configures accordingly.

 SETTINGS

 - Dell: Uses DellBIOSProvider module, sets WakeOnLan to "LANOnly"
 - HP: Uses HPCMSL module, sets Wake On Lan to "Boot to Hard Drive"
 - Lenovo: Uses WMI, sets WakeOnLAN to "Primary"
 - Windows: Enables MSPower_DeviceWakeEnable on all capable NICs

 BEHAVIOR

 1. Checks/installs required PowerShell modules (NuGet, PSGallery)
 2. Detects system manufacturer
 3. Installs manufacturer-specific BIOS module if needed
 4. Configures BIOS WOL setting
 5. Enables WOL on all capable Windows NICs

 PREREQUISITES

 - Windows 10/11
 - Admin privileges required
 - Internet connectivity for module installation
 - Supported manufacturer: Dell, HP, or Lenovo

 SECURITY NOTES

 - No secrets in logs
 - Modifies BIOS settings (requires admin)
 - Installs PowerShell modules from PSGallery

 EXIT CODES

 - 0: Success
 - 1: Warning (rerun required after PowerShellGet update)
 - Other: Manufacturer not supported or error

 EXAMPLE RUN

 [INFO] SYSTEM DETECTION
 ==============================================================
 Manufacturer : Dell Inc.

 [RUN] BIOS CONFIGURATION
 ==============================================================
 Installing DellBIOSProvider module...
 Setting WakeOnLan to LANOnly...
 BIOS WOL configured successfully

 [RUN] NIC CONFIGURATION
 ==============================================================
 Enabling WOL for Intel(R) Ethernet...
 NIC WOL enabled successfully

 [OK] RESULT
 ==============================================================
 Status : Success

 [OK] SCRIPT COMPLETE
 ==============================================================
--------------------------------------------------------------------------------
 CHANGELOG
--------------------------------------------------------------------------------
 2026-01-19 v1.0.3 Fixed EXAMPLE RUN section formatting
 2026-01-19 v1.0.2 Updated to two-line ASCII console output style
 2025-12-23 v1.0.1 Updated to Limehawk Script Framework
 2025-11-29 v1.0.0 Initial Style A implementation
================================================================================
#>

Set-StrictMode -Version Latest

# ==== STATE ====
$errorOccurred = $false
$errorText = ""
$resultCode = 0
$summary = ""

# ==== RUNTIME OUTPUT ====
Write-Host ""
Write-Host "[INFO] DEPENDENCY CHECK"
Write-Host "=============================================================="

# Check and install NuGet provider
$PPNuGet = Get-PackageProvider -ListAvailable | Where-Object { $_.Name -eq "Nuget" }
if (-not $PPNuGet) {
    Write-Host "[RUN] Installing NuGet provider..."
    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
    $summary += "Installed NuGet. "
} else {
    Write-Host "[OK] NuGet provider already installed"
}

# Check PSGallery
$PSGallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue
if (-not $PSGallery) {
    Write-Host "[RUN] Configuring PSGallery..."
    Set-PSRepository -InstallationPolicy Trusted -Name PSGallery
    $summary += "Configured PSGallery. "
} else {
    Write-Host "[OK] PSGallery already configured"
}

# Check PowerShellGet version
$PsGetVersion = (Get-Module PowerShellGet -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Version
if ($PsGetVersion -lt [version]'2.0') {
    Write-Host "[RUN] PowerShellGet version $PsGetVersion is outdated, updating..."
    try {
        Install-Module -Name PowerShellGet -MinimumVersion 2.2 -Force -AllowClobber -ErrorAction Stop
        Write-Host "[WARN] PowerShellGet updated. Please rerun this script."
        $summary += "Updated PowerShellGet. "
        $resultCode = 1
    } catch {
        Write-Host "[WARN] Could not update PowerShellGet: $($_.Exception.Message)"
        $summary += "PowerShellGet update failed. "
    }
}

if ($resultCode -eq 1) {
    Write-Host ""
    Write-Host "[WARN] RESULT"
    Write-Host "=============================================================="
    Write-Host "Status  : Rerun Required"
    Write-Host "Summary : $summary"
    Write-Host ""
    Write-Host "[INFO] SCRIPT COMPLETE"
    Write-Host "=============================================================="
    exit 1
}

Write-Host ""
Write-Host "[INFO] SYSTEM DETECTION"
Write-Host "=============================================================="

# Detect manufacturer
$Manufacturer = (Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer
Write-Host "Manufacturer : $Manufacturer"

Write-Host ""
Write-Host "[INFO] BIOS CONFIGURATION"
Write-Host "=============================================================="

try {
    if ($Manufacturer -like "*Dell*") {
        $summary += "Dell system. "
        Write-Host "[RUN] Detected Dell system"

        # Install Dell BIOS Provider if needed
        $Mod = Get-Module -ListAvailable -Name DellBIOSProvider
        if (-not $Mod) {
            Write-Host "[RUN] Installing DellBIOSProvider module..."
            Install-Module -Name DellBIOSProvider -Force -ErrorAction Stop
            $summary += "Installed DellBIOSProvider. "
        }
        Import-Module DellBIOSProvider -Global

        # Set WOL
        Write-Host "[RUN] Setting WakeOnLan to LANOnly..."
        Set-Item -Path "DellSmBios:\PowerManagement\WakeOnLan" -Value "LANOnly" -ErrorAction Stop
        Write-Host "[OK] Dell BIOS WOL configured successfully"
        $summary += "Dell WOL updated. "

    } elseif ($Manufacturer -like "*HP*" -or $Manufacturer -like "*Hewlett*") {
        $summary += "HP system. "
        Write-Host "[RUN] Detected HP system"

        # Install HP CMSL if needed
        $Mod = Get-Module -ListAvailable -Name HPCMSL
        if (-not $Mod) {
            Write-Host "[RUN] Installing HPCMSL module..."
            Install-Module -Name HPCMSL -Force -AcceptLicense -ErrorAction Stop
            $summary += "Installed HPCMSL. "
        }
        Import-Module HPCMSL -Global

        # Set WOL for all WOL-related settings
        Write-Host "[RUN] Configuring HP Wake On LAN settings..."
        $WolTypes = Get-HPBIOSSettingsList | Where-Object { $_.Name -like "*Wake On Lan*" }
        foreach ($WolType in $WolTypes) {
            Write-Host "  Setting: $($WolType.Name)"
            Set-HPBIOSSettingValue -Name $($WolType.Name) -Value "Boot to Hard Drive" -ErrorAction Stop
        }
        Write-Host "[OK] HP BIOS WOL configured successfully"
        $summary += "HP WOL updated. "

    } elseif ($Manufacturer -like "*Lenovo*") {
        $summary += "Lenovo system. "
        Write-Host "[RUN] Detected Lenovo system"

        # Set WOL via WMI
        Write-Host "[RUN] Setting WakeOnLAN via WMI..."
        (Get-WmiObject -Class "Lenovo_SetBiosSetting" -Namespace "root\wmi" -ErrorAction Stop).SetBiosSetting('WakeOnLAN,Primary') | Out-Null
        (Get-WmiObject -Class "Lenovo_SaveBiosSettings" -Namespace "root\wmi" -ErrorAction Stop).SaveBiosSettings() | Out-Null
        Write-Host "[OK] Lenovo BIOS WOL configured successfully"
        $summary += "Lenovo WOL updated. "

    } else {
        Write-Host "[WARN] Manufacturer '$Manufacturer' not supported for BIOS WOL configuration"
        Write-Host "Supported manufacturers: Dell, HP, Lenovo"
        $summary += "$Manufacturer not supported. "
    }
} catch {
    Write-Host "[WARN] BIOS WOL configuration failed: $($_.Exception.Message)"
    $summary += "BIOS WOL error. "
}

Write-Host ""
Write-Host "[INFO] NIC CONFIGURATION"
Write-Host "=============================================================="

# Enable WOL on all capable NICs
$NicsWithWake = Get-CimInstance -ClassName "MSPower_DeviceWakeEnable" -Namespace "root/wmi" -ErrorAction SilentlyContinue

if ($NicsWithWake) {
    foreach ($Nic in $NicsWithWake) {
        Write-Host "[RUN] Enabling WOL for: $($Nic.InstanceName)"
        try {
            Set-CimInstance -InputObject $Nic -Property @{Enable = $true} -ErrorAction Stop
            Write-Host "[OK] Success"
            $summary += "$($Nic.InstanceName) WOL enabled. "
        } catch {
            Write-Host "[WARN] $($_.Exception.Message)"
            $summary += "$($Nic.InstanceName) WOL error. "
        }
    }
} else {
    Write-Host "[WARN] No NICs with Wake-on-LAN capability found"
    $summary += "No WOL NICs found. "
}

Write-Host ""
Write-Host "[INFO] RESULT"
Write-Host "=============================================================="
Write-Host "Status  : Success"
Write-Host "Summary : $summary"

Write-Host ""
Write-Host "[INFO] FINAL STATUS"
Write-Host "=============================================================="
Write-Host "[OK] Wake-on-LAN configuration completed."
Write-Host "A reboot may be required for BIOS changes to take effect."

Write-Host ""
Write-Host "[INFO] SCRIPT COMPLETE"
Write-Host "=============================================================="
exit 0

Manufacturer handling

The script installs the required PowerShell module or library if it's missing, then sets the BIOS parameter by the vendor-specific name (Dell calls it "WakeOnLan", HP calls it "Wake on LAN", Lenovo uses "WakeOnLAN"). For Dell and Lenovo the BIOS password can be passed in as a parameter if the fleet has a shared admin password — HP's CMSL handles the BIOS setup PIN similarly. After BIOS is set, the Windows NIC side gets configured the same way across all three vendors because that part is OS-level, not firmware.

  • Dell: DellBIOSProvider PowerShell module
  • HP: HP Client Management Script Library (CMSL)
  • Lenovo: WMI (Lenovo_SetBiosSetting class)
  • Windows NIC: MSPower_DeviceWakeEnable WMI class
  • all of it driven from a single deployment

One thing worth calling out — BIOS changes don't take effect until reboot. The script applies the setting, then flags the machine for a reboot on next maintenance window. If you try to send a magic packet before the reboot, nothing happens and you'll think the script failed.

Outcome

Deployed to the whole fleet through the RMM. 85 of 85 reported successful configuration. We coordinated a single reboot cycle during the next lunch hour to apply the BIOS changes — nobody noticed because laptops get rebooted all the time. The following maintenance window: RMM sent magic packets at 1:55 AM, every machine came up, patches installed, and the RMM put them back to sleep at 4 AM. Next morning report: 85 of 85 patched. Zero user disruption, zero billable time lost to "why is my computer on this morning."

  • machines configured: 85 of 85
  • next patch window: 100% reached
  • deployment time: about 15 minutes running in parallel
  • patches installed on next overnight window: 85 of 85

Key takeaways