Private/Kinds/Battery.ps1

# The Battery Kind: how much of the battery is left, as a fraction of what it shipped with.
#
# This is not a Check about running on battery. Several vendors throttle the processor hard
# when the battery is worn even with the charger plugged in, so a worn battery is one of the
# few single facts that explains a laptop that is slow all the time and fine on a colleague's
# identical machine.

$script:BatteryNeedsAdmin = $true

function Get-BatteryData {
    [CmdletBinding()]
    [OutputType([psobject])]
    param([hashtable]$Parameters = @{})

    $design = $null
    $full   = $null
    try {
        $design = @(Get-CimInstance -Namespace root/wmi -ClassName BatteryStaticData -ErrorAction Stop)[0].DesignedCapacity
        $full   = @(Get-CimInstance -Namespace root/wmi -ClassName BatteryFullChargedCapacity -ErrorAction Stop)[0].FullChargedCapacity
    }
    catch { }

    # Whether there is a battery at all is a different question from whether the firmware
    # will say how worn it is, and a desktop must not be reported as a laptop with a fault.
    $present = @(Get-CimInstance Win32_Battery -ErrorAction SilentlyContinue).Count -gt 0

    [pscustomobject]@{
        PSTypeName             = 'Gutcheck.Data.Battery'
        BatteryPresent         = $present
        DesignedCapacity       = $design
        FullChargedCapacity    = $full
        Elevated               = (Get-CurrentPrivilege) -eq 'admin'
    }
}

function ConvertTo-BatteryFinding {
    [CmdletBinding()]
    [OutputType([psobject])]
    param(
        [AllowNull()]$Data,
        [hashtable]$Parameters = @{}
    )

    $warnBelow = Get-Parameter $Parameters 'BatteryHealthWarnBelowPercent' 80
    $failBelow = Get-Parameter $Parameters 'BatteryHealthFailBelowPercent' 60

    # A desktop has nothing to say here, and saying it anyway would put a line in every
    # Report that a Technician learns to skip past.
    if (-not (Get-DataProperty $Data 'BatteryPresent')) { return }

    $design = ConvertTo-Number (Get-DataProperty $Data 'DesignedCapacity')
    $full   = ConvertTo-Number (Get-DataProperty $Data 'FullChargedCapacity')

    if ($null -eq $design -or $null -eq $full -or $design -le 0 -or $full -le 0) {
        $elevated = [bool](Get-DataProperty $Data 'Elevated')
        return New-Finding -Category Power -Check (Get-Text 'Check.Battery.BatteryHealth') -Severity INFO `
            -Value $(if ($elevated) { (Get-Text 'Value.Battery.NotReportedByFirmware') } else { (Get-Text 'Value.Shared.NeedsAdmin') }) `
            -Hint (Get-Text 'Hint.Battery.AlternativePowercfgBatteryreportAdmin')
    }

    $health = $full / $design * 100

    New-Finding -Category Power -Check (Get-Text 'Check.Battery.BatteryHealth') `
        -Severity (Get-SeverityBelow $health $warnBelow $failBelow) `
        -Value ((Get-Text 'Value.Battery.DesignCapacity') -f $health) `
        -Hint (Get-Text 'Hint.Battery.WornBatterySomeVendorsDell')
}