-
-
Save korylprince/be2e09e049d2fd721ce769770d983850 to your computer and use it in GitHub Desktop.
#!/usr/local/munki/munki-python | |
# change the above path to your own python if you don't have Munki installed | |
""" | |
Merges add_servers into current favorites and removes remove_servers. | |
Run as root to update all users or as normal user to update just that user. | |
""" | |
import os | |
import getpass | |
import subprocess | |
import uuid | |
import Foundation | |
favorites_path = "/Users/{user}/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl2" | |
# add these servers if they don't exist already | |
# use a tuple: ("<name>", "<path>") to set a name for the favorite. | |
# otherwise just use a string and the path will be used as the name | |
add_servers = (("My Name", "smb://server.example.com/share"), "vnc://server.example.com") | |
# remove these servers if they exist. Use a wildcard (*) at the end to remove all shares | |
# does not support ("<name>", "<path>") syntax | |
remove_servers = ("smb://old.example.com/*", "vnc://old.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, add_servers, remove_servers): | |
"Set the Server Favorites for the given user" | |
# read existing favorites file | |
data = Foundation.NSKeyedUnarchiver.unarchiveObjectWithFile_(favorites_path.format(user=user)) | |
# reformat add_servers to [(name, path), ...] | |
new_add_servers = [] | |
for s in add_servers: | |
if len(s) == 2: | |
new_add_servers.append(s) | |
else: | |
new_add_servers.append((s, s)) | |
add_servers = new_add_servers | |
existing_servers = [] | |
# read existing items safely | |
if data is not None: | |
data_items = data.get("items", []) | |
# read existing servers | |
for item in data_items: | |
name = item["Name"] | |
url, _, _ = Foundation.NSURL.initByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(Foundation.NSURL.alloc(), item["Bookmark"], Foundation.NSURLBookmarkResolutionWithoutUI, None, None, None) | |
existing_servers.append((name, url)) | |
# get unique ordered list of all servers | |
all_servers = [] | |
# add existing_servers to list, updating name if necessary | |
for s in existing_servers: | |
try: | |
idx = [a[1] for a in add_servers].index(s[1]) | |
all_servers.append((add_servers[idx][0], s[1])) | |
except ValueError: | |
all_servers.append(s) | |
# add add_servers if not present already | |
for s in add_servers: | |
if s[1] not in [e[1] for e in existing_servers]: | |
all_servers.append(s) | |
# remove old servers: exact match | |
# matches "smb://old.domain" exactly | |
all_servers = [s for s in all_servers if s[1] not in remove_servers] | |
# remove old servers: shares | |
# matches "smb://old.domain/*" | |
all_servers = [s for s in all_servers if len( | |
[True for r in remove_servers if r.endswith("*") and str(s[1]).startswith(r[:-1])] | |
) < 1] | |
# generate necessary structures | |
items = [] | |
for name, path in all_servers: | |
item = {} | |
item["Name"] = name | |
url = Foundation.NSURL.URLWithString_(str(path)) | |
bookmark, _ = url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(0, None, None, None) | |
item["Bookmark"] = bookmark | |
# generate a new UUID for each server | |
item["uuid"] = str(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, favorites_path.format(user=user)) | |
# loop through users and set favorites | |
if __name__ == "__main__": | |
# if running as root, run for all users. Otherwise run for current user | |
user = getpass.getuser() | |
if user == "root": | |
users = get_users() | |
else: | |
users = [user] | |
for user in users: | |
try: | |
set_favorites(user, add_servers, remove_servers) | |
# fix owner if ran as root | |
if user == "root": | |
os.system(("chown {user} " + favorites_path).format(user=user)) | |
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") |
#!/usr/local/munki/munki-python | |
# change the above path to your own python if you don't have Munki installed | |
""" | |
Overwrites server favorites with servers. | |
Run as root to update all users or as normal user to update just that user. | |
""" | |
import os | |
import getpass | |
import subprocess | |
import uuid | |
import Foundation | |
favorites_path = "/Users/{user}/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl2" | |
# Use a tuple: ("<name>", "<path>") to set a name for the favorite. | |
# Otherwise just use a string and the path will be used as the name | |
servers = (("My Name", "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: | |
name = server[0] if len(server) == 2 else server | |
path = server[1] if len(server) == 2 else server | |
item = {} | |
item["Name"] = name | |
url = Foundation.NSURL.URLWithString_(path) | |
bookmark, _ = url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(0, None, None, None) | |
item["Bookmark"] = bookmark | |
# generate a new UUID for each server | |
item["uuid"] = str(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, favorites_path.format(user=user)) | |
# loop through users and set favorites | |
if __name__ == "__main__": | |
# if running as root, run for all users. Otherwise run for current user | |
user = getpass.getuser() | |
if user == "root": | |
users = get_users() | |
else: | |
users = [user] | |
for user in users: | |
try: | |
set_favorites(user, servers) | |
# fix owner if ran as root | |
if user == "root": | |
os.system(("chown {user} " + favorites_path).format(user=user)) | |
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") |
Kory - thanks for maintaining this. Could I ask you a favor? Could you update the script to allow it to accept variables passed to it? I'm not a python guy, but I almost got it working with the macadmin's python3 and taking variables $4 thru $11 to add servers. Maybe $4 could declare if the rest are adding or removing or something. way over my head at this point but I'm working to learn more - got my books and stack overflow.
I tried the overwrite.py script in Ventura 13.2 and it worked, but only if not run as root. I found that the reason is that subprocess.check_output() returns the user list as "bytes". I got it working by adding ",encoding='UTF-8'" so that line 26 looks like this:
dscl_users = subprocess.check_output(["/usr/bin/dscl", ".", "-list", "/Users"],encoding='UTF-8').splitlines()
may I know how can I change the add_servers pointing to my specific local folder ? let's say I have the ABC folder inside the Documents, and would like to stick it into the SideBar
I've not had a chance to test this. I haven't actually used this code in several years, though I've tried to keep it updated for others. I don't see any reason it wouldn't work though, assuming you have a python3 installed.