Skip to content

Instantly share code, notes, and snippets.

@knee-cola
Last active January 23, 2023 14:43
Show Gist options
  • Save knee-cola/49a7cedf3675da485e76d6e1e5e838c6 to your computer and use it in GitHub Desktop.
Save knee-cola/49a7cedf3675da485e76d6e1e5e838c6 to your computer and use it in GitHub Desktop.
tracking battery usage on Windows laptop

What's this?

This is a script, which tracks charging and discharging time of a Windows powered laptop.

It creates a log file, which contains information about time the laptop spend charging and discharging the battery. The collected information can give you a pretty good idea about the battery life of your laptop.

Here's a sample:

charge=77
mode=discharging
start=09/12/2017 22:36:40
checked=09/12/2017 23:05:51
duration=1751 (00:29:11)
---------------
09/12/2017 22:26:51 charging (00:03:00)
09/12/2017 21:05:39 discharging (00:13:19)

At the top you can see the current information, while at the bottom there's a log, consisting of:

  • start time
  • charging state
  • duration

Why?

Because Windows 10 doesn't provide this kind of information ... an I really wanted mesure battery performance of my new laptop (Asus UX360)

Installation

Download both of the attached VBS script and just run install.vbs. This will create a Task Scheduler task, which will run the battery-worker.vbs script every 60 seconds + whenever laptop is plugged or unplugged from power.

Option Explicit
'---------------------------------------
' reading previos data from file
'---------------------------------------
Dim prevChargeRemaining, prevMode, prevStartTime, prevCheckTime, prevDuration
Dim fso, file, fileName, line, ix, batteryLog(), batteryLogLength
fileName = "battery.log"
batteryLogLength = -1
Set fso = CreateObject("Scripting.FileSystemObject")
Function formatTime (total)
Dim seconds, minutes, hours
seconds = total mod 60
total = (total - seconds)/60
minutes = total mod 60
total = (total - minutes)/60
hours = total
If seconds < 10 Then
seconds = "0" & seconds
End If
If minutes < 10 Then
minutes = "0" & minutes
End If
If hours < 10 Then
hours = "0" & hours
End If
formatTime = hours&":"&minutes&":"&seconds
End Function
If fso.FileExists(fileName) Then
Set file = fso.OpenTextFile (fileName, 1)
ix = 0
Do Until file.AtEndOfStream
line = file.Readline()
Select Case ix
Case 0:
' charge=97
prevChargeRemaining=Split(line,"=")(1)
Case 1:
' mode=charging
prevMode=Split(line,"=")(1)
Case 2:
' start=2017-12-05 15:22:23
prevStartTime=Split(line,"=")(1)
Case 3:
' checked=2017-12-05 15:35:23
prevCheckTime=Split(line,"=")(1)
Case 4:
' duration=125 (15:19)
prevDuration=Split(Split(line,"=")(1)," ")(0)
Case 5:
' delimiter ...
Case Else
batteryLogLength = batteryLogLength+1
Redim Preserve batteryLog(batteryLogLength)
batteryLog(batteryLogLength) = line
End Select
ix = ix + 1
Loop
file.Close
Else
' no previous data is available
prevChargeRemaining = Null
prevMode = Null
End If
'-------------------------------
' geting the current values
'-------------------------------
Dim objWMIService, objItem, colItems, strComputer
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Battery",,48)
Dim currChargeRemaining, BatteryStatus, currMode, currStartTime, currCheckTime, currDuration
currCheckTime = Now
For Each objItem in colItems
currChargeRemaining = objItem.EstimatedChargeRemaining
BatteryStatus = objItem.BatteryStatus
Next
'---------------------------------------
' comparing previous and current value
'---------------------------------------
Select Case BatteryStatus
' Other (1)
' - The battery is discharging.
Case 1
currMode = "discharging"
' Unknown (2)
' - The system has access to AC so no battery is being discharged.
' However, the battery is not necessarily charging.
Case 2
currMode = "charging"
' Fully Charged (3)
Case 3
currMode = "full"
' Low (4)
Case 4
currMode = "discharging"
' Critical (5)
Case 5
currMode = "discharging"
' Charging (6)
Case 6
currMode = "charging"
' Charging and High (7)
Case 7
currMode = "charging"
' Charging and Low (8)
Case 8
currMode = "charging"
' Charging and Critical (9)
Case 9
currMode = "charging"
' Undefined (10)
Case 10
currMode = "undefined"
' Partially Charged (11)
Case 10
currMode = "charging"
End Select
Dim newLogEntry
newLogEntry = ""
If IsNull(prevMode) Then
currStartTime = Now
currDuration = 0
ElseIf currMode <> prevMode Then
currStartTime = Now
currDuration = 0
' in case the previous mode was known
' > add the previous state to log
If prevMode <> "unknown" Then
newLogEntry = prevStartTime & " " & prevMode & " (" & formatTime(prevDuration) & ")"
End If
Else
currStartTime = prevStartTime
Dim timeDiff
timeDiff = DateDiff("s", prevCheckTime, currCheckTime)
' timer is running every 60 seconds
' so the diff should not be greater than 60 sec
' here I add additional 60 sec .. just in case task was delayed
If timeDiff > 120 Then
' IF duration is greater than 2 minutes => computer was turned off
timeDiff = 0
End If
currDuration = prevDuration + timeDiff
End If
'---------------------------------------
' writing results to file
'---------------------------------------
Set fso = CreateObject("Scripting.FileSystemObject")
Dim MyFile
Set MyFile = fso.CreateTextFile(fileName, true) ' overwrite file if one exists
' writing header
MyFile.WriteLine("charge="&currChargeRemaining)
MyFile.WriteLine("mode="&currMode)
MyFile.WriteLine("start="&currStartTime)
MyFile.WriteLine("checked="&currCheckTime)
MyFile.WriteLine("duration="&currDuration & " (" & formatTime(currDuration) & ")")
MyFile.WriteLine("---------------")
' writing the new log entry at the top
If newLogEntry<>"" Then
MyFile.WriteLine(newLogEntry)
End If
' writing older log entries
For ix=0 to batteryLogLength
MyFile.WriteLine(batteryLog(ix))
Next
MyFile.close
WSCript.Quit
'------------------------------------------------------------------
' This sample schedules a task to start on a daily basis.
'------------------------------------------------------------------
Const TASK_TRIGGER_EVENT = 0 ' Starts the task when a specific event occurs.
Const TASK_TRIGGER_TIME = 1 ' Starts the task at a specific time of day.
Const TASK_TRIGGER_DAILY = 2 ' Starts the task daily.
Const TASK_TRIGGER_WEEKLY = 3 ' Starts the task weekly.
Const TASK_TRIGGER_MONTHLY = 4 ' Starts the task monthly.
Const TASK_TRIGGER_MONTHLYDOW = 5 ' Starts the task every month on a specific day of the week.
Const TASK_TRIGGER_IDLE = 6 ' Starts the task when the computer goes into an idle state.
Const TASK_TRIGGER_REGISTRATION = 7 ' Starts the task when the task is registered.
Const TASK_TRIGGER_BOOT = 8 ' Starts the task when the computer boots.
Const TASK_TRIGGER_LOGON = 9 ' Starts the task when a specific user logs on.
Const TASK_TRIGGER_SESSION_STATE_CHANGE = 11 ' Triggers the task when a specific sessio
Const TASK_ACTION_EXEC = 0 ' This action performs a command-line operation. For example, the action could run a script, launch an executable, or, if the name of a document is provided, find its associated application and launch the application with the document.
Const TASK_ACTION_COM_HANDLER = 5 ' This action fires a handler.
Const TASK_ACTION_SEND_EMAIL = 6 ' This action sends an email message.
Const TASK_ACTION_SHOW_MESSAGE = 7 ' This action shows a message box.
Const TASK_LOGON_NONE = 0 'The logon method is not specified. Used for non-NT credentials.
Const TASK_LOGON_PASSWORD = 1 'Use a password for logging on the user. The password must be supplied at registration time.
Const TASK_LOGON_S4U = 2 'Use an existing interactive token to run a task. The user must log on using a service for user (S4U) logon. When an S4U logon is used, no password is stored by the system and there is no access to either the network or encrypted files.
Const TASK_LOGON_INTERACTIVE_TOKEN = 3 'User must already be logged on. The task will be run only in an existing interactive session.
Const TASK_LOGON_GROUP = 4 'Group activation. The userId field specifies the group.
Const TASK_LOGON_SERVICE_ACCOUNT = 5 'Indicates that a Local System, Local Service, or Network Service account is being used as a security context to run the task.
Const TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6 'First use the interactive token. If the user is not logged on (no interactive token is available), then the password is used. The password must be specified when a task is registered. This flag is not recommended for new tasks because it is less reliable than TASK_LOGON_PASSWORD.
cONST TASK_RUNLEVEL_LUA = 0 'Tasks will be run with the least privileges (LUA).
cONST TASK_RUNLEVEL_HIGHEST = 1 'Tasks will be run with the highest privileges.
'********************************************************
' Create the TaskService object.
Set service = CreateObject("Schedule.Service")
call service.Connect()
'********************************************************
' Get a folder to create a task definition in.
Dim rootFolder
Set rootFolder = service.GetFolder("\")
' The taskDefinition variable is the TaskDefinition object.
Dim taskDefinition
' The flags parameter is 0 because it is not supported.
Set taskDefinition = service.NewTask(0)
'********************************************************
' Define information about the task.
' ' Setting principal - it should run even if user is not logged in
' Dim principal
' set principal = taskDefinition.principal
' principal.LogonType = TASK_LOGON_PASSWORD
' ' principal.password = "unciBal7791"
' ' principal.UserId = "nikola"
' ' principal.RunLevel = TASK_RUNLEVEL_HIGHEST
' Set the registration info for the task by
' creating the RegistrationInfo object.
Dim regInfo
Set regInfo = taskDefinition.RegistrationInfo
regInfo.Description = "Logs time spent on battery. For more info see: https://gist.github.com/knee-cola/49a7cedf3675da485e76d6e1e5e838c6"
regInfo.Author = "Administrator"
' Set the task setting info for the Task Scheduler by
' creating a TaskSettings object.
Dim settings
Set settings = taskDefinition.Settings
settings.Enabled = True
settings.StartWhenAvailable = True
settings.Hidden = False
' we need to have task running while on batteries
settings.StopIfGoingOnBatteries = False
settings.DisallowStartIfOnBatteries = False
'********************************************************
' Create a daily trigger. Note that the start boundary
' specifies the time of day that the task starts and the
' interval specifies what days the task is run.
Dim triggers
Set triggers = taskDefinition.Triggers
Dim trigger
Set trigger = triggers.Create(TASK_TRIGGER_DAILY)
' Trigger variables that define when the trigger is active
' and the time of day that the task is run. The format of
' this time is YYYY-MM-DDTHH:MM:SS
Const startTime = "2006-05-02T08:00:00" 'Task runs at 8:00 AM
Const endTime = "2099-05-02T08:00:00"
trigger.StartBoundary = startTime
trigger.EndBoundary = endTime
trigger.DaysInterval = 1 'Task runs every day.
trigger.Id = "DailyTriggerId"
trigger.Enabled = True
' Set the task repetition pattern for the task.
Dim repetitionPattern
Set repetitionPattern = trigger.Repetition
' repetitionPattern.Duration = "PT4M" - it will be repeated indefinitely
repetitionPattern.Interval = "PT1M" ' repear the task once every minute
' Creating an additional trigger, which will get called each time
' a charger was plugged in or unplugged
Set trigger = triggers.Create(TASK_TRIGGER_EVENT)
trigger.Id = "EventTriggerId" 'Inherited from the Trigger object. Gets or sets the identifier for the trigger.
' trigger.Delay = 0 'Gets or sets a value that indicates the amount of time between when the event occurs and when the task is started.
trigger.Enabled = true 'Inherited from the Trigger object. Gets or sets a Boolean value that indicates whether the trigger is enabled.
' trigger.StartBoundary = startTime 'Inherited from the Trigger object. Gets or sets the date and time when the trigger is activated.
' trigger.EndBoundary = endTime 'Inherited from the Trigger object. Gets or sets the date and time when the trigger is deactivated. The trigger cannot start the task after it is deactivated.
trigger.Subscription = "<QueryList><Query Id='0' Path='System'><Select Path='System'>*[System[EventID=105]]</Select></Query></QueryList>" 'Gets or sets the XPath query string that identifies the event that fires the trigger.
' trigger.ExecutionTimeLimit = "PT5M" 'Inherited from the Trigger object. Gets or sets the maximum amount of time that the task launched by this trigger is allowed to run.
' trigger.Repetition = 'Inherited from the Trigger object. Gets or sets how often the task is run and how long the repetition pattern is repeated after the task is started.
' trigger.ValueQueries = 'Gets or sets a collection of named XPath queries. Each query in the collection is applied to the last matching event XML that is returned from the subscription query specified in the Subscription property. The name of the query can be used as a variable in the message of a ShowMessageAction action.
'***********************************************************
' Create the action for the task to execute.
' Add an action to the task to run notepad.exe.
Dim Action
Set Action = taskDefinition.Actions.Create( TASK_ACTION_EXEC )
'Action.Path = "cscript"
'Action.Arguments = "battery-worker.vbs"
Action.Path = "battery-worker.vbs"
Action.WorkingDirectory = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) & "\"
'***********************************************************
' Register (create) the task.
' https://msdn.microsoft.com/en-us/library/windows/desktop/aa382577(v=vs.85).aspx
Set oWshShell = WScript.CreateObject("WScript.Shell")
Set objWSHshell = WScript.CreateObject( "WScript.Shell" )
Const path = "BatteryTrackerWorker"
Const flags = 6
Dim userId
userId = objWSHshell.ExpandEnvironmentStrings( "%USERNAME%" )
Dim password
password = InputBox("Please provide your system password." & Chr(10) & "It's needed to register the task in Task Scheduler.", "BatteryTracker Installation")
Dim logonType
logonType = TASK_LOGON_PASSWORD
call rootFolder.RegisterTaskDefinition(path, taskDefinition, flags, userId, password, logonType)
WScript.Echo "Battery Task created!" & Chr(10) & "Installation completed successfully!" & Chr(10) & Chr(10) & "You cand find it in Task Scheduler under " & path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment