How to toggle the macbook menu bar battery/wifi icon on/off via the command line

To toggle the showing of the Wi-Fi and Battery Status icons on the Menu Bar from the command line in Terminal, one can use a shell script to do so, as in the example AppleScript code used as a shell script, presented below.

The core parts of the example AppleScript code, shown below, was tested in Script Editor, and the entire script as a executable shell script in Terminal, under macOS Catalina and with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

  • 1Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.
  • The example AppleScript code presented herein works as tested in macOS Catalina, however, will need to be modified for use in macOS Big Sur or later.

General Notes:

In macOS Catalina when the Menu Extras that show on the Menu Bar are showing, it's the ~/Library/Preferences/com.apple.systemuiserver.plist file that contains an entry under the menuExtras key for those that show. If they are not showing, then the entry is removed from the target .plist file.

While one can use the defaults command line utility, or the /usr/libexec/PlistBuddy command line utility to modify the target .plist file, nonetheless, even after killing the SystemUIServer process, it does not reflect the current state of the modified target .plist file. As such, one can use AppleScript with UI Scripting and System Events to modify System Preferences to remove the target Menu Extras from the Menu Bar. To show them, it's not as complicated as removing them and it's just a matter of opening the target Menu Extras.

The Menu Extras are located at: /System/Library/CoreServices/Menu Extras/

Below you'll find two separate AppleScript scripts that will toggle the state of the Wi-Fi and Battery Status icons shown on the Menu Bar. They will be available for use from Terminal, or other methods of calling a command line utility.

System Preferences will not show its UI, however, its Dock icon will bounce briefly one time when removing the target icons from the menu bar. (It's barely noticeable.)

  • Note that after creating and testing the executable shell script for each, they should be moved to a directory that is included in the PATH passed to the shell so they can be used by just typing their name without the leading ./, or their fully qualified pathname.


Wi-Fi Menu Bar Icon

To use the example AppleScript code as an executable shell script in Terminal, run the following compound command in Terminal:

f='wifimbi'; touch "$f"; open -e "$f"; chmod +x "$f"

In the opened wifimbi document, copy and paste the example AppleScript code into it, then save and close it.

Back in Terminal, type ./wifimbi and then press enter:

It should output:

Missing argument, e.g.,: wifimbi [on|off]

Meaning to use it you type either wifimbi on or wifimbi off to add to remove the Wi-Fi icon from the menu bar.

Then test it using ./wifimbi on and ./wifimbi off, however, do not run the commands immediately back to back as it takes a few moments for the script to run and the target .plist file to update.

Example AppleScript code:

#!/usr/bin/osascript

on run argv
    
    if argv is equal to {} then ¬
        return "Missing argument, e.g.,: " & ¬
            name of me & " [on|off]"
    
    set thePropertyListFilePath to ¬
        the POSIX path of ¬
            (path to preferences from user domain as string) & ¬
        "com.apple.systemuiserver.plist"
    
    tell application "System Events" to ¬
        tell the property list file thePropertyListFilePath to ¬
            set menuExtrasListAsString to the value of ¬
                the property list item ¬
                    "menuExtras" as string
    
    if argv is {"on"} and ¬
        menuExtrasListAsString does not contain "Airport" then
        do shell script ¬
            "open -g '/System/Library/CoreServices/Menu Extras/Airport.menu'"
        return "The Wi-Fi menu bar icon is now showing..."
    else if argv is {"on"} and ¬
        menuExtrasListAsString contains "Airport" then
        return "The Wi-Fi menu bar icon is already showing..."
    else if argv is {"off"} and ¬
        menuExtrasListAsString contains "Airport" then
        my toggleMenuExtras()
        return "The Wi-Fi menu bar icon is no longer showing..."
    else if argv is {"off"} and ¬
        menuExtrasListAsString does not contain "Airport" then
        return "The Wi-Fi menu bar icon is already not showing..."
    end if
    
end run


--  ## Handler ##

on toggleMenuExtras()
    
    --  # Check to see if System Preferences is 
    --  # running and if yes, then close it.
    --  # 
    --  # This is done so the script will not fail 
    --  # if it is running and a modal sheet is 
    --  # showing, hence the use of 'killall' 
    --  # as 'quit' fails when done so, if it is.
    --  #
    --  # This is also done to allow default behaviors
    --  # to be predictable from a clean occurrence.
    
    if running of application "System Preferences" then
        try
            tell application "System Preferences" to quit
        on error
            do shell script "killall 'System Preferences'"
        end try
        delay 0.1
    end if
    
    --  # Make sure System Preferences is not running before
    --  # opening it again. Otherwise there can be an issue
    --  # when trying to reopen it while it's actually closing.
    
    repeat while running of application "System Preferences" is true
        delay 0.1
    end repeat
    
    --  # Open System Preferences to the Network pane. 
    
    tell application "System Preferences" to ¬
        reveal pane id "com.apple.preference.network"
    
    
    tell application "System Events"
        tell window 1 of application process "System Preferences"
            
            --  # Wait for the target UI element to be available.
            
            set i to 0
            repeat until exists scroll area 1
                delay 0.1
                set i to i + 1
                if i ≥ 30 then return
            end repeat
            
            --  # Select Wi-Fi from the list of services.
            
            try
                select ¬
                    (rows of table 1 of scroll area 1 ¬
                        whose value of static text 1 ¬
                        starts with "Wi-Fi")
            end try
            
            --  # Wait for the target UI element to be available.
            
            set i to 0
            repeat until exists group 1
                delay 0.1
                set i to i + 1
                if i ≥ 30 then return
            end repeat
            
            --  # Toggle the state of the checkbox:
            --  # Show Wi-Fi status in menu bar
            
            click checkbox 1 of group 1
            
        end tell
    end tell
    
    delay 0.2
    
    quit application "System Preferences"
    
end toggleMenuExtras

Notes:

Using the open command with the target Menu Extras adds its icon to the menu bar and is faster than calling the toggleMenuExtras() handler.



Battery Status Menu Bar Icon

To use the example AppleScript code as an executable shell script in Terminal, run the following compound command in Terminal:

f='batterymbi'; touch "$f"; open -e "$f"; chmod +x "$f"

In the opened batterymbi document, copy and paste the example AppleScript code into it, then save and close it.

Back in Terminal, type ./batterymbi and then press enter:

It should output:

Missing argument, e.g.,: batterymbi [on|off]

Meaning to use it you type either batterymbi on or batterymbi off to add to remove the Wi-Fi icon from the menu bar.

Then test it using ./batterymbi on and ./batterymbi off, however, do not run the commands immediately back to back as it takes a few moments for the script to run and the target .plist file to update.

Example AppleScript code:

#!/usr/bin/osascript

on run argv
    
    if argv is equal to {} then ¬
        return "Missing argument, e.g.,: " & ¬
            name of me & " [on|off]"
    
    set thePropertyListFilePath to ¬
        the POSIX path of ¬
            (path to preferences from user domain as string) & ¬
        "com.apple.systemuiserver.plist"
    
    tell application "System Events" to ¬
        tell the property list file thePropertyListFilePath to ¬
            set menuExtrasListAsString to the value of ¬
                the property list item ¬
                    "menuExtras" as string
    
    if argv is {"on"} and ¬
        menuExtrasListAsString does not contain "Battery" then
        do shell script ¬
            "open -g '/System/Library/CoreServices/Menu Extras/Battery.menu'"
        return "The battery status menu bar icon is now showing..."
    else if argv is {"on"} and ¬
        menuExtrasListAsString contains "Battery" then
        return "The battery status menu bar icon is already showing..."
    else if argv is {"off"} and ¬
        menuExtrasListAsString contains "Battery" then
        my toggleMenuExtras()
        return "The battery status menu bar icon is no longer showing..."
    else if argv is {"off"} and ¬
        menuExtrasListAsString does not contain "Battery" then
        return "The battery status menu bar icon is already not showing..."
    end if
    
end run


--  ## Handler ##

on toggleMenuExtras()

    --  # Check to see if System Preferences is 
    --  # running and if yes, then close it.
    --  # 
    --  # This is done so the script will not fail 
    --  # if it is running and a modal sheet is 
    --  # showing, hence the use of 'killall' 
    --  # as 'quit' fails when done so, if it is.
    --  #
    --  # This is also done to allow default behaviors
    --  # to be predictable from a clean occurrence.
    
    if running of application "System Preferences" then
        try
            tell application "System Preferences" to quit
        on error
            do shell script "killall 'System Preferences'"
        end try
        delay 0.1
    end if
    
    --  # Make sure System Preferences is not running before
    --  # opening it again. Otherwise there can be an issue
    --  # when trying to reopen it while it's actually closing.
    
    repeat while running of application "System Preferences" is true
        delay 0.1
    end repeat

    --  # Open System Preferences to the Energy Saver pane. 
    
    tell application "System Preferences" to ¬
        reveal pane id "com.apple.preference.energysaver"
    
    
    tell application "System Events"
        tell window 1 of application process "System Preferences"
            
            --  # Wait for the target UI element to be available.
            
            set i to 0
            repeat until exists checkbox 1
                delay 0.1
                set i to i + 1
                if i ≥ 30 then return
            end repeat
                        
            --  # Toggle the state of the checkbox:
            --  # Show battery status in menu bar
            
            click checkbox 1
            
        end tell
    end tell
    
    delay 0.2
    
    quit application "System Preferences"
    
end toggleMenuExtras

Notes:

Using the open command with the target Menu Extras adds its icon to the menu bar and is faster than calling the toggleMenuExtras() handler.

Also, with the Menu Extras for the Battery Status, there was issues with getting the [√] to stick when using the toggleMenuExtras() handler. While it did check it, it would only stick if the UI of System Preferences was made visible, which of course would somewhat defeat the purpose of doing this from the command line.



Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.