Trevor Sullivan's Tech Room

Minding the gap between administration and development

PowerShell: Enable / Disable Wake-on-LAN (in ConfigMgr)

Posted by Trevor Sullivan on 2010/08/12


Hello from Houston, Texas everyone!

Today I’ve got a PowerShell script that was specially developed for my consulting engagements going forward. When implementing 1E WakeUp at a customer, who is integrating it with ConfigMgr (to wake up machines using Software Distribution and Software Updates assignments), I have found that occasionally, a customer has already enabled wake-on-LAN for some of their distributions. The purpose of this script is to disable, or enable, the wake-on-LAN option for all ConfigMgr software distribution Advertisements and Updates Assignments (aka. Deployment Management objects).

Before I get into the script however, I’d like to talk about why 1E WakeUp can help to enhance your organization’s patching and software distribution success.

Why 1E WakeUp? What about ConfigMgr Wake-On-LAN? (this is optional reading)

Now at this point, you might be asking yourself an important question: “Why do I need 1E WakeUp, if ConfigMgr has built-in wake-on-LAN capabilities?” That’s a great question! There are several reasons why 1E WakeUp can help you, in tandem with ConfigMgr.

Distributed Wake-on-LAN

ConfigMgr’s wake-on-LAN functionality is centralized, meaning that only ConfigMgr Primary site servers can send wake-up packets to clients. There are two types of wake-up packets that ConfigMgr sends out, each of which uncovers a unique challenge:

  • Unicast Unicast packets are subject to fail if a switch’s ARP cache expires
  • Subnet-directed Broadcast – Most enterprise routers block broadcast traffic for security reasons

1E WakeUp is able to work around these issues by sending out wake-up frames on the local subnet using a software agent that sits on each client system. The 1E WakeUp Server sends a list of computers to wake up, down to the local 1E WakeUp “main proxy agent” on each subnet, and that proxy agent is then responsible for sending out broadcasts on its local subnet only. This is beneficial, because no modifications are required to the network infrastructure, in order to reliably wake up computers in subnets that are distant from the ConfigMgr primary site.

What happens if the “main agent” for a subnet is taken offline (eg. a user shuts it down)? Another agent in the same subnet will automagically (hey, I like that word!) take over as the main agent, and the solution will continue to function normally!

Last Known IP

ConfigMgr uses the last known IP address from its hardware inventory to determine what IP address (unicast) or subnet (subnet-directed broadcast) to send a wakeup packet to. This can cause wake-up challenges if a computer has not recently run a hardware inventory cycle, or changed subnets (eg. a laptop changing from a docked / wired connection, to wireless). 1E WakeUp works around this situation, because the software agent on each computer updates its IP address with the WakeUp server every time its IP changes. Thus, the most up-to-date IP information is always stored in the 1E database, and is used to more accurately target wake-up packets.

Summary

There are other reasons that the 1E WakeUp solution works better together with ConfigMgr, but I personally think the above two points are most critical. Anyway, now that I’ve gone off on a tangent and explained why 1E WakeUp is awesome, let’s talk about the script!

—–

Why Would You Blanketly Disable Wake-on-LAN?

When first implementing 1E WakeUp with ConfigMgr integration, unless you switch off the “Enable Wake-on-LAN” option for ConfigMgr advertisements and updates assignments, the WakeUp Server will automatically process these scheduled assignments, and begin waking up workstations! Depending on your goals with implementing 1E WakeUp, this may or may not be desirable. For example, some customers are implementing 1E WakeUp to help increase software distribution and patching success, while others are looking to save energy using 1E NightWatchman, while simultaneously making sure that computers can be made available when necessary using 1E WakeUp.

For those customers looking to save energy, and only perform controlled wake-ups of enterprise clients, it may make sense to disable wake-on-LAN for any scheduled deployments. Conversely, for customers looking to increase deployment success, it may make sense to enable wake-on-LAN for all deployments! The script I’ve included below will do both!

Script Usage

To use the script below, all you need to do is:

  1. Find the “Configuration Section” near the bottom
  2. Plug in your ConfigMgr site server name
  3. Plug in your ConfigMgr site code
  4. Set the $EnableWolAdverts and $EnableWolUpdates to $true or $false dependent on your needs
  5. Enable the $ReallyRun variable by setting it to $true (this is just a safe guard)
  6. Run the script!

Disclaimer: I take no responsibility for what you do with this script!


########################################################
# Enable Wake-on-LAN for all SMS_Advertisement objects #
########################################################

#######################################################################
# Wake-on-LAN is the 22nd bit in the AdvertFlags property, which is
# 2 to the 22nd power. The decimal (base-10) value of this is: 4194304.
# 
#
#######################################################################

function Set-WoLAdvertisements([bool] $EnableWol)
{
    Log-Message 3 "Enabling wake-on-lan for all advertisements in site code: $SiteCode"

    $AdvertisementList = @()
    $AdvertisementList = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -ComputerName $SiteServer -Class SMS_Advertisement -ErrorAction SilentlyContinue
    # If an error occurs, exit the function
    if (-not $?) {
        Log-Message 1 "Error detected while retrieving advertisement list"
        Start-Sleep 2
        return $null
    }

    # Iterate over advertisement objects from ConfigMgr provider
    foreach ($Advertisement in $AdvertisementList)
    {
        # Get a direct reference to the WMI object - The ConfigMgr provider requires this for lazy properties
        $Advertisement = [wmi]"$($Advertisement.Path)"

        # Grab the current AdvertFlags value, to compare with the updated one later
        $AdvertFlagsOld = $Advertisement.AdvertFlags

        # If Wake-on-LAN is enabled, then ...
        if (($Advertisement.AdvertFlags -band 4194304) -eq 4194304 -and -not $EnableWol) {
            Log-Message 3 "Wake-on-LAN is enabled, but disablement has been requested; Disabling ..."
            $Advertisement.AdvertFlags = $Advertisement.AdvertFlags -bxor 4194304
        }
        # If Wake-on-LAN is disabled, then ...
        elseif (($Advertisement.AdvertFlags -band 4194304) -eq 0 -and $EnableWol) {
            Log-Message 3 "Wake-on-LAN is disabled, but enablement has been requested; Enabling ..."
            $Advertisement.AdvertFlags = $Advertisement.AdvertFlags -bxor 4194304
        }

        # Echo the old and new $AdvertFlags
        Log-Message 3 "`$AdvertFlagsOld: $AdvertFlagsOld -- New: $($Advertisement.AdvertFlags)"

        # If $ReallyRun is $true, then go ahead and write the instance back to the provider
        if ($ReallyRun) {
            # Commit the in-memory WMI instance to the ConfigMgr provider
            $PutResult = $Advertisement.Put()
            if ($?) {
                Log-Message 3 "Successfully enabled WoL for advertisement: $($Advertisement.AdvertisementName)"
            }
        }
        # If $ReallyRun is $false, then just echo the advertisement name that would have been updated
        else {
            Log-Message 2 "Pretending to set Wake-on-LAN for advertisement: $($Advertisement.AdvertisementName)"
        }
    }
    Log-Message 3 "Completed enabling wake-on-lan for all advertisements in site code: $SiteCode"
}

############################################################
# END Enable Wake-on-LAN for all SMS_Advertisement objects #
############################################################


########################################################
# Enable Wake-on-LAN for SMS_UpdatesAssignment objects #
########################################################

function Set-UpdatesAssignmentWol([bool] $EnableWol)
{
    Log-Message 3 "Enabling wake-on-LAN for all SUP deployment management objects in site code: $SiteCode"
    $Updates = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -ComputerName $SiteServer -Class SMS_UpdatesAssignment -ErrorAction SilentlyContinue
    # If an error occurs, exit the function
    if (-not $?) {
        Log-Message 1 "Error detected while retrieving updates assignment list"
        # Exit the function, returning $null
        return $null
    }

    # Iterate over each SMS_UpdatesAssignment
    foreach ($UpdateObj in $Updates)
    {
        # Set the WoLEnabled property to $true or $false
        $UpdateObj.WoLEnabled = $EnableWol

        # Only commit the change to the provider if we REALLY want to (this is a safe-guard)
        if ($ReallyRun) {
            # Commit updated WMI instance to the provider
            $PutResult = $UpdateObj.Put()

            # Error handler
            if ($?) {
                Log-Message 3 "Successfully enabled WoL for deployment management object: $($UpdateObj.AssignmentName)"
            }
            else {
                Log-Message 1 "An error occurred enabling WoL for deployment management object: $($UpdateObj.AssignmentName)"
            }
        }
        # If we don't have $ReallyRun set to $true, then just echo the name of the object we would be updating
        else {
            Log-Message 3 "Pretending to enable WoL for deployment management object: $($UpdateObj.AssignmentName)"
        }
    }
}

############################################################
# END Enable Wake-on-LAN for SMS_UpdatesAssignment objects #
############################################################

################################
# Get-DateTimeShort() function #
################################

function Get-DateTimeShort()
{
    $Date = [DateTime]::Now
    $tDate = "$($Date.Year)-$($Date.Month.ToString().PadLeft(2,'0'))-$($Date.Day.ToString().PadLeft(2,'0'))"
    $tDate = $tDate + " $(($Date.Hour % 12).ToString().PadLeft(2,'0')).$($Date.Minute.ToString().PadLeft(2,'0')).$($Date.Second.ToString().PadLeft(2,'0'))"
    Write-Output $tDate
}

####################################
# END Get-DateTimeShort() function #
####################################

##########################
# Log-Message() function #
##########################

function Log-Message($tSeverity, $tMessage)
{
    switch ($tSeverity)
    {
        1
        { $tSeverity = "ERROR" }
        2
        { $tSeverity = "WARNING" }
        3
        { $tSeverity = "INFO" }
        default
        { $tSeverity = "INFO" }
    }

    $tMessage = "$(Get-DateTimeShort): $tSeverity`: $tMessage"
    Add-Content -Path $LogPath -Value $tMessage
}

##############################
# END Log-Message() function #
##############################

#################### Configuration Section ####################
$SiteServer = 'sccm01'
$SiteCode = 'lab'
$ReallyRun = $false # Set this to $true if you want to actually affect objects
$LogPath = $env:windir + "\Temp\$(Get-DateTimeShort) Set-ConfigMgrWoL.log"
$EnableWolAdverts = $true
$EnableWolUpdates = $true
###############################################################

function Main()
{
    Log-Message 3 "Starting script."
    if (-not $ReallyRun) { Log-Message 2 "Script is running in read-only mode! No changes will be made!" }

    Set-UpdatesAssignmentWol $EnableWolUpdates
    Set-WoLAdvertisements $EnableWolAdverts

    if (-not $ReallyRun) { Log-Message 2 "Script is running in read-only mode! No changes were made!" }
    Log-Message 3 "Script completed."
}

Main
Advertisements

2 Responses to “PowerShell: Enable / Disable Wake-on-LAN (in ConfigMgr)”

  1. Your powershell skillz are handy as always. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: