Syncro System Status:

CyberDrain Scripting Winners For December Are Now Available

These two winning submissions have been written by CyberDrain and are now available in our Community Scripting Library.

  1. Battery Health Monitor

Query the laptop battery health and logs a ticket if the battery capacity is below X% (defined in a script variable) of it’s original capacity.

  1. Detect Clock Skew

Alerts when an asset’s clock has drifted by a variable amount of minutes, including daylight savings and time zone offsets.

1 Like

Clock Skew one looks interesting. What do you think, run daily?

Okay, testing the Battery Health Monitor script on a few internal laptops… Second one I tested generates an error in the script. From the script output:

Battery life report saved to file path C:\Windows\system32\WindowsPowerShell\v1.0\batteryreport.xml.
error> Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Int64".
error> At C:\ProgramData\Syncro\bin\1a635e2f-d8e2-4b60-a76f-3cb9cb3bcd79.ps1:22 char:9
error> +     if ([int64]$Battery.FullChargeCapacity * 100 / [int64]$Battery.De ...
error> +         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error>     + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
error>     + FullyQualifiedErrorId : ConvertToFinalInvalidCastException
error>

The subject PC is a Surface Book with two internal batteries. Here’s data from the XML:

  <Batteries>
    <Battery>
      <Id>X906972</Id>
      <Manufacturer>SMP</Manufacturer>
      <SerialNumber>23182</SerialNumber>
      <ManufactureDate></ManufactureDate>
      <Chemistry>LION</Chemistry>
      <LongTerm>1</LongTerm>
      <RelativeCapacity>0</RelativeCapacity>
      <DesignCapacity>17902</DesignCapacity>
      <FullChargeCapacity>15390</FullChargeCapacity>
      <CycleCount>268</CycleCount>
    </Battery>
    <Battery>
      <Id>X905255</Id>
      <Manufacturer>SMP</Manufacturer>
      <SerialNumber>711</SerialNumber>
      <ManufactureDate></ManufactureDate>
      <Chemistry>LION</Chemistry>
      <LongTerm>1</LongTerm>
      <RelativeCapacity>0</RelativeCapacity>
      <DesignCapacity>51000</DesignCapacity>
      <FullChargeCapacity>40140</FullChargeCapacity>
      <CycleCount>398</CycleCount>
    </Battery>
  </Batteries>

So far in single-battery laptops it’s working perfectly.

Ran the battery script on a Latitude E7440. ??? I replaced the runtime variable with 50 and got the same result.
Battery life report saved to file path C:\WINDOWS\system32\WindowsPowerShell\v1.0\batteryreport.xml.
error> Attempted to divide by zero.
error> At C:\ProgramData\Syncro\bin\3ad1c98e-791a-41fb-b4d9-f65604e857f7.ps1:22 char:9
error> + if ([int64]$Battery.FullChargeCapacity * 100 / [int64]$Battery.De
error> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error> + CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
error> + FullyQualifiedErrorId : RuntimeException
error>

Ran the Battery Health one on an Asus Laptop with a known dead battery. Used 80% as the alert level. Script throws and errors ( not divisible by zero ).

error> Unable to perform operation. An unexpected error (0x10d2) has occurred: The library, drive, or media pool is empty.
error>
error>
error> Get-Content : Cannot find path ‘C:\WINDOWS\system32\WindowsPowerShell\v1.0\batteryreport.xml’ because it does not exist.
error> At C:\ProgramData\Syncro\bin\5a4e956c-bdd5-4122-be4f-865fefd91848.ps1:5 char:16
error> + [xml]$Report = Get-Content “batteryreport.xml”
error> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error> + CategoryInfo : ObjectNotFound: (C:\WINDOWS\syst…tteryreport.xml:String) [Get-Content], ItemNotFoundException
error> + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
error>
error> Attempted to divide by zero.
error> At C:\ProgramData\Syncro\bin\5a4e956c-bdd5-4122-be4f-865fefd91848.ps1:22 char:9
error> + if ([int64]$Battery.FullChargeCapacity * 100 / [int64]$Battery.De
error> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error> + CategoryInfo : NotSpecified: (:slight_smile: , RuntimeException
error> + FullyQualifiedErrorId : RuntimeException
error> `

I made some changes that seem to work for PCs with more than one battery as well as no battery. Also added Activity Logging.

Paste Bin

If you get any errors, I’d love to hear about them.

I’m running it against every Latitude to check at 75%
Most failed with the error above. A few finished had two alerts
Here’s one I don’t understand: The battery health is less than expect. The battery was designed for 53010 but the maximum charge is 53010. The battery info is DELL 9077G0B

That seems to have fixed the problem with my errors. Thanks!

1 Like

Logic seems to be wrong to me. It’s checking if the battery health is higher than the minimum and generating an alert.

if ([int64]$Battery.FullChargeCapacity * 100 / [int64]$Battery.DesignCapacity -gt $AlertPercent) {

I replaced the -gt with -lt and mine is now creating alerts for low battery health rather than high.

Also any device without a battery throws an error when the script tries to read the XML file, which doesn’t exist. I added an exit 0 here which stops the script before it tries to read the XML.

if (!$BatteryStatus) {
    Write-Host "This device does not have batteries, or we could not find the status of the batteries."
    exit 0
}

Edit: @jeremy seems to have done the same as me on both counts. Shame I didn’t try his first before getting my copy to work :wink:

1 Like

I actually wonder if their original -gt code actually did work properly based on the priority of mathematical operators. I’ve never been able to understand those rules, so that’s why I put in the parenthesis and changed it to -lt. Easier for my brain to track that way.

That should remove the alerts I’ve gotten where the battery was at 100%.

1 Like

Did the clock skew work for anyone? I tried it on a computer that was off 15 minutes and go no alert or correction. :frowning: