Skip to content

Instantly share code, notes, and snippets.

@zaxbux
Last active November 15, 2024 18:20
Show Gist options
  • Save zaxbux/0f3662c8390a1bcf3773a1fea62714e5 to your computer and use it in GitHub Desktop.
Save zaxbux/0f3662c8390a1bcf3773a1fea62714e5 to your computer and use it in GitHub Desktop.
Mac sysadmin

Startup

Paths

  • ~/Library/Saved Application State/

OpenSSL

In case Keychain complains about certificates touched by openssl, make sure to use the system binary and not one installed by the user.

/usr/bin/openssl

Printers

# Generate the ppd
/System/Library/Printers/Libraries/ipp2ppd ipp://ipaddress/ipp/print /tmp/test > printer.ppd

# Setup the printer
/usr/sbin/lpadmin -p #{printer_name} -E -D "#{printer_name}" -P "/tmp/test/printer.ppd" -v ipp://ippaddress/ipp/print -L "#{printer_description}" -o printer-is-shared=false 2>&1

System Settings

Date

sudo systemsetup -getdate
sudo systemsetup -setdate <mm:dd:yy>

Time

sudo systemsetup -gettime
sudo systemsetup -settime <hh:mm:ss>

Timezone

sudo systemsetup -listtimezones
sudo systemsetup -gettimezone
sudo systemsetup -settimezone America/Vancouver

Enable location services

#!/bin/bash

uuid=$("/usr/sbin/system_profiler" SPHardwareDataType | grep "Hardware UUID" | awk '{ print $3 }')
timedPrefs="/private/var/db/timed/Library/Preferences/com.apple.timed.plist"
dateTimePrefs="/private/var/db/timed/Library/Preferences/com.apple.preferences.datetime.plist"
locationPrefs="/private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.${uuid}.plist"
byHostPath="/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd"

# Set preferences.
echo "Ensuring location services are enabled"
sudo -u "_locationd" /usr/bin/defaults -currentHost write "$locationPrefs" LocationServicesEnabled -int 1
sudo defaults write "${byHostPath}" LocationServicesEnabled -int 1
/usr/sbin/chown "_locationd:_locationd" "$locationPrefs"

echo "Configuring automatic time"
/usr/bin/defaults write "$timedPrefs" TMAutomaticTimeZoneEnabled -bool YES
/usr/bin/defaults write "$timedPrefs" TMAutomaticTimeOnlyEnabled -bool YES
/usr/bin/defaults write "$dateTimePrefs" timezoneset -bool YES
/usr/sbin/chown "_timed:_timed" "$timedPrefs" "$dateTimePrefs"

exit 0
  • Tested: macOS 14
  • Reboot required: Yes for macOS 14.4 since launchctl no longer has control over important system processes

Source: https://community.jamf.com/t5/jamf-pro/how-to-enable-the-set-time-zone-automatically-using-your-current/m-p/303766/highlight/true#M266304

Enable Screen Sharing

defaults write /var/db/launchd.db/com.apple.launchd/overrides.plist com.apple.screensharing -dict Disabled -bool false

Finder

Create alias

$DIR/$ALIAS -> $TARGET

osascript \
    -e 'tell application "Finder"' \
    -e '  set theTgt to POSIX file "'"$TARGET"'" as alias' \
    -e '  make new alias to theTgt at POSIX file "'"$DIR"'"' \
    -e '  set name of result to "'"$ALIAS"'"' \
    -e 'end tell'

Move File/Folder to Trash

osascript -e 'tell application "Finder" to delete ((POSIX file "<FILE_PATH>") as alias)'

Security

Password hints

Disable

  • macOS 10.7+
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0”>
<dict>
	<key>PayloadContent</key>
	<array>
		<dict>
			<!-- ... -->
			
			<key>RetriesUntilHint</key>
			<integer>0</integer>
			
			<!-- ... -->
			<key>PayloadIdentifier</key>
			<string>com.example.myloginwindowpayload</string>
			<key>PayloadType</key>
			<string>com.apple.loginwindow</string>
			<key>PayloadUUID</key>
			<string>fe9ba3c5-0f1a-45c7-b6df-a5f4489695fe</string>
			<key>PayloadVersion</key>
			<integer>1</integer>
		</dict>
	</array>
	<key>PayloadDisplayName</key>
	<string>Login Window</string>
	<key>PayloadIdentifier</key>
	<string>com.example.myprofile</string>
	<key>PayloadType</key>
	<string>Configuration</string>
	<key>PayloadUUID</key>
	<string>61bd7d63-4a4a-4b67-9112-5ceb16afb4dc</string>
	<key>PayloadVersion</key>
	<integer>1</integer>
</dict>
</plist>
defaults write com.apple.loginwindow RetriesUntilHint -int 0

Users

Check out "Directory Utility":/System/Library/CoreServices/Applications/Directory Utility.app

Check password

dscl /Local/Default -authonly $USERNAME $PASSWORD

Return code 0 on success, 10 on failure.

Create a user (10.10+)

Hidden admin user:

LOCAL_ADMIN_FULLNAME="Joe Admin"     # The local admin user's full name
LOCAL_ADMIN_SHORTNAME="joeadmin"     # The local admin user's shortname
LOCAL_ADMIN_PASSWORD="password"      # The local admin user's password

# Create a local admin user account
sysadminctl -addUser $LOCAL_ADMIN_SHORTNAME -fullName "$LOCAL_ADMIN_FULLNAME" -password "$LOCAL_ADMIN_PASSWORD"  -admin
dscl . create /Users/$LOCAL_ADMIN_SHORTNAME IsHidden 1  # Hides the account (10.10 and above)
mv /Users/$LOCAL_ADMIN_SHORTNAME /var/$LOCAL_ADMIN_SHORTNAME # Moves the admin home folder to /var
dscl . -create /Users/$LOCAL_ADMIN_SHORTNAME NFSHomeDirectory /var/$LOCAL_ADMIN_SHORTNAME # Create new home dir attribute
dscl . -delete "/SharePoints/$LOCAL_ADMIN_FULLNAME's Public Folder" # Removes the public folder sharepoint for the local admin

Create a user (Prior to 10.5 - 10.9)

USERID=$(dscl . -list /Users UniqueID | awk 'BEGIN { max = 500; } { if ($2 > max) max = $2; } END { print max + 1; }')

dscl . -create /Users/$USERNAME
dscl . -create /Users/$USERNAME UserShell /bin/bash
dscl . -create /Users/$USERNAME RealName "$FULLNAME"
dscl . -create /Users/$USERNAME UniqueID "$USERID"
# 'staff' user group
dscl . -create /Users/$USERNAME PrimaryGroupID 20
dscl . -create /Users/$USERNAME NFSHomeDirectory /Users/$USERNAME

dscl . -passwd /Users/$USERNAME $PASSWORD

dseditgroup -o edit -t user -a $USERNAME admin

createhomedir -c -u $USERNAME > /dev/null

Starting with Catalina, the default UserShell is /bin/zsh.

Password hint

Change

  • macOS ??
# dscl . -merge /Users/$USERNAME hint "your password hint"
dscl . -merge /Users/$USERNAME AuthenticationHint "your password hint"

Read

dscl . -read /Users/$USERNAME AuthenticationHint

Delete

#!/bin/sh

for userhomedir in /Users/*/
do /usr/bin/dscl . -delete "$userhomedir" AuthenticationHint
done

List Users

dscacheutil -q user | grep -A 3 -B 2 -e uid:\ 5'[0-9][0-9]'
dscl . list /Users UniqueID | grep -v '^_'
  • macOS: 10.15+

Delete a user

This does not delete the /Users/<user> folder.

/usr/bin/dscl . -delete /Users/<user>

Make an admin user a standard user

sudo dseditgroup -o edit -d <user> -t user admin

Rename a user

User being renamed must not be signed in.

dscl . change /Users/<old> NFSHomeDirectory /Users/<old> /Users/<new>
mv /Users/<old> /Users/<new>
dscl . change /Users/<old> RecordName <old> <new>

See the RenameMacUserNameAndHomeDirectory.sh below.

Set User Picture

#!/bin/sh
user="$1"
image="$2"
dscl . delete "/Users/$user" JPEGPhoto
dscl . delete "/Users/$user" Picture
tmp="$(mktemp)"
printf "0x0A 0x5C 0x3A 0x2C dsRecTypeStandard:Users 2 dsAttrTypeStandard:RecordName base64:dsAttrTypeStandard:JPEGPhoto\n%s:%s" \
    "$user" "$(base64 -i "$image")" > "$tmp"
dsimport "$tmp" /Local/Default M
rm "$tmp"

Usage: sudo setUserPicture <user> <image path>

Source: https://apple.stackexchange.com/a/432510

Log Out a User

Current User

With confirmation:

osascript -e 'tell app "System Events" to log out'

Without confirmation:

ignoring application responses
    tell app "System Events" to  «event aevtrlgo»
	-- OR:
    -- tell application "loginwindow" to «event aevtrlgo»
end ignoring
osascript -e 'tell app "System Events" to «event aevtrlgo»'

Source: https://apple.stackexchange.com/a/126762

Specific User

sudo launchctl bootout "gui/$(id -u <username>)"
# OR
sudo launchctl bootout "user/$(id -u <username>)"
  • macOS 10.11.x or later

Apps

Silently Uninstall Adobe Acrobat DC

sudo /Applications/Adobe\ Acrobat\ DC/Adobe\ Acrobat.app/Contents/Helpers/Acrobat\ Uninstaller.app/Contents/Library/LaunchServices/com.adobe.Acrobat.RemoverTool

Find app path by bundle id

mdfind kMDItemCFBundleIdentifier = "com.adobe.reader"

CLI Tools

pluginkit

pluginkit manages the PlugInKit subsystem for the current user. plugin plug-in extension pluginkit

Examples

List all extensions:

pluginkit -m

Enable an extension:

pluginkit -e use -i com.google.drivefs.finderhelper.findersync

du

Display disk usage statistics.

Examples

Size of each user's home directory:

du -h -d 1 -I Library -I .Trash /Users

-I excludes the directories that usually result in errors

systemsetup

Configuration tool for certain machine settings in System Settings.

  • man: Yes
  • Path: /usr/sbin/systemsetup
systemsetup -getdate
systemsetup -setdate <mm:dd:yy>
systemsetup -gettime
systemsetup -settime <hh:mm:ss>
systemsetup -gettimezone
systemsetup -settimezone <timezone>
systemsetup -listtimezones
systemsetup -getusingnetworktime
systemsetup -setusingnetworktime <on off>
systemsetup -getnetworktimeserver
systemsetup -setnetworktimeserver <timeserver>
systemsetup -getsleep
systemsetup -setsleep <minutes>
systemsetup -getcomputersleep
systemsetup -setcomputersleep <minutes>
systemsetup -getdisplaysleep
systemsetup -setdisplaysleep <minutes>
systemsetup -getharddisksleep
systemsetup -setharddisksleep <minutes>
systemsetup -getwakeonmodem
systemsetup -setwakeonmodem <on off>
systemsetup -getwakeonnetworkaccess
systemsetup -setwakeonnetworkaccess <on off>
systemsetup -getrestartpowerfailure
systemsetup -setrestartpowerfailure <on off>
systemsetup -getrestartfreeze
systemsetup -setrestartfreeze <on off>
systemsetup -getallowpowerbuttontosleepcomputer
systemsetup -setallowpowerbuttontosleepcomputer <on off>
systemsetup -getremotelogin
systemsetup -setremotelogin <on off>
systemsetup -getremoteappleevents
systemsetup -setremoteappleevents <on off>
systemsetup -getcomputername
systemsetup -setcomputername <computername>
systemsetup -getlocalsubnetname
systemsetup -setlocalsubnetname <name>
systemsetup -getstartupdisk
systemsetup -setstartupdisk <disk>
systemsetup -liststartupdisks
systemsetup -getwaitforstartupafterpowerfailure
systemsetup -setwaitforstartupafterpowerfailure <seconds>
systemsetup -getdisablekeyboardwhenenclosurelockisengaged
systemsetup -setdisablekeyboardwhenenclosurelockisengaged <yes no>
systemsetup -version
systemsetup -help
systemsetup -printCommands

dscl

Directory service command line utility.

  • man: Yes
  • Path: /usr/bin/dscl

plutil

Property list utility

  • man: Yes
  • Path: /usr/bin/plutil

Convert a binary base64 encoded plist (bplist) to JSON

echo "YnBsaXN0MDDRAQJWbW9kdWxl0QMEWHJlbGF0aXZlXxA7ZmlsZTovLy9TeXN0ZW0vTGlicmFyeS9FeHRlbnNpb25LaXQvRXh0ZW5zaW9ucy9GbHVycnkuYXBwZXgICxIVHgAAAAAAAAEBAAAAAAAAAAUAAAAAAAAAAAAAAAAAAABc" | base64 -d -i - | plutil -convert json -o - -- -

https://developer.apple.com/documentation/devicemanagement/nsextensionmanagement

Devices running macOS 10.14+

Extension Bundle ID
AirDrop com.apple.share.AirDrop.send
FinderSync com.apple.FinderSync
Mail com.apple.share.Mail.compose
Messages com.apple.messages.ShareExtension
Photos com.apple.share.System.add-to-iphoto
Aperture com.apple.share.System.add-to-aperture
Reading List com.apple.share.System.add-to-safari-reading-list
Notes com.apple.Notes.SharingExtension
Reminders com.apple.reminders.RemindersShareExtension
iCloud Share com.apple.share.CloudSharing.invite
Single Sign On Extensions com.apple.app-sso
Single Sign On Kerberos Extension com.apple.AppSSOKerberos.KerberosExtension
  1. Create your workflow

  2. Save workflow as an app

    Note: There is a bug in Automator (macOS 14.4.1?) where the app is initially always saved as a workflow.

    Fix: Close Automator, then re-open the .app in Automator and save the file. This "repairs" the app.

  3. Sign app

    This is necessary in order to apply Privacy Preferences Policies.

    See: https://developer.apple.com/documentation/xcode/creating-distribution-signed-code-for-the-mac

    1. Obtain a Developer ID Application certificate from https://developer.apple.com/account/resources/certificates and add to your keychain.
      codesign -s "Developer ID Application: Johnny Appleseed (XXXXXXXXXX)" --deep --force --timestamp -o runtime YourWorkflow.app
      codesign -d -r - YourWorkflow.app
      

      See https://forums.developer.apple.com/forums/thread/129980 for explaination on why --deep is necessary for Automator apps.

  4. Create package installer

    https://developer.apple.com/documentation/xcode/packaging-mac-software-for-distribution

    1. Obtain a Developer ID Installer certificate from https://developer.apple.com/account/resources/certificates and add to your keychain.
    2. Find your Installer-signing identity:
      security find-identity -v
      
    3. Sign:
      productbuild --sign <Identity> --component YourWorkflow.app /Applications YourWorkflow.pkg
      

      Note: Notarization is not necessary when deploying via MDM.

Resize a window to a specific size

osascript -e 'tell application "Google Chrome" to set the bounds of the front window to {0, 0, 1920, 1080}'
#!/bin/bash
: '
Script to rename the username of a user account on MacOS
The script updates the users record name (username), RealName (displayName), and home directory
If the user receiving the name change is signed in they will be signed out.
Example usage: sudo sh RenameMacUserNameAndHomeDirectory.sh cat dog
Above example would rename account cat to dog
NOTE: SCRIPT MUST BE RUN AS ROOT
NOTE: SYSTEM WILL RESTART AFTER SUCCESSFUL NAME UPDATE
https://community.spiceworks.com/t/mac-account-rename-script-username-home-directory-display-name/975280
'
# Ensures that script is run as ROOT
if [[ "${UID}" != 0 ]]; then
(echo >&2 "Error: $0 script must be run as root")
exit 1
fi
# Ensures that the system is not domain bound
readonly domainBoundCheck=$(dsconfigad -show)
if [[ "${domainBoundCheck}" ]]; then
(echo >&2 "Cannot run on domain bound system. Unbind system and try again.")
exit 1
fi
# Ensures that parameters are entered
if [[ ${#} -ne 2 ]]; then
echo "Usage: $0 oldUserName newUserName"
exit 1
fi
oldUser=$1
newUser=$2
# Test to ensure logged in user is not being renamed
readonly loggedInUser=$(ls -la /dev/console | cut -d " " -f 4)
if [[ "${loggedInUser}" == "${oldUser}" ]]; then
echo "Cannot rename active GUI logged in user. Log in with another admin account and try again."
exit 1
fi
# Verify valid username
if [[ -z "${newUser}" ]]; then
echo "New user name must not be empty!"
exit 1
fi
# Test to ensure account update is needed
if [[ "${oldUser}" == "${newUser}" ]]; then
echo "No updates needed"
exit 0
fi
# Query existing user accounts
readonly existingUsers=($(dscl . -list /Users | grep -Ev "^_|com.*|root|nobody|daemon|\/" | cut -d, -f1 | sed 's|CN=||g'))
# Ensure old user account is correct and account exists on system
if [[ ! " ${existingUsers[@]} " =~ " ${oldUser} " ]]; then
echo "${oldUser} account not present on system to update"
exit 1
fi
# Ensure new user account is not already in use
if [[ " ${existingUsers[@]} " =~ " ${newUser} " ]]; then
echo "${newUser} account already present on system. Cannot add duplicate"
exit 1
fi
# Query existing home folders
readonly existingHomeFolders=($(ls /Users))
# Ensure existing home folder is not in use
if [[ " ${existingHomeFolders[@]} " =~ " ${newUser} " ]]; then
echo "${newUser} home folder already in use on system. Cannot add duplicate"
exit 1
fi
# Checks if user is logged in
loginCheck=$(ps -Ajc | grep ${oldUser} | grep loginwindow | awk '{print $2}')
# Logs out user if they are logged in
timeoutCounter='0'
while [[ "${loginCheck}" ]]; do
echo "${oldUser} account logged in. Logging user off to complete username update."
sudo launchctl bootout gui/$(id -u ${oldUser})
Sleep 5
loginCheck=$(ps -Ajc | grep ${oldUser} | grep loginwindow | awk '{print $2}')
timeoutCounter=$((${timeoutCounter} + 1))
if [[ ${timeoutCounter} -eq 4 ]]; then
echo "Timeout unable to log out ${oldUser} account."
exit 1
fi
done
# Captures current "RealName" this is the displayName
fullRealName=$(dscl . -read /Users/${oldUser} RealName)
# Formats "RealName"
readonly origRealName=$(echo ${fullRealName} | cut -d' ' -f2-)
# Updates "RealName" to new username (Yes JCAgent will overwrite this after user/system association)
sudo dscl . -change "/Users/${oldUser}" RealName "${origRealName}" "${newUser}"
if [[ $? -ne 0 ]]; then
echo "Could not rename the user's RealName in dscl. - err=$?"
echo "Reverting RealName changes"
sudo dscl . -change "/Users/${oldUser}" RealName "${origRealName}" "${origRealName}"
exit 1
fi
# Captures current NFS home directory
readonly origHomeDir=$(dscl . -read "/Users/${oldUser}" NFSHomeDirectory | awk '{print $2}' -)
if [[ -z "${origHomeDir}" ]]; then
echo "Cannot obtain the original home directory name, is the oldUserName correct?"
echo "Reverting RealName changes"
sudo dscl . -change "/Users/${oldUser}" RealName "${newUser}" "${origRealName}"
exit 1
fi
# Updates NFS home directory
sudo dscl . -change "/Users/${oldUser}" NFSHomeDirectory "${origHomeDir}" "/Users/${newUser}"
if [[ $? -ne 0 ]]; then
echo "Could not rename the user's home directory pointer, aborting further changes! - err=$?"
echo "Reverting Home Directory changes"
sudo dscl . -change "/Users/${oldUser}" NFSHomeDirectory "/Users/${newUser}" "${origHomeDir}"
echo "Reverting RealName changes"
sudo dscl . -change "/Users/${oldUser}" RealName "${newUser}" "${origRealName}"
exit 1
fi
# Updates name of home directory to new username
mv "${origHomeDir}" "/Users/${newUser}"
if [[ $? -ne 0 ]]; then
echo "Could not rename the user's home directory in /Users"
echo "Reverting Home Directory changes"
mv "/Users/${newUser}" "${origHomeDir}"
sudo dscl . -change "/Users/${oldUser}" NFSHomeDirectory "/Users/${newUser}" "${origHomeDir}"
echo "Reverting RealName changes"
sudo dscl . -change "/Users/${oldUser}" RealName "${newUser}" "${origRealName}"
exit 1
fi
# Actual username change
sudo dscl . -change "/Users/${oldUser}" RecordName "${oldUser}" "${newUser}"
if [[ $? -ne 0 ]]; then
echo "Could not rename the user's RecordName in dscl - the user should still be able to login, but with user name ${oldUser}"
echo "Reverting username change"
sudo dscl . -change "/Users/${oldUser}" RecordName "${newUser}" "${oldUser}"
echo "Reverting Home Directory changes"
mv "/Users/${newUser}" "${origHomeDir}"
sudo dscl . -change "/Users/${oldUser}" NFSHomeDirectory "/Users/${newUser}" "${origHomeDir}"
echo "Reverting RealName changes"
sudo dscl . -change "/Users/${oldUser}" RealName "${newUser}" "${origRealName}"
exit 1
fi
# Links old home directory to new. Fixes dock mapping issue
ln -s "/Users/${newUser}" "${origHomeDir}"
# Success message
read -r -d '' successOutput <<EOM
Success ${oldUser} username has been updated to ${newUser}
Folder "${origHomeDir}" has been renamed to "/Users/${newUser}"
RecordName: ${newUser}
RealName: ${newUser}
NFSHomeDirectory: "/Users/${newUser}"
SYSTEM RESTARTING in 5 seconds to complete username update.
EOM
echo "${successOutput}"
# System restart
Sleep 5
osascript -e 'tell application "System Events" to restart'
exit 0

Links

Examples

Catalina (10.15) and up

defaults -currentHost read com.apple.screensaver moduleDict
  • Flurry
    {
      moduleName = Flurry;
      path = "/System/Library/ExtensionKit/Extensions/Flurry.appex";
      type = 0;
    }
    

macOS Sonoma (14)

This has changed in Sonoma. New location: ~/Library/Application\ Support/com.apple.wallpaper/Store/Index.plist

loggedInUser=$(/usr/bin/stat -f%Su /dev/console)
wallpaper_store_path="/Users/${loggedInUser}/Library/Application Support/com.apple.wallpaper/Store/Index.plist"
getScreensaverBase64=$(plutil -extract AllSpacesAndDisplays xml1 -o - "${wallpaper_store_path}" | awk '/<data>/,/<\/data>/' | xargs | tr -d " " | tr "<" "\n" | tail -2 | head -1 | cut -c6-)
echo "$getScreensaverBase64" | base64 -d -i - | plutil -convert json -o - -- -
  • Flurry
    {"module":{"relative":"file:\/\/\/System\/Library\/ExtensionKit\/Extensions\/Flurry.appex"}}

Get Wallpaper

Simple method

osascript -e 'tell app "finder" to get posix path of (get desktop picture as alias)'

Sonoma

This doesn't work if 'Show on all Spaces' is turned off.

plutil -extract AllSpacesAndDisplays.Desktop.Content.Choices xml1 -o - ~/Library/Application\ Support/com.apple.wallpaper/Store/Index.plist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment