Home > Mac administration, macOS, Scripting > Identifying Mac laptops and desktops from the command line by checking for a built-in battery

Identifying Mac laptops and desktops from the command line by checking for a built-in battery

Every so often, it may be necessary for Mac admins to deploy a script that can apply different settings to Mac desktops and laptops. A good example may be using the pmset command to apply Energy Saver settings, where you may want to apply one set of power management settings to laptops and a different set to desktops.


#!/bin/bash
# Set separate power management settings for desktops and laptops
# If it's a laptop, the power management settings for "Battery" are set to have the computer sleep in 15 minutes,
# disk will spin down in 10 minutes, the display will sleep in 5 minutes and the display itself will dim to
# half-brightness before sleeping. While plugged into the AC adapter, the power management settings for "Charger"
# are set to have the computer never sleep, the disk doesn't spin down, the display sleeps after 30 minutes and
# the display dims before sleeping.
#
# If it's not a laptop (i.e. a desktop), the power management settings are set to have the computer never sleep,
# the disk doesn't spin down, the display sleeps after 30 minutes and the display dims before sleeping.
#
# Detects if this Mac is a laptop or not by checking the model ID for the word "Book" in the name.
IS_LAPTOP=$(/usr/sbin/system_profiler SPHardwareDataType | grep "Model Identifier" | grep "Book")
if [[ -n "$IS_LAPTOP" ]]; then
/usr/bin/pmset -b sleep 15 disksleep 10 displaysleep 5 halfdim 1
/usr/bin/pmset -c sleep 0 disksleep 0 displaysleep 30 halfdim 1
else
/usr/bin/pmset sleep 0 disksleep 0 displaysleep 30 halfdim 1
fi

view raw

powersetings.sh

hosted with ❤ by GitHub

In the example above, the Model Identifier information from the system_profiler command is used to help identify if the Mac is a desktop or laptop. In this case, the Model Identifier information is checked to see if the model identifier contains “Book”.

Screenshot 2022 12 23 at 5 51 44 PM

If it does, it’s a laptop. Otherwise, it’s a desktop:


/usr/sbin/system_profiler SPHardwareDataType | grep "Model Identifier" | grep "Book"

view raw

gistfile1.txt

hosted with ❤ by GitHub

However, the latest Mac laptops’ model identifier does not contain “Book”. This means that this identification method should no longer be considered reliable.

Screenshot 2022 12 23 at 5 40 48 PM

What’s an alternative way to check? One way is to use the ioreg command to see if the Mac in question has a built-in battery or not. Laptops will have a built-in battery and desktops will not. For more details, please see below the jump.


Update – 12-29-2022: It appears my original choice of detection criteria of using built-in with the ioreg command was not universally returning no output data for desktops, as I hadn’t tested against Apple Silicon Mac desktops. Apple Silicon Mac desktops share a number of characteristics with Apple Silicon laptops, including having the following command respond with the following output:

Yes


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/built-in/ {print $3}'
Yes
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

However, there is another criteria we can search for which should provide better results, which is to use BatteryInstalled in place of built-in as criteria when running the ioreg command:


/usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'

view raw

gistfile1.txt

hosted with ❤ by GitHub

On a laptop, the following output should be returned:

Yes


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
Yes
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

On a desktop, either the following output or no output should be returned:

No


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
No
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

No output:


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

I’ve updated this blog post to now reference the BatteryInstalled criteria in place of the built-in criteria previously referenced.

Note: There is an edge case where it’s possible a laptop may have its built-in battery removed and thus respond with No or return no output, like a desktop would. Mac laptops made since 2009 and later have non-removable batteries built into the laptop, so this scenario shouldn’t be a common one for most environments, but it’s worth mentioning if you have a non-zero number of Mac laptops with their built-in batteries removed.


You can use the ioreg command shown below to query the information for the AppleSmartBattery hardware driver (currently used by macOS for its battery management) and check whether the Mac has a built-in battery or not:


/usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'

view raw

gistfile1.txt

hosted with ❤ by GitHub

On a laptop, the following command should return Yes:


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
Yes
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

On a desktop, the same command should return No or no output:

No


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
No
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

No output:


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}'
username@computername ~ %

view raw

gistfile1.txt

hosted with ❤ by GitHub

You should be able to use this command to update the example script for setting power management to correctly identify laptops vs. desktops again:


#!/bin/bash
# Set separate power management settings for desktops and laptops
# If it's a laptop, the power management settings for "Battery" are set to have the computer sleep in 15 minutes,
# disk will spin down in 10 minutes, the display will sleep in 5 minutes and the display itself will dim to
# half-brightness before sleeping. While plugged into the AC adapter, the power management settings for "Charger"
# are set to have the computer never sleep, the disk doesn't spin down, the display sleeps after 30 minutes and
# the display dims before sleeping.
#
# If it's not a laptop (i.e. a desktop), the power management settings are set to have the computer never sleep,
# the disk doesn't spin down, the display sleeps after 30 minutes and the display dims before sleeping.
#
# Detects if this Mac is a laptop or not by checking for a built-in battery.
IS_LAPTOP=$(/usr/sbin/ioreg -c AppleSmartBattery -r | awk '/BatteryInstalled/ {print $3}')
if [[ "$IS_LAPTOP" = "Yes" ]]; then
/usr/bin/pmset -b sleep 15 disksleep 10 displaysleep 5 halfdim 1
/usr/bin/pmset -c sleep 0 disksleep 0 displaysleep 30 halfdim 1
else
/usr/bin/pmset sleep 0 disksleep 0 displaysleep 30 halfdim 1
fi

Note: The AppleSmartBattery hardware driver is being queried by the ioreg command to gather this information. If Apple ever changes the name or the functionality of the AppleSmartBattery hardware driver, this method may stop working and need to be updated for the new name or functionality.

  1. blinvisible
    December 27, 2022 at 7:49 pm

    FYI I have Mac minis (M1 2020/Macmini9,1) and Mac Studios (Mac13,1) that are returning a ‘Yes’ from the ioreg command via Jamf extension attribute. I don’t have access to them at the moment to test more in-depth to see why, unless they too have some sort of internal battery that I’m not aware of.

  2. blinvisible
    December 27, 2022 at 7:55 pm

    …and a couple iMacs, as more machines are checking in:

    iMac21,1
    iMac21,2

  3. blinvisible
    December 27, 2022 at 10:27 pm

    Here’s the ioreg output from Macmini9,1. Interestingly, despite all the battery-related info, “BatteryInstalled” has a value of No (whereas on a MacBookPro18,3 the value is Yes).

    +-o AppleSmartBattery
    {
    “Amperage” = 0
    “CurrentCapacity” = 0
    “MaxCapacity” = 0
    “IOReportLegendPublic” = Yes
    “BatteryInvalidWakeSeconds” = 30
    “built-in” = Yes
    “FullPathUpdated” = 1672179572
    “AdapterInfo” = 0
    “ExternalChargeCapable” = Yes
    “PostChargeWaitSeconds” = 120
    “Location” = 0
    “IsCharging” = No
    “BootPathUpdated” = 1671800289
    “AdapterDetails” = {“FamilyCode”=0}
    “PostDischargeWaitSeconds” = 120
    “UpdateTime” = 1672179572
    “AppleRawAdapterDetails” = ()
    “BatteryInstalled” = No
    “Voltage” = 0
    “CycleCount” = 0
    “IOGeneralInterest” = “IOCommand is not serializable”
    “IOReportLegend” = ({“IOReportChannels”=((7167869599145487988,6460407809,”BatteryCycleCount”)),”IOReportGroupName”=”Battery”,”IOReportChannelInfo”={“IOReportChannelUnit”=0}} )
    “ExternalConnected” = Yes
    “TimeRemaining” = 0
    }

    • December 27, 2022 at 10:38 pm

      Interesting. Is “BatteryInstalled” consistently reporting No on the outlier Mac models?

      • December 27, 2022 at 10:41 pm

        The reason I’m asking is that it may be possible to swap “BatteryInstalled” for “built-in” in the ioreg command.

  4. blinvisible
    December 27, 2022 at 10:44 pm

    iMac21,1 and the Mac Studio (Mac13,1) are both showing No for their “BatteryInstalled” values. The others haven’t yet reported in since I changed my extension attribute to include a case statement for those specific models to get more data, but I can let you know when they do. The pattern so far suggests that they will.

  5. blinvisible
    December 28, 2022 at 12:55 am

    I can confirm that all outliers that I’ve found so far have a “BatteryInstalled” value of No, and that modifying the piped awk command accordingly does seem to produce more consistent results in separating desktop vs. laptop devices.

    If you want the full ioreg output for each model type, let me know.

    • December 28, 2022 at 1:36 am

      Yes, please. Thank you for offering to share that.

      • blinvisible
        December 28, 2022 at 1:48 am

        Here is the complete output of $(/usr/sbin/ioreg -c AppleSmartBattery -r) for each of those models.

        iMac21,1:
        +-o AppleSmartBattery
        {
        “Amperage” = 0
        “CurrentCapacity” = 0
        “MaxCapacity” = 0
        “IOReportLegendPublic” = Yes
        “BatteryInvalidWakeSeconds” = 30
        “built-in” = Yes
        “FullPathUpdated” = 1672191220
        “AdapterInfo” = 0
        “ExternalChargeCapable” = Yes
        “PostChargeWaitSeconds” = 120
        “Location” = 0
        “IsCharging” = No
        “BootPathUpdated” = 1670879494
        “AdapterDetails” = {“SerialString”=”C4H207502EX02KNBA”,”Watts”=144,”Model”=”0x7015″,”Name”=”143W Power Adapter”,”Current”=9100,”FamilyCode”=18446744073172697098,”FwVersion”=”01060061″,”AdapterVoltage”=15800,”AdapterID”=28693,”IsWireless”=No,”HwVersion”=”00000000″,”Manufacturer”=”Apple Inc.”}
        “PostDischargeWaitSeconds” = 120
        “UpdateTime” = 1672191220
        “AppleRawAdapterDetails” = ({“SerialString”=”C4H207502EX02KNBA”,”Watts”=144,”Model”=”0x7015″,”Name”=”143W Power Adapter”,”Current”=9100,”FamilyCode”=18446744073172697098,”FwVersion”=”01060061″,”AdapterVoltage”=15800,”AdapterID”=28693,”IsWireless”=No,”HwVersion”=”00000000″,”Manufacturer”=”Apple Inc.”})
        “PowerTelemetryData” = {“WallEnergyEstimate”=2189,”AccumulatedSystemPowerIn”=6541337382,”AdapterEfficiencyLossAccumulatorCount”=1304490,”AccumulatedWallEnergyEstimate”=2107101751,”SystemPowerInAccumulatorCount”=1304490,”SystemEnergyConsumed”=1887,”SystemPowerIn”=6794,”SystemLoad”=7421,”AccumulatedSystemLoad”=7028205312,”SystemLoadAccumulatorCount”=1304491,”AccumulatedSystemEnergyConsumed”=1816422489,”AdapterEfficiencyLoss”=302,”AccumulatedAdapterEfficiencyLoss”=290679262}
        “BestAdapterIndex” = 4
        “BatteryInstalled” = No
        “Voltage” = 0
        “CycleCount” = 0
        “IOGeneralInterest” = “IOCommand is not serializable”
        “IOReportLegend” = ({“IOReportChannels”=((7167869599145487988,6460407809,”BatteryCycleCount”)),”IOReportGroupName”=”Battery”,”IOReportChannelInfo”={“IOReportChannelUnit”=0}} )
        “ExternalConnected” = Yes
        “TimeRemaining” = 0
        }

        iMac21,2:
        +-o AppleSmartBattery
        {
        “Amperage” = 0
        “CurrentCapacity” = 0
        “MaxCapacity” = 0
        “IOReportLegendPublic” = Yes
        “BatteryInvalidWakeSeconds” = 30
        “built-in” = Yes
        “FullPathUpdated” = 1672191118
        “AdapterInfo” = 0
        “ExternalChargeCapable” = Yes
        “PostChargeWaitSeconds” = 120
        “Location” = 0
        “IsCharging” = No
        “BootPathUpdated” = 1668151390
        “AdapterDetails” = {“SerialString”=”C4H151101XR13VVBD”,”Watts”=144,”Model”=”0x7018″,”Name”=”143W Power Adapter”,”Current”=9100,”FamilyCode”=18446744073172697098,”FwVersion”=”01060061″,”AdapterVoltage”=15800,”AdapterID”=28696,”IsWireless”=No,”HwVersion”=”00000000″,”Manufacturer”=”Apple Inc.”}
        “PostDischargeWaitSeconds” = 120
        “UpdateTime” = 1672191118
        “AppleRawAdapterDetails” = ({“SerialString”=”C4H151101XR13VVBD”,”Watts”=144,”Model”=”0x7018″,”Name”=”143W Power Adapter”,”Current”=9100,”FamilyCode”=18446744073172697098,”FwVersion”=”01060061″,”AdapterVoltage”=15800,”AdapterID”=28696,”IsWireless”=No,”HwVersion”=”00000000″,”Manufacturer”=”Apple Inc.”})
        “PowerTelemetryData” = {“WallEnergyEstimate”=1333,”AccumulatedSystemPowerIn”=20523749467,”AdapterEfficiencyLossAccumulatorCount”=4027500,”AccumulatedWallEnergyEstimate”=6611176466,”SystemPowerInAccumulatorCount”=4027500,”SystemEnergyConsumed”=1149,”SystemPowerIn”=4138,”SystemLoad”=4163,”AccumulatedSystemLoad”=20743949828,”SystemLoadAccumulatorCount”=4027501,”AccumulatedSystemEnergyConsumed”=5699127083,”AdapterEfficiencyLoss”=184,”AccumulatedAdapterEfficiencyLoss”=912049383}
        “BestAdapterIndex” = 2
        “BatteryInstalled” = No
        “Voltage” = 0
        “CycleCount” = 0
        “IOGeneralInterest” = “IOCommand is not serializable”
        “IOReportLegend” = ({“IOReportChannels”=((7167869599145487988,6460407809,”BatteryCycleCount”)),”IOReportGroupName”=”Battery”,”IOReportChannelInfo”={“IOReportChannelUnit”=0}} )
        “ExternalConnected” = Yes
        “TimeRemaining” = 0
        }

        Macmini9,1:
        +-o AppleSmartBattery
        {
        “Amperage” = 0
        “CurrentCapacity” = 0
        “MaxCapacity” = 0
        “IOReportLegendPublic” = Yes
        “BatteryInvalidWakeSeconds” = 30
        “built-in” = Yes
        “FullPathUpdated” = 1672191612
        “AdapterInfo” = 0
        “ExternalChargeCapable” = Yes
        “PostChargeWaitSeconds” = 120
        “Location” = 0
        “IsCharging” = No
        “BootPathUpdated” = 1671800289
        “AdapterDetails” = {“FamilyCode”=0}
        “PostDischargeWaitSeconds” = 120
        “UpdateTime” = 1672191612
        “AppleRawAdapterDetails” = ()
        “BatteryInstalled” = No
        “Voltage” = 0
        “CycleCount” = 0
        “IOGeneralInterest” = “IOCommand is not serializable”
        “IOReportLegend” = ({“IOReportChannels”=((7167869599145487988,6460407809,”BatteryCycleCount”)),”IOReportGroupName”=”Battery”,”IOReportChannelInfo”={“IOReportChannelUnit”=0}} )
        “ExternalConnected” = Yes
        “TimeRemaining” = 0
        }

        Mac13,1:
        +-o AppleSmartBattery
        {
        “Amperage” = 0
        “CurrentCapacity” = 0
        “MaxCapacity” = 0
        “IOReportLegendPublic” = Yes
        “BatteryInvalidWakeSeconds” = 30
        “built-in” = Yes
        “FullPathUpdated” = 1672191735
        “AdapterInfo” = 0
        “ExternalChargeCapable” = Yes
        “PostChargeWaitSeconds” = 120
        “Location” = 0
        “IsCharging” = No
        “BootPathUpdated” = 1667938057
        “AdapterDetails” = {“FamilyCode”=0}
        “PostDischargeWaitSeconds” = 120
        “UpdateTime” = 1672191735
        “AppleRawAdapterDetails” = ()
        “BatteryInstalled” = No
        “Voltage” = 0
        “CycleCount” = 0
        “IOGeneralInterest” = “IOCommand is not serializable”
        “IOReportLegend” = ({“IOReportChannels”=((7167869599145487988,6460407809,”BatteryCycleCount”)),”IOReportGroupName”=”Battery”,”IOReportChannelInfo”={“IOReportChannelUnit”=0}} )
        “ExternalConnected” = Yes
        “TimeRemaining” = 0
        }

  6. Pico
    December 29, 2022 at 5:43 pm

    I’ve seen this behavior of the “AppleSmartBattery” being filled out with “BatteryInstalled = No” on Apple Silicon desktops as well. I believe this is because the same exact Apple Silicon SoCs are used across all Macs and they all technically support batteries while different chipset capabilities were exposed desktop vs laptop on Intel Macs.

    Since checking for “BatteryInstalled = No” could technically give a rare but possible false negative for a laptop with it’s battery disconnected or removed, I think the most reliable alternative to using the Model ID is to use the “Model Name” field from “system_profiler” which will still always list “MacBook Pro” even for MacBook Pro’s with “MacXX,Y” Model IDs, and of course it can be used to check for Intel Macs too, it’s a consistent and reliable check with no edge cases like checking for a battery has.

    This could be checked across all models as simply as just running “system_profiler SPHardwareDataType | grep MacBook” because that command would just get 2 matched lines on older Macs laptops with “MacBookProXX,Y” Model IDs and only one matched line on newer Macs laptops with “MacXX,Y” Model IDs and no lines would ever be matched for any desktops.

  7. JGuy
    April 5, 2023 at 12:32 pm

    Going back to your original method of using system_profiler could you not just grep on “Model Name” instead of “Model Identifier”?

  8. July 25, 2023 at 9:00 pm

    FYI,
    The command:
    /usr/sbin/system_profiler SPHardwareDataType | grep “Model Identifier” | grep “Book”

    No longer applies for M2 MacBook Air.

    The model identifier for my MacBook Air M2 is Mac14,2.
    There may be more models like this, looks like we are better off using ‘system_profiler SPHardwareDataType’ and grep the “Model Name”.
    Cesar.

  1. No trackbacks yet.

Leave a reply to blinvisible Cancel reply