Where does `powercfg` get battery health information, and why isn't it in WMI?

It looks like you have to dig into MSBattery super class:

A number of the classes in root\wmi return results from more than one class. That sounds odd but it can be explained by an example.

The namespace contains a number of classes related to the battery in laptops

gwmi -Namespace root\wmi -List *battery*

MSBatteryClassEvent
BatteryStatusChange
BatteryTagChange 
MSBatteryClass
BatteryStaticData
BatteryRuntime
BatteryCycleCount 
BatteryTemperature
BatteryStatus
BatteryFullChargedCapacity

We’ll ignore the event and change classes for now. If we pick out the MSBattery class we get information from a number of other classes returned – MSBattery is a super class.

PS> gwmi -Namespace root\wmi -Class MSBatteryClass | select __class

__CLASS  ——-
BatteryCycleCount
BatteryFullChargedCapacity
BatteryStaticData
BatteryRuntime BatteryStatus

Examples, that kind of work on my laptop:

Get-WmiObject -Namespace 'root\wmi' -Query 'select DeviceName, ManufactureName, Chemistry, DesignedCapacity from BatteryStaticData'

__GENUS          : 2
__CLASS          : BatteryStaticData
__SUPERCLASS     : 
__DYNASTY        : 
__RELPATH        : 
__PROPERTY_COUNT : 4
__DERIVATION     : {}
__SERVER         : 
__NAMESPACE      : 
__PATH           : 
Chemistry        : 1852787020
DesignedCapacity : 48400
DeviceName       : K52F-44
ManufactureName  : ASUSTek
PSComputerName   : 


Get-WmiObject -Namespace 'root\wmi'  -Query 'select FullChargedCapacity  from BatteryFullChargedCapacity'

__GENUS             : 2
__CLASS             : BatteryFullChargedCapacity
__SUPERCLASS        : 
__DYNASTY           : 
__RELPATH           : 
__PROPERTY_COUNT    : 1
__DERIVATION        : {}
__SERVER            : 
__NAMESPACE         : 
__PATH              : 
FullChargedCapacity : 47157
PSComputerName      : 


Get-WmiObject -Namespace 'root\wmi'  -Query 'select CycleCount from BatteryCycleCount'

__GENUS          : 2
__CLASS          : BatteryCycleCount
__SUPERCLASS     : 
__DYNASTY        : 
__RELPATH        : 
__PROPERTY_COUNT : 1
__DERIVATION     : {}
__SERVER         : 
__NAMESPACE      : 
__PATH           : 
CycleCount       : 0
PSComputerName   : 

Why kind of? Because while you can see that DesignedCapacity, FullChargedCapacity and CycleCount have some values, powercfg /batteryreport doesnt recoginze them:

Battery stats


Here is a simple WMI "crawler" that combines all battery-classes into one object:

# get battery-identifier:
$batteryClass = Get-WmiObject -Namespace root\WMI -Class MSBatteryClass
if (!$batteryClass) {'this device has no physical battery.'; break}
$batteryData = foreach ($entry in $batteryClass) {
    if ($entry.UniqueID) {$entry | select UniqueID, InstanceName}
}

# find data based on the UniqueID of the battery:
foreach ($entry in Get-wmiobject Win32_battery) {
    $battery = @($batteryData).where{$_.UniqueID -eq $entry.DeviceID}
    $attribs = $entry | Get-Member | ?{$_.MemberType -eq 'Property' -and !$_.name.startswith('__')}
    foreach ($a in $attribs.name) {
        $battery | Add-Member -Name "Win32_battery.$a" -Value $entry.$a -MemberType NoteProperty
    }
}

# find data based on the InstanceName of the battery:
foreach ($class in $batteryClass.__CLASS | select -Unique) {
    $classData = Get-WmiObject -Namespace root\WMI -Class $class
    foreach ($entry in $classData) {
        $battery = @($batteryData).where{$_.InstanceName -eq $entry.InstanceName}
        $attribs = $entry | Get-Member | ?{$_.MemberType -eq 'Property' -and !$_.name.startswith('__')}
        foreach ($a in $attribs.name) {
            $battery | Add-Member -Name "$class.$a" -Value $entry.$a -MemberType NoteProperty
        }
    }
}

$battery

Unfortunaltely the WMI-classes do not translate all values into readable format (e.g. chemistry is just a value but not a string) and also not any runtime estimation for the fully charged battery. That one comes from the history of all charg/discharge events into the powercfg-report.