Posted on 05-12-2014 07:12 AM
What has everyone found to be the most effective way of customizing the menu bar? Personally I'd like to have certain extras enforced on the menu bar, but allow the user to add additional ones if they like. For example:
Keychain status, AirPort, HomeSync, Battery, Clock, Volume, VPN
I've seen that "defaults write com.apple.systemuiserver menuExtras -array-add "<Extra>.menu"" will work. But it lacks the ability to see if that extra is already in the menu (so i get multiples if i just re-run it).
Posted on 05-12-2014 08:20 AM
I've been using com.apple.systemuiserver as you mentioned, though I've never been able to reliably get the binoculars that show remote access to work. (It will often work for the first user that logs in, but not subsequent ones)
I'd be interested in what you find.
Posted on 05-12-2014 08:37 AM
We use MCX to force homesync off menu bar and battery on. I tested config profiles doing same prefs works as well.
Posted on 05-12-2014 09:03 AM
@CasperSally: I see the "Managed Menu Extras" under Managed Preferences. How did you do the same with Configuration Profiles? I see that I could use Custom Settings to deploy a PLIST, but wouldn't that wipe out any menu's that a user would enable that we didn't care to enforce? I just want to ensure a few certain ones are on and then let the user have a choice for the others. Only in my first couple months using Mac's, so sorry for the noob question.
Thanks
Posted on 05-12-2014 09:38 AM
This isn't as easy as it sounds, certainly when using Managed Preferences (MCX) We use it here and unfortunately, if a user adds one of their own Menu Extras in,. its fine until they restart their Mac or log out and back in. At that point, the managed menu bar settings take over and any Menu Extras they added are removed.
This may be different when using Configuration Profiles, but I can't say since we don't use them for that here.
I'm not sure if there's a good solution to this issue.
We get occasional gripes/complaints from users that their Menu Extras aren't "sticking" Our solution for now is to instruct them to add the Menu Extra directly to their Account's Login Items by locating it in /System/Library/CoreServices/Menu Extras/ and dragging it into their Login Items. This has the effect of "opening" the Menu Extra at login, and you can still enforce whichever ones you want to have show up there at every login.
Although you could change the MCX to a One time only setting, that would mean if a user removes it, it won't come back at next login.
Posted on 05-12-2014 12:04 PM
You possibly may be able to add the items as a login item via a script.
See here for an example https://github.com/tkimpton/Scripts/blob/master/Bash/AddLoginItemADPassMon.sh
Posted on 05-12-2014 12:27 PM
I was able to write up a script that accomplishes the task. It parses the systemuiserver plist for references to the menu's I'm looking at and if something is missing it opens the menu to put it in. Haven't done much testing with it yet, but it works when I run it directly. It's failing when put in a policy due to running as root. Any suggestions on how to get it to update the plist for the logged on user? You can see I've tried a few things to get "currUser" which haven't worked.
#!/bin/bash
# This script adds items to the menu bar if they are not currently shown.
# Author: Jason Olsen
# Date: 05/12/2014
#currUser=$(who | grep "console" | cut -d" " -f1)
currUser='ls -l /dev/console | cut -d " " -f4'
Keychain=$(su - "${currUser}" -c 'grep "Keychain.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c')
if [ $Keychain == 0 ]; then
echo "Adding Keychain status to menu"
open '/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu'
fi
AirPort=$(grep "AirPort.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $AirPort == 0 ]; then
echo "Adding AirPort status to menu"
open '/System/Library/CoreServices/Menu Extras/AirPort.menu'
fi
HomeSync=$(grep "HomeSync.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $HomeSync == 0 ]; then
echo "Adding HomeSync status to menu"
open '/System/Library/CoreServices/Menu Extras/HomeSync.menu'
fi
Battery=$(grep "Battery.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $Battery == 0 ]; then
echo "Adding Battery status to menu"
open '/System/Library/CoreServices/Menu Extras/Battery.menu'
fi
Bluetooth=$(grep "Bluetooth.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $Bluetooth == 0 ]; then
echo "Adding Bluetooth status to menu"
open '/System/Library/CoreServices/Menu Extras/Bluetooth.menu'
fi
Clock=$(grep "Clock.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $Clock == 0 ]; then
echo "Adding Clock status to menu"
open '/System/Library/CoreServices/Menu Extras/Clock.menu'
fi
Volume=$(grep "Volume.menu" /Users/$currUser/Library/Preferences/com.apple.systemuiserver.plist -c)
if [ $Volume == 0 ]; then
echo "Adding Volume status to menu"
open '/System/Library/CoreServices/Menu Extras/Volume.menu'
fi
Posted on 05-12-2014 01:03 PM
@Jason, I wouldn't try running the commands as the user. Get the logged in user and use defaults against the account's com.apple.systemuiserver plist instead. Like this for example:
#!/bin/sh
currentUser=$( ls -l /dev/console | awk '{print $3}' )
userHome=$( dscl . read /Users/$currentUser NFSHomeDirectory | awk '{print $NF}' )
MenuExtras=$( defaults read "$userHome/Library/Preferences/com.apple.systemuiserver.plist" menuExtras | awk -F'"' '{print $2}' )
if [[ $( echo "${MenuExtras}" | grep "Keychain.menu" ) ]]; then
echo "do something"
else
echo "do something else"
fi
Just change what you grep for in each instance to check for the specific Menu Extras.
Posted on 05-12-2014 01:31 PM
Hi again @Jason. you got me thinking a bit about this process. Your solution is a pretty good one if you decide not to go the MCX or Config Profile route.
Here'a a modified version I just whipped up, It uses an array that you can specify in the script. Note that you enter the full path to the Menu Extra as it would show up on the command line, since that's how the plist stores the information.
It loops through each one, checking the logged in user's systemuiserver.plist file, and if the Menu Extra isn't present, opens it, or just echoes back that its already present. It may not be perfect, as in some cases, the plist doesn't get updated right away when a user Command drags an item off the menu bar, but in testing it seems to work pretty reliably. The good thing about using an array is that all you ever have to do is add/remove whichever Menu Extra items you want into the list on the top.
Here's the script. Check it out and see if it does what you want-
#!/bin/bash
PreferredMenuExtras=(
"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"
"/System/Library/CoreServices/Menu Extras/AirPort.menu"
"/System/Library/CoreServices/Menu Extras/Battery.menu"
"/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
"/System/Library/CoreServices/Menu Extras/Clock.menu"
"/System/Library/CoreServices/Menu Extras/Eject.menu"
)
currentUser=$( ls -l /dev/console | awk '{print $3}' )
userHome=$( dscl . read /Users/$currentUser NFSHomeDirectory | awk '{print $NF}' )
MenuExtras=$( defaults read "$userHome/Library/Preferences/com.apple.systemuiserver.plist" menuExtras | awk -F'"' '{print $2}' )
for menuExtra in "${PreferredMenuExtras[@]}"; do
menuShortName=$( echo "${menuExtra}" | awk -F'/' '{print $NF}' )
if [[ $( echo "${MenuExtras}" | grep "${menuExtra}" ) ]]; then
echo "Menu Extra "${menuShortName}" present"
else
echo "Menu Extra "${menuShortName}" not in plist. Opening..."
open "${menuExtra}"
fi
done
Obviously, edit the "PreferredMenuExtras" array to put the ones you want in there.
One last note. I haven't actually tested the "open" part of the script from a policy. Its possible this may not work and you may need to run the command as the user for it to work.
Posted on 07-18-2014 03:41 PM
One last note. I haven't actually tested the "open" part of the script from a policy. Its possible this may not work and you may need to run the command as the user for it to work.
Tested. Works. Love it. Thanks!
Posted on 07-21-2014 05:10 AM
One last note. I haven't actually tested the "open" part of the script from a policy. Its possible this may not work and you may need to run the command as the user for it to work. Tested. Works. Love it. Thanks!
I'm still actually trying to get that "open" part to work. It runs fine when I execute the script directly, but not when I run it from JAMF. Here is the script as it currently exists for me:
#!/bin/bash
PreferredMenuExtras=(
"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"
"/System/Library/CoreServices/Menu Extras/AirPort.menu"
"/System/Library/CoreServices/Menu Extras/Battery.menu"
"/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
"/System/Library/CoreServices/Menu Extras/Clock.menu"
"/System/Library/CoreServices/Menu Extras/Eject.menu"
)
## Get user context
currentUser=$3;echo "Current User: $currentUser"
userHome=$( dscl . read /Users/$currentUser NFSHomeDirectory | awk '{print $NF}' )
## Get list of current menu items
MenuExtras=$( defaults read "$userHome/Library/Preferences/com.apple.systemuiserver.plist" menuExtras | awk -F'"' '{print $2}' )
su $currentUser
for menuExtra in "${PreferredMenuExtras[@]}"; do
menuShortName=$( echo "${menuExtra}" | awk -F'/' '{print $NF}' )
if [[ $( echo "${MenuExtras}" | grep "${menuExtra}" ) ]]; then
## Menu extra already exists
echo "Menu Extra "${menuShortName}" present"
else
## Menu extra doesn't exist
echo "Menu Extra "${menuShortName}" not in plist. Opening "${menuExtra}"..."
menuItem=$menuExtra
## Open Menu extra so it is added to menu bar
sudo -u $currentUser open "$menuItem"
whoami
fi
done
It differs slightly from the previously posted script in that the open command gets run as the logged on user (and not root). But now I'm getting an error stating: LSOpenURLsWithRole() failed with error -10810 for the file /System/Library/CoreServices/Menu Extras/Bluetooth.menu
So still working through it.
Posted on 07-21-2014 08:49 AM
Hi @Jason, so in the Get user context section where the script gets the "loggedInUser" and other stuff, add this line just below everything else-
loggedInPID=$( ps -axj | awk "/^$loggedInUser/ && /Dock.app/ {print $2;exit}" )
Then replace the line that does sudo -u $currentUser open "$menuItem" toward the end with the following syntax-
/bin/launchctl bsexec "${loggedInPID}" sudo -iu "${loggedInUser}" "open "$menuItem""
The launchctl bsexec trick usually works when simply doing sudo -u user something doesn't work. Give that a try and see how you fare with that.
That LSOpenURLsWithRole error you see is just Mavericks being a biotch and not letting you run your open command in the user context. The above launchctl bsexec still isn't 100% guaranteed to work, but it usually does.
Posted on 07-22-2014 05:30 AM
The same issue seems to appear, but now I'm getting a second error as well:
Menu Extra "Battery.menu" not in plist. Opening "/System/Library/CoreServices/Menu Extras/Battery.menu"... LSOpenURLsWithRole() failed with error -10810 for the file /System/Library/CoreServices/Menu Extras/Battery.menu. launchctl bsexec failed: Inappropriate ioctl for device
Initially I was receiving an error when I ran against Dock.app, even from Terminal, so I changed it to loginwindow which was able to get me the PID. I also changed loggedInUser to currentUser since that's what I had already. It works from Terminal though. Are there any other ways around this to Open that menu extra?
#!/bin/bash
PreferredMenuExtras=(
"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"
"/System/Library/CoreServices/Menu Extras/AirPort.menu"
"/System/Library/CoreServices/Menu Extras/Battery.menu"
"/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
"/System/Library/CoreServices/Menu Extras/Clock.menu"
"/System/Library/CoreServices/Menu Extras/Eject.menu"
)
## Get user context
currentUser=$3;echo "Current User: $currentUser"
userHome=$( dscl . read /Users/$currentUser NFSHomeDirectory | awk '{print $NF}' )
loggedInPID=$( ps -axj | awk "/loginwindow/ {print $2;exit}" )
## Get list of current menu items
MenuExtras=$( defaults read "$userHome/Library/Preferences/com.apple.systemuiserver.plist" menuExtras | awk -F'"' '{print $2}' )
su $currentUser
for menuExtra in "${PreferredMenuExtras[@]}"; do
menuShortName=$( echo "${menuExtra}" | awk -F'/' '{print $NF}' )
if [[ $( echo "${MenuExtras}" | grep "${menuExtra}" ) ]]; then
## Menu extra already exists
echo "Menu Extra "${menuShortName}" present"
else
## Menu extra doesn't exist
echo "Menu Extra "${menuShortName}" not in plist. Opening "${menuExtra}"..."
menuItem=$menuExtra
## Open Menu extra so it is added to menu bar
#sudo -u $currentUser open "$menuItem"
#whoami
/bin/launchctl bsexec "${loggedInPID}" sudo -iu "${currentUser}" "open "$menuItem""
fi
done
Posted on 07-30-2014 08:25 AM
It differs slightly from the previously posted script in that the open command gets run as the logged on user (and not root).
@Jason What's the reasoning behind this? Why not just run the script as root using Casper?
Posted on 07-30-2014 11:11 AM
@Jason What's the reasoning behind this? Why not just run the script as root using Casper?
When I first started trying to get this working I think I ran it as root (mostly because I couldn't figure out how to run it as anything else). It didn't have any impact though and no errors were displayed. I was assuming that I need to run the commands as the logged on user to have it impact that users session (since the settings are user specific).
Posted on 07-30-2014 03:26 PM
@Jason If you could humour me: locally, without casper, what happens if you paste mm2270's script into a terminal after sudo -s with say, the keychain access menu item added?
sudo -s
Type your password
#!/bin/bash
PreferredMenuExtras=(
"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"
"/System/Library/CoreServices/Menu Extras/AirPort.menu"
"/System/Library/CoreServices/Menu Extras/Battery.menu"
"/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
"/System/Library/CoreServices/Menu Extras/Clock.menu"
"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"
)
currentUser=$( ls -l /dev/console | awk '{print $3}' )
userHome=$( dscl . read /Users/$currentUser NFSHomeDirectory | awk '{print $NF}' )
MenuExtras=$( defaults read "$userHome/Library/Preferences/com.apple.systemuiserver.plist" menuExtras | awk -F'"' '{print $2}' )
for menuExtra in "${PreferredMenuExtras[@]}"; do
menuShortName=$( echo "${menuExtra}" | awk -F'/' '{print $NF}' )
if [[ $( echo "${MenuExtras}" | grep "${menuExtra}" ) ]]; then
echo "Menu Extra "${menuShortName}" present"
else
echo "Menu Extra "${menuShortName}" not in plist. Opening..."
open "${menuExtra}"
fi
done
Posted on 01-26-2016 07:58 AM
OK, so this thread isn't that old but I just wanted to comment on @mm2270 's original suggestion. I've been testing it under 10.10 with local accounts and it's working brilliantly!
Posted on 01-26-2016 08:00 AM
However, what I'd really like to do is to create a profile that sets up the VN menu extra along with the VPN profile. Since we abandoned mcx a LONG time ago, it would be great to regain this functionality. I'm about to start playing with some of the manifests and mcxToProfile from jamfnation here but I'd love to know if anyone has a more modern solution... or at least thoughts.
Posted on 09-20-2019 04:50 AM
@Chris_Hafner Did you manage to create Config Profiles for the menubars in the end?
Posted on 09-20-2019 05:01 AM
Actually, no, though I'm going to go back to looking at it. FYI, I didn't do it because I ended up moving onto other projects and had a working solution. However, now that you bring it up...
Posted on 01-10-2020 01:38 PM
Works in Catalina 10.15.2
If you have it be Once Per User you should be able to avoid duplicates.
Posted on 09-18-2020 04:34 PM
@larry_barrett Like your solution. Just some observations.
The Volume does not work under BigSur Beta 20A5364e. The Volume.menu doesn't work when just opening it from the GUI, while VPN.menu works both from JAMF policy and GUI. Some of the .menu files that resided in /System/Library/CoreServices/Menu Extras/ are no longer there (ie Bluetooth). Still looking for them...
I am hoping these are just beta issues.
I would also have the policy run at every login, I don't get duplicate icons for the VPN. Still testing the others.
Posted on 10-29-2020 11:52 AM
I used the bluetooth menu bar item to pass a CIS benchmark? DId you find it or the moved menu bar items?
C
Posted on 11-17-2020 06:34 PM
After some experimenting, modifying the com.apple.controlcenter.plist file will allow you to add wifi and volume back to the men bar.
Posted on 12-03-2020 09:50 AM
I'm also using this to pass the 10.15 CIS Benchmark 2.1.3 for Bluetooth. Was wondering if this could also be used for 4.2 to show Wi-Fi status in menu bar?