Run a script only if client is connected to AC power

08/06/2023

In the age of remote work, managing hundreds of client machines can be a bit of a hassle. In a perfect world, all remote clients would receive new software deployments and updates 100% of the time.

Unless you run an authoritarian organization, you cannot mandate that everyone connect their laptops to the internet and to AC power at exactly 4pm on the second Tuesday of the month in preparation for an urgent security update. Instead, you can use the traditional tools to manage updates and let the clients update the next time they check in. No problem.

But let’s think about when we are pushing a critical software package to company laptops. Some tools are better than others, but you might not have the best of the best.

I recently found myself needing to push an important update to all Windows clients, and needed to ensure as successful a deployment as possible.

To eliminate one failure point, I thought it would be helpful to tell the clients not to update if they are operating on battery power. We don’t want a machine shutting down mid-installation — this particular software update could brick the computer in such a scenario.

Here’s a sample script using PowerShell + CIM, with my notes, you can use to accomplish this.

# Let's make sure the Win32_SystemEnclosure CIM class is installed (by default, it is).

If (Get-CimClass -ClassName Win32_SystemEnclosure -ErrorAction SilentlyContinue) {
        Write-Output "CIM class exists"

# Use the aforementioned CIM class to get the type of chassis of the current computer. Obviously, if it's not a laptop, we don't need to check whether it is connected to AC power.

        $ChassisTypes = (Get-CimInstance -Class Win32_SystemEnclosure).ChassisTypes

# Set the value of the $Chassis variable based upon the value returned by the previous command.

        Switch($ChassisTypes) {

        3 { $Chassis = "Desktop" }
        4 { $Chassis = "Desktop" }
        5 { $Chassis = "Desktop" }
        6 { $Chassis = "Desktop" }
        7 { $Chassis = "Desktop" }
        8 { $Chassis = "Laptop" }
        9 { $Chassis = "Laptop" }
        10 { $Chassis = "Laptop" }
        11 { $Chassis = "Laptop" }
        12 { $Chassis = "Laptop" }
        14 { $Chassis = "Laptop" }
        15 { $Chassis = "Desktop" }
        16 { $Chassis = "Desktop" }
        18 { $Chassis = "Laptop" }
        21 { $Chassis = "Laptop" }
        23 { $Chassis = "Server" }
        31 { $Chassis = "Laptop" }
        }

        If($Chassis -eq "Laptop") {

# Get the current power status by calling on the BatteryStatus CIM Class. The PowerOnline property will either return True or False.
# In this case, we have to specify the Namespace root\wmi because the PowerOnline property is not available in the default namespace of root\cimv2
            $PowerStatus = (Get-CimInstance -Class BatteryStatus  -Namespace root\wmi -ErrorAction SilentlyContinue).PowerOnLine
   
                If($PowerStatus -eq $True) {
 
                    write-output "Power is connected. Proceed with installation"
#PUT YOUR INSTALL SCRIPT HERE

                }

	            Else {
#Abort install if AC power is not connected
		            write-output "Power is not connected. Abort installation"
                }
        }
        ElseIf($Chassis -ne "Laptop"){
            write-output "Not a laptop. Power is connected"}
# PUT YOUR INSTALL SCRIPT HERE

} 
        else {
            Write-output "CIM class Win32_SystemEnclosure doesn't exist. Abort."

        }

Additional notes

Keep in mind this is a very basic script that does not include error handling or logging.
Using this template, you will also need to put your install script in two different places.
You could of course create a variable that checks conditions so that you only have one ‘install script’ block.

Always test before using in production.

If you aren’t familiar with CIM, here is a helpful article about why you should use it instead of WMI. Test out the following commands on your own computer!:

# Get all properties of the Win32_SystemEnclosure class, and the current value.
Get-CimInstance -Class Win32_SystemEnclosure | select *

# Open up a GUI to explore all the WMI/CIM object classes. The default namespace is root\cimv2
# This command opens the Windows Management Instrumentation tester
webemtest

#another way to get this information is to use: 
Get-CimClass *