With slftool
not able to add favorites in High Sierra, I set out on a journey to find an alternative. The sfl2 format is just a Foundation.NSKeyedArchiver
dump, so I wrote the following python script to generate the Server Favorites file:
Edit: See my post below for a script that applies to all users.
Edit 2: The latest version of these scripts are available here.
# some inspiration from: https://github.com/quicksilver/Quicksilver/blob/master/Quicksilver/Code-QuickStepCore/QSObject_FileHandling.m
# get the latest version of this script at: https://gist.github.com/korylprince/be2e09e049d2fd721ce769770d983850
import os
import uuid
import Foundation
servers = ("smb://server.example.com/share", "vnc://server.example.com")
user = "administrator"
items = []
for server in servers:
item = {}
item["Name"] = unicode(server)
url = Foundation.NSURL.URLWithString_(unicode(server))
bookmark, _ = url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(0, None, None, None)
item["Bookmark"] = bookmark
item["uuid"] = unicode(uuid.uuid1()).upper()
item["visibility"] = 0
item["CustomItemProperties"] = Foundation.NSDictionary.new()
items.append(Foundation.NSDictionary.dictionaryWithDictionary_(item))
data = Foundation.NSDictionary.dictionaryWithDictionary_({
"items": Foundation.NSArray.arrayWithArray_(items),
"properties": Foundation.NSDictionary.dictionaryWithDictionary_({"com.apple.LSSharedFileList.ForceTemplateIcons": False})
})
Foundation.NSKeyedArchiver.archiveRootObject_toFile_(data, "/Users/{user}/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl2".format(user=user))
os.system("killall sharedfilelistd")
Some caveats:
- This particular code is for the Finder Server Favorites list, but should be easily adaptable to the other lists (I haven't tried.)
- This code replaces the favorites file, though you could load the current file with
Foundation.NSKeyedUnarchiver
and append data to it pretty easily as well.
- Getting the settings to actually apply seems a bit finicky; if Finder is open the new settings won't take effect even if you kill
sharedfilelistd
.
Hope someone finds this useful!
@korylprince This did the trick for me. Much appreciated.
I just needed a simple way to deploy/mange SMB file server URL favorites which appear in the Finder's "Connect to Server..." box. All previous options have been "broken" since 10.13 High Sierra. Our file servers dont change often, but when they do its critical that all users know how to manually navigate to the new servers (in situations when a login script didn't/couldn't mount them)
I'm not a Python scripter (yet), so what I need to figure out next is how to extend your single-user focus out to recursively apply to ALL local homedirs in /Users.
@dstranathan Here's an updated script that will loop through all active users.
Edit: The latest version of these scripts are available here.
# get the latest version of this script at: https://gist.github.com/korylprince/be2e09e049d2fd721ce769770d983850
import os
import subprocess
import uuid
import Foundation
servers = ("smb://server.example.com/share", "vnc://server.example.com")
def get_users():
"Get users with a home directory in /Users"
# get users from dscl
dscl_users = subprocess.check_output(["/usr/bin/dscl", ".", "-list", "/Users"]).splitlines()
# get home directories
homedir_users = os.listdir("/Users")
# return users that are in both lists
users = set(dscl_users).intersection(set(homedir_users))
return [u.strip() for u in users if u.strip() != ""]
def set_favorites(user, servers):
"Set the Server Favorites for the given user"
# generate necessary structures
items = []
for server in servers:
item = {}
# use unicode to translate to NSString
item["Name"] = unicode(server)
url = Foundation.NSURL.URLWithString_(unicode(server))
bookmark, _ = url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(0, None, None, None)
item["Bookmark"] = bookmark
# generate a new UUID for each server
item["uuid"] = unicode(uuid.uuid1()).upper()
item["visibility"] = 0
item["CustomItemProperties"] = Foundation.NSDictionary.new()
items.append(Foundation.NSDictionary.dictionaryWithDictionary_(item))
data = Foundation.NSDictionary.dictionaryWithDictionary_({
"items": Foundation.NSArray.arrayWithArray_(items),
"properties": Foundation.NSDictionary.dictionaryWithDictionary_({"com.apple.LSSharedFileList.ForceTemplateIcons": False})
})
# write sfl2 file
Foundation.NSKeyedArchiver.archiveRootObject_toFile_(data, "/Users/{user}/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl2".format(user=user))
# loop through users and set favorites
if __name__ == "__main__":
for user in get_users():
try:
set_favorites(user, servers)
print "Server Favorites set for " + user
except Exception as e:
# if there's an error, log it an continue on
print "Failed setting Server Favorites for {0}: {1}".format(user, str(e))
# kill sharedfilelistd process to reload file. Finder should be closed when this happens
os.system("killall sharedfilelistd")
I've also added some comments to explain what the code does. Also note that this won't do anything for a User who hasn't signed in yet. This only works for users that already have a home directory created in /Users
. All of the caveats from my post above still apply.
@korylprince Very nice. I have been using this script with a jamf policy to generate shortcuts:
when used as a script payload, the even variables are urls and the odd variable is the finder name.
I don't know python yet, but this gives me an excuse to learn.
#!/bin/bash
evens=( "$4" "$6" "$8" "${10}" )
odds=( "$5" "$7" "$9" "${11}" )
for ((i=0;i<${#evens[@]};++i)); do
if [[ -n ${evens[i]} ]]; then
sfltool add-item -n "${odds[i]}" com.apple.LSSharedFileList.FavoriteServers "${evens[i]}" &> /dev/null &&
sleep 2
/usr/libexec/PlistBuddy -c "Add URL string '${evens[i]}'" "/Users/$3/Desktop/Server Aliases/${odds[i]}.afploc"
fi
done
@korylprince are you using #!/usr/bin/python to run this?
I have run the script using #!/usr/bin/python and get this echoed in terminal - "Server Favorites set for username" , but nothing shows even after logout/login or restart.
Maybe I am missing something in the compiler?
Thanks
Michael
@korylprince, where do I send the bitcoins?!
Thank guy guys, this is great!
@mlitton,
I was just running sudo python /path/to/script.py
, but using #!/usr/bin/python
will work as well. All Finder windows must be closed or the changes may not apply.
I have updated my scripts. One can be used to overwrite the current favorites, and the other can merge into existing favorites, optionally also removing specified servers. If the scripts are run as root, they will affect all users. If they are run as a normal user they will just affect that user.
You can see them on GitHub.
I have been using versions of Kory's scripts - they work great. I finally have robust control over deploying and managing Server URL favorites. I'm a happy camper.
I use have both versions of the script (destructive and non-destructive). There was time when I needed to add a single specific new SMB server. I didn't want to break/delete any user's existing Server Favorites (used a non-destructive version). In another situation, we migrated to new SMB servers, so I replaced ALL Server URL Favorites with new Favorites - so user's weren't confused (I used a destructive 'nuke & pave' version of the script).
@djdavetrouble I'm not nearly as familiar with python as I should be. Did you get anywhere in your version such that you could set both the server and the Finder name?
I'm in the same boat. Is there any version of any of these scripts that allows for, at least, adding an entry and it's "friendly name"?
This is super clunky but works from 10.9 to 10.13 (running as the user):
#!/bin/bash
path="/path/you/want/to/add"
function side_shortcut () {
/usr/bin/osascript > /dev/null 2>&1 <<-END
tell application "Finder" to activate
tell application "System Events"
try
keystroke "t" using {command down, control down}
end try
end tell
END
}
/usr/bin/open "$path"
side_shortcut
exit 0
Hi guys so I'm running into a slight issue with this and feel like I'm missing something. Here is the script I'm currently running.
#!/bin/sh
python - <<EOF
import sys
sys.path.append('/usr/local/bin')
from FinderSidebarEditor import FinderSidebar # Import the module
sidebar = FinderSidebar() # Create a Finder sidebar instance to act on.
sidebar.removeAll() # Remove All Favorites from sidebar
sidebar.add("/Applications") # Add '/Applications' favorite to sidebar
sidebar.add("/Users/testuser/Desktop") # Add 'User Desktop' favorite to sidebar
sidebar.add("/Users/testuser/Documents") # Add 'User Documents' favorite to sidebar
sidebar.add("/Users/testuser/Downloads") # Add 'User Downloads' favorite to sidebar
EOF
Now if I run this locally, or as a command through ARD it does exactly what I expect it to do. However the moment I try running it through Jamf Remote it stops functioning. Logs say it completed successfully but the changes are never made to Finder for the currently logged in user. Just to further test I added the following lines at the bottom.
import os
path = '/Users/testuser/Desktop/PYTHON'
os.mkdir(path)
Running through Jamf Remote this does create a folder on the Desktop called "PYTHON" so from what I can tell the script does appear to be running correctly in every sense, Finder is just not refreshing correctly.
Forgot to mention I have tried running the script with "killall cfprefsd" and/or "killall Finder" at the end just to see if this would give any different results but it's still the same.
Thanks.
@aporlebeke, @georgecm12
I've updated my example scripts on GitHub to include the ability to set a favorite name.
Example:
servers = (("My Name", "smb://example.com/share"), "vnc://example.com")
This would create a favorite named "My Name" pointed to smb://example.com/share
and another favorite both named and pointed to vnc://example.com
.
Hopefully this should do what you're wanting.
Much appreciated, @korylprince .
Because of timing and my inability to full vet and test this before we deployed I moved most of these shortcuts to NoMAD, as we can configure who has access to what based on AD security group membership and our NoMAD shares config profile.
Hi @korylprince
I tried running the most recent version of your script from your GitHub page, but I'm getting the error:
" File "./connecttoserver_v2.py", line 20
"Get users with a home directory in /Users"
^
IndentationError: expected an indented block"
Am I doing something wrong?
Edit: Nevermind, I just don't know how to use GitHub properly...
Thanks,
Noah Blair
@korylprince this was working great up until Catalina. But I guess some Python functionality has been deprecated, including the Foundation module. Do you happen to have a workaround for this? And thank you for creating this script to begin with, it's been a total lifesaver for me.
Thanks,
Chris
If the sidebar is all you care about @tuck.itadmin have you tried mysides? We're not on Catalina but still works great on Mojave (10.14.6)
I'm just now getting to testing this with Catalina. Catalina didn't remove python, just deprecated it; so we're fine for now. When it's gone we'll have to come up with another alternative (maybe a compiled Swift app?)
My scripts work, however there are some caveats. If you try to run the script directly in terminal, you'll find it runs, but it doesn't work. It turns out the com.apple.sharedfilelist directory is now protected along with the other security improvements in Catalina. To get it to run, you have to enable full disk access for terminal in the Security & Privacy settings.
I have not yet attempted to run the script in an automated process, so I'm not sure what, if any, hoops you'll have to jump through to get it to run properly.
By chance has anyone updated this handy script for Python3? I am seeing an error:
File "configureServerFavorites.py", line 123, in <module>
item["Name"] = unicode(server)
NameError: name 'unicode' is not defined
By chance has anyone updated this handy script for Python3? I am seeing an error:
File "configureServerFavorites.py", line 123, in <module>
item["Name"] = unicode(server)
NameError: name 'unicode' is not defined
Figured it out: Python3 doesn't need Unicode to be explicitly defined as Python2 did - it supports Unicode by default. So I changed type 'unicode' to type 'str' and resolved the issue.
Hi @korylprince,
Any chance you have an update on this awesome script? Looks like 12.3 and up said bye to Python 2. Here's the error now:
/usr/bin/python: bad interpreter: No such file or directory
Error running script: return code was 126.
Hi @korylprince,
Any chance you have an update on this awesome script? Looks like 12.3 and up said bye to Python 2. Here's the error now:
/usr/bin/python: bad interpreter: No such file or directory
Error running script: return code was 126.
12.3 said goodbye to all versions of python. Going forward you'll need to install it yourself if you want to use python.
I've updated the scripts and tested them on successfully on 12.3.1 with Munki's python. Make sure to read the comments there. I'm also working on a compiled solution to this so python won't be required, but have no ETA on when that will be ready.
Has anyone gotten this to work with Python3?
How are ya'll adding AirDrop back to the Finder Sidebar?
I'm trying this command with mysides but getting nowhere:
$mysides add domain-AirDrop "nwnode://domain-AirDrop"
killall cfprefsd
It's not perfect, but it works. It opens a separate finder window when you click on the item.
mysides add AirDrop file:///System/Library/CoreServices/Finder.app/Contents/Applications/AirDrop.app/