├── .gitignore ├── README.md ├── functions ├── Bash │ ├── README.md │ ├── create_folder │ │ ├── README.md │ │ └── create_folder.sh │ ├── folder_hierachy_from_date │ │ ├── README.md │ │ └── folder_hierachy_from_date.sh │ ├── move_file_ftp │ │ ├── README.md │ │ └── move_file_ftp.sh │ ├── variables_script │ │ ├── README.md │ │ └── variables_script.sh │ ├── variables_sgr-escape-sequence │ │ ├── README.md │ │ └── variables_sgr-escape-sequence.sh │ └── variables_xattr-com-apple-FinderInfo │ │ ├── README.md │ │ └── variables_xattr-com-apple-FinderInfo.sh └── README.md ├── installer ├── README.md ├── installerCreateUser │ ├── README.md │ └── installerCreateUser └── installerCurrentUserEnvVarTMPDIR │ ├── README.md │ └── installerCurrentUserEnvVarTMPDIR ├── random ├── README.md ├── createWeblocWithCustomIcon │ ├── README.md │ └── createWeblocWithCustomIcon ├── dmgLoopDSCore │ ├── README.md │ └── dmgLoopDSCore ├── dmgLoopServerApp │ ├── README.md │ └── dmgLoopServerApp ├── modifyAuthorizationDB │ ├── README.md │ └── modifyAuthorizationDB ├── modifyNetworkServiceDelete │ ├── README.md │ └── modifyNetworkServiceDelete ├── modifyNetworkServiceEnabled │ ├── README.md │ └── modifyNetworkServiceEnabled ├── modifyNetworkServiceIPv6 │ ├── README.md │ └── modifyNetworkServiceIPv6 ├── modifyNetworkServiceOrder │ ├── README.md │ └── modifyNetworkServiceOrder ├── printDHCPOptions │ ├── README.md │ └── printDHCPOptions ├── printSIPStatus │ ├── README.md │ └── printSIPStatus ├── printUserWithMostLoggedInTime │ ├── README.md │ └── printUserWithMostLoggedInTime ├── reconnectWiFiNetwork │ ├── README.md │ ├── com.github.erikberglund.reconnectWiFiNetwork.plist │ └── reconnectWiFiNetwork └── saveUserPictureToFile │ ├── README.md │ └── saveUserPictureToFile ├── snippets ├── README.md ├── macos_certificates.md ├── macos_diskimages.md ├── macos_finder.md ├── macos_hardware.md ├── macos_netboot.md ├── macos_network.md └── macos_os.md └── tools ├── README.md ├── jekyllServe ├── README.md └── jekyllServe ├── letsEncryptJSS ├── README.md └── letsEncryptJSS ├── modelUTIInfo ├── README.md └── modelUTIInfo.py ├── osxImageModifier ├── README.md ├── osxImageModifier └── osxImageModifierScript.bash ├── osxInstallerArchiver ├── README.md └── osxInstallerArchiver ├── privilegedHelperToolReset ├── README.md └── privilegedHelperToolReset ├── privilegedHelperToolStatus ├── README.md └── privilegedHelperToolStatus ├── resetVMWare └── resetVMWare.bash ├── serverAppArchiver ├── README.md └── serverAppArchiver ├── sharedLibraryDependencyChecker ├── README.md └── sharedLibraryDependencyChecker └── uninstallAST ├── README.md └── uninstallAST /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Scripts 2 | 3 | Scripts and snippets I've written. 4 | 5 | * [functions](https://github.com/erikberglund/Scripts/tree/master/functions) 6 | Functions I use in my scripts. 7 | 8 | * [installer](https://github.com/erikberglund/Scripts/tree/master/installer) 9 | Scripts designed to be run in an OS X installer package. 10 | 11 | * [random](https://github.com/erikberglund/Scripts/tree/master/random) 12 | Scripts that doesn't fit any other category. 13 | 14 | * [snippets](https://github.com/erikberglund/Scripts/tree/master/snippets) 15 | Snippets I use in my scripts. 16 | 17 | * [tools](https://github.com/erikberglund/Scripts/tree/master/tools) 18 | Scripts with a utility like feature to be used as tools. 19 | 20 | 21 | -------------------------------------------------------------------------------- /functions/Bash/README.md: -------------------------------------------------------------------------------- 1 | # Bash Functions 2 | 3 | These are functions I use in my BASH scripts. 4 | 5 | * [Variables](https://github.com/erikberglund/Scripts/tree/master/functions/Bash#variables) 6 | 7 | ## Variables 8 | These functions setup variables to use later in the script. 9 | 10 | * [variables_sgr-escape-sequence](https://github.com/erikberglund/Scripts/tree/master/functions/Bash/variables_sgr-escape-sequence) 11 | * [variables_xattr-com-apple-FinderInfo](https://github.com/erikberglund/Scripts/tree/master/functions/Bash/variables_xattr-com-apple-FinderInfo) -------------------------------------------------------------------------------- /functions/Bash/create_folder/README.md: -------------------------------------------------------------------------------- 1 | # create_folder 2 | 3 | Recursively create all folders passed to function. 4 | Exists script if anything prevented folder creation. 5 | 6 | ## Usage 7 | 8 | ```bash 9 | create_folder "${path_folder_1}" "${path_folder_2}" ... 10 | ``` -------------------------------------------------------------------------------- /functions/Bash/create_folder/create_folder.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Recursively create all folders passed to function. 14 | # Exists script if anything prevented folder creation. 15 | 16 | # Verifications. 17 | # If folder path contains ^/Volumes, check that the mountpath exist before creating any folders recursively 18 | 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | ### 21 | ### USAGE 22 | ### 23 | #////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | # create_folder "${path_folder_1}" "${path_folder_2}" ... 26 | 27 | #////////////////////////////////////////////////////////////////////////////////////////////////// 28 | ### 29 | ### FUNCTIONS 30 | ### 31 | #////////////////////////////////////////////////////////////////////////////////////////////////// 32 | 33 | create_folder() { 34 | # https://github.com/erikberglund/Scripts/blob/master/functions/Bash/create_folder/create_folder.sh 35 | for create_folder_folder in "${@}"; do 36 | 37 | # If folder path contains a mounted volume, check if volume is mounted before creating folder 38 | if [[ ${create_folder_folder} =~ ^/Volumes ]]; then 39 | local create_folder_folder_volume_mountpoint=$( awk -F"/" '{ print "/"$2"/"$3 }' <<< "${create_folder_folder}" ) 40 | if [[ ! -d "${create_folder_folder_volume_mountpoint}" ]]; then 41 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Unable to create folder: ${create_folder_folder}" >&2 42 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Mountpoint referenced in target path does not exist" >&2 43 | exit 1 44 | fi 45 | fi 46 | 47 | # Check if folder exists, else create it 48 | if [[ -d ${create_folder_folder} ]]; then 49 | if [[ -w ${create_folder_folder} ]]; then 50 | printf "%s %s\n" "[${FUNCNAME}]" "Folder exist and current user ($( /usr/bin/id -un )) have write permissions." 51 | else 52 | printf "%s %s\n" "[${FUNCNAME}]" "Folder exist but current user ($( /usr/bin/id -un )) don't have write permissions." 53 | fi 54 | 55 | # Check if folder path exists and is a file, exit with error 56 | elif [[ -f ${create_folder_folder} ]]; then 57 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Unable to create folder: ${create_folder_folder}" >&2 58 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "A file already exist at path" >&2 59 | exit 1 60 | 61 | # If passed all checks and folder doesn't exist, create it 62 | else 63 | create_folder_mkdir_output=$( /bin/mkdir -p "${create_folder_folder/#\~/$HOME}" 2>&1 ) 64 | if (( ${?} == 0 )); then 65 | printf "%s %s\n" "[${FUNCNAME}]" "Folder '${create_folder_folder##*/}' was created successfully." 66 | else 67 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Error creating folder: ${create_folder_folder}" >&2 68 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "$( /usr/bin/awk -F": " '{ print $3 }' <<< "${create_folder_mkdir_output}" )" >&2 69 | exit 1 70 | fi 71 | fi 72 | done 73 | } -------------------------------------------------------------------------------- /functions/Bash/folder_hierachy_from_date/README.md: -------------------------------------------------------------------------------- 1 | # folder_hierachy_from_date 2 | 3 | Outputs a folder hierachy from passed (or current if nothing passed) date. 4 | 5 | * Date format defaults to YYYY-MM-DD 6 | * If passed date is not in the default format, pass a format string for use by the `date` command. 7 | 8 | ## Usage 9 | 10 | ```bash 11 | folder_hierachy_from_date "${date_string}" "${date_format_string}" 12 | ``` 13 | 14 | ## Example: 15 | 16 | ```bash 17 | folder_hierachy_from_date '2016-05-02' 18 | /2016/05/02 19 | ``` 20 | 21 | ```bash 22 | folder_hierachy_from_date '1462176024' '%s' 23 | /2016/05/02 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /functions/Bash/folder_hierachy_from_date/folder_hierachy_from_date.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Outputs a folder hierachy from passed (or current if nothing passed) date. 14 | # Date format defaults to YYYY-MM-DD, if passed date has another format, pass a format string for 'date' to convert passed date. 15 | # 16 | # Example Input: '2016-05-02' 17 | # Expected output: '/2016/05/02' 18 | 19 | # Example Input: '1462176024' '%s' 20 | # Expected output: '/2016/05/02' 21 | 22 | #////////////////////////////////////////////////////////////////////////////////////////////////// 23 | ### 24 | ### USAGE 25 | ### 26 | #////////////////////////////////////////////////////////////////////////////////////////////////// 27 | 28 | # folder_hierachy_from_date "${date_string}" "${date_format_string}" 29 | 30 | #////////////////////////////////////////////////////////////////////////////////////////////////// 31 | ### 32 | ### FUNCTIONS 33 | ### 34 | #////////////////////////////////////////////////////////////////////////////////////////////////// 35 | 36 | folder_hierachy_from_date() { 37 | # https://github.com/erikberglund/Scripts/blob/master/functions/Bash/folder_hierachy_from_date/folder_hierachy_from_date.sh 38 | # Verify input 39 | if [[ -z ${2} ]] && [[ -n ${1} ]] && [[ ${1} =~ "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" ]]; then 40 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Passed date doesn't match the format YYYY-MM-DD, please pass a format string to successfully decode passed date." >&2 41 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Passed date: ${1}" >&2 42 | exit 1 43 | fi 44 | 45 | # Assign hierarchy to variable 46 | local date_output="$( /bin/date -j -f "${2:-%F}" "${1:-$( date +%F )}" "+/%Y/%m/%d" 2>&1 )" 47 | 48 | # Verify date command output 49 | if (( ${?} == 0 )) && [[ ${date_output} =~ ^[/0-9]*$ ]]; then 50 | printf "%s" "${date_output}" 51 | else 52 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "$( sed -n '1p' <<< "${date_output}" )" >&2 53 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "$( sed -n '2p' <<< "${date_output}" )" >&2 54 | exit 1 55 | fi 56 | } -------------------------------------------------------------------------------- /functions/Bash/move_file_ftp/README.md: -------------------------------------------------------------------------------- 1 | # move\_file\_ftp 2 | 3 | Move a file on an ftp server, creating target directory if it doesn't exist 4 | 5 | **Important**: No leading slash in ftp paths! (might add a check/fix later). 6 | 7 | ## Usage 8 | 9 | ```bash 10 | move_file_ftp "${ftp_path_file_1}" "${ftp_path_file_2}" 11 | ``` -------------------------------------------------------------------------------- /functions/Bash/move_file_ftp/move_file_ftp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Move a file on an ftp server, creating target directory if it doesn't exist 14 | 15 | # Important: No leading slash in ftp paths passed to function! 16 | 17 | #////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ### 19 | ### USAGE 20 | ### 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | # move_file_ftp "${ftp_path_file_1}" "${ftp_path_file_2}" 24 | 25 | #////////////////////////////////////////////////////////////////////////////////////////////////// 26 | ### 27 | ### FUNCTIONS 28 | ### 29 | #////////////////////////////////////////////////////////////////////////////////////////////////// 30 | 31 | move_file_ftp() { 32 | # https://github.com/erikberglund/Scripts/blob/master/functions/Bash/move_file_ftp/move_file_ftp.sh 33 | # List current content of target directory (creating it if it doesn't exist) 34 | curl_output=$( curl --list-only --silent --show-error --ftp-create-dirs --user "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}/${2}/" ) 35 | if (( ${?} != 0 )); then 36 | printf "%s\n" "Listing contents of ftp target directory '${2}' failed!" >&2 37 | printf "%s\n" "curl_output=${curl_output}" >&2 38 | exit 1 39 | fi 40 | 41 | # Check if file already exist in target folder 42 | if [[ ${curl_output[@]} =~ ${1##*/} ]]; then 43 | printf "%s\n" "File ${1##*/} already exist in ftp target directory '${2}'" 44 | exit 1 45 | fi 46 | 47 | # Move file from current directory to target directory 48 | curl_output=$( curl --quote "RNFR ${1}" --quote "RNTO ${2}/${1##*/}" --user "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}" ) 49 | if (( ${?} != 0 )); then 50 | printf "%s\n" "Moving file '${1##*/}' to target directory '${2}' failed!" >&2 51 | printf "%s\n" "curl_output=${curl_output}" >&2 52 | exit 1 53 | fi 54 | } -------------------------------------------------------------------------------- /functions/Bash/variables_script/README.md: -------------------------------------------------------------------------------- 1 | # variables_script 2 | 3 | Variables I often use in scripts. -------------------------------------------------------------------------------- /functions/Bash/variables_script/variables_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Recursively create all folders passed to function. 14 | # Exists script if anything prevented folder creation. 15 | 16 | # Verifications. 17 | # If folder path contains ^/Volumes, check that the mountpath exist before creating any folders recursively 18 | 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | ### 21 | ### VARIABLES 22 | ### 23 | #////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | -------------------------------------------------------------------------------- /functions/Bash/variables_sgr-escape-sequence/README.md: -------------------------------------------------------------------------------- 1 | # variables_sgr-escape-sequence 2 | 3 | This function set up variables for the sgr escape sequences to mek it possible to change color and attributes of text printed to the current terminal. 4 | 5 | I have a blog post on how to use this function in a script here: [Script Tip: Modifying text appearance in console output](http://erikberglund.github.io/2016/Script_Tip_Modifying_text_appearance_in_console_output/) 6 | -------------------------------------------------------------------------------- /functions/Bash/variables_sgr-escape-sequence/variables_sgr-escape-sequence.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # In the cases where I dont' know the tput commands, 4 | # I have used hardcoded ANSI/VT100 escape sequences as they 5 | # are recognized on Mac OS X where I write most of my scripts. 6 | 7 | # I have a blog post about how to use these variables in a script here: 8 | # http://erikberglund.github.io/2016/Script_Tip_Modifying_text_appearance_in_console_output/ 9 | 10 | sgr_color() { 11 | # Foreground text colors 12 | blk=$(tput setaf 0) # Black 13 | red=$(tput setaf 1) # Red 14 | grn=$(tput setaf 2) # Green 15 | yel=$(tput setaf 3) # Yellow 16 | blu=$(tput setaf 4) # Blue 17 | mag=$(tput setaf 5) # Magenta 18 | cya=$(tput setaf 6) # Cyan 19 | whi=$(tput setaf 7) # White 20 | def=$'\e[39m' # Default foreground color 21 | 22 | # Deactivate ALL sgr attributes and colors. 23 | clr=$(tput sgr0) 24 | } 25 | 26 | sgr_bgcolor() { 27 | # Background text colors 28 | bgblk=$(tput setab 0) # Black 29 | bgred=$(tput setab 1) # Red 30 | bggrn=$(tput setab 2) # Green 31 | bgyel=$(tput setab 3) # Yellow 32 | bgblu=$(tput setab 4) # Blue 33 | bgmag=$(tput setab 5) # Magenta 34 | bgcya=$(tput setab 6) # Cyan 35 | bgwhi=$(tput setab 7) # White 36 | bgdef=$'\e[49m' # Default foreground color 37 | 38 | # Deactivate ALL sgr attributes and colors. 39 | clr=$(tput sgr0) 40 | } 41 | 42 | sgr_attributes() { 43 | # Activate text attributes 44 | bld=$(tput bold) # Bold 45 | dim=$(tput dim) # Dim 46 | uln=$(tput smul) # Underline 47 | bnk=$(tput blink) # Blink 48 | rev=$(tput rev) # Reverse 49 | sto=$(tput smso) # Standout 50 | 51 | # Deactivate text attributes 52 | nobld=$'\e[22m' # Deactivate Bold 53 | nouln=$(tput rmul) # Deactivate Underline 54 | nobnk=$'\e[25m' # Deactivate Blink 55 | norev=$'\e[27m' # Deactivate Reverse 56 | nosto=$(tput rmso) # Deactivate Standout 57 | 58 | # Deactivate ALL sgr attributes and colors. 59 | clr=$(tput sgr0) 60 | } 61 | -------------------------------------------------------------------------------- /functions/Bash/variables_xattr-com-apple-FinderInfo/README.md: -------------------------------------------------------------------------------- 1 | # variables_xattr-com-apple-FinderInfo 2 | 3 | This function set up variables for the com.apple.FinderInfo extended attributes that corresponds to the label colors available in Finder. 4 | -------------------------------------------------------------------------------- /functions/Bash/variables_xattr-com-apple-FinderInfo/variables_xattr-com-apple-FinderInfo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables for setting the com.apple.FinderInfo extended attributes to items on OS X. 4 | 5 | fi_color() { 6 | # com.apple.FinderInfo attribute label colors 7 | fi_red="0000000000000000000D00000000000000000000000000000000000000000000" # Red 8 | fi_ora="0000000000000000000F00000000000000000000000000000000000000000000" # Orange 9 | fi_yel="0000000000000000000B00000000000000000000000000000000000000000000" # Yellow 10 | fi_grn="0000000000000000000500000000000000000000000000000000000000000000" # Green 11 | fi_blu="0000000000000000000900000000000000000000000000000000000000000000" # Blue 12 | fi_pur="0000000000000000000700000000000000000000000000000000000000000000" # Purple 13 | fi_gra="0000000000000000000300000000000000000000000000000000000000000000" # Gray 14 | 15 | # Clear ALL com.apple.FinderInfo attributes 16 | fi_clr="0000000000000000000000000000000000000000000000000000000000000000" 17 | 18 | # List of available labels 19 | fi_color_available=( "fi_red"\ 20 | "fi_grn"\ 21 | "fi_blu"\ 22 | "fi_gra"\ 23 | "fi_pur"\ 24 | "fi_yel"\ 25 | "fi_ora"\ 26 | "fi_clr" 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /functions/README.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | Functions I use in my scripts. 4 | 5 | * [Bash](https://github.com/erikberglund/Scripts/tree/master/functions/Bash) -------------------------------------------------------------------------------- /installer/README.md: -------------------------------------------------------------------------------- 1 | ## Installer Scripts 2 | 3 | Scripts designed to be run in an OS X installer package. 4 | 5 | * [installerCreateUser](https://github.com/erikberglund/Scripts/tree/master/installer/installerCreateUser) 6 | Create local user account with multiple options. 7 | 8 | * [installerCurrentUserEnvVarTMPDIR](https://github.com/erikberglund/Scripts/tree/master/installer/installerCurrentUserEnvVarTMPDIR) 9 | Get user environment variable(s) that's not passed when run by installer. 10 | -------------------------------------------------------------------------------- /installer/installerCreateUser/README.md: -------------------------------------------------------------------------------- 1 | ## installerCreateUser 2 | 3 | Create local user account with multiple options. 4 | -------------------------------------------------------------------------------- /installer/installerCurrentUserEnvVarTMPDIR/README.md: -------------------------------------------------------------------------------- 1 | ## installerCurrentUserEnvVarTMPDIR 2 | 3 | Get user environment variable(s) that aren't passed when run in installer. 4 | -------------------------------------------------------------------------------- /installer/installerCurrentUserEnvVarTMPDIR/installerCurrentUserEnvVarTMPDIR: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.1 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script is designed to be run from an installer package as a preinstall or a postinstall script. 14 | # It will get the value of the current users's variable TMPDIR that is not passed in the env to the script. 15 | 16 | #////////////////////////////////////////////////////////////////////////////////////////////////// 17 | ### 18 | ### AUTOMATIC VARIABLES 19 | ### 20 | #////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | # Set up all variables passed by installer 23 | # More info here on page 50: https://developer.apple.com/legacy/library/documentation/DeveloperTools/Conceptual/SoftwareDistribution4/SoftwareDistribution4.pdf 24 | installerPackagePath="${1}" # Full path to the installation package the Installer application is processing. 25 | destinationPath="${2}" # Full path to the installation destination. Example: /Applications 26 | targetVolumePath="${3}" # Installation volume (or mountpoint) to receive the payload 27 | rootPath="${4}" # The root directory for the system. Example: / 28 | 29 | #////////////////////////////////////////////////////////////////////////////////////////////////// 30 | ### 31 | ### MAIN SCRIPT 32 | ### 33 | #////////////////////////////////////////////////////////////////////////////////////////////////// 34 | 35 | # UPDATE! 36 | # Thanks to user @dre in the macadmins.slack.com #bash-channel for showing me a much simpler way of getting variables not passed as environment. 37 | path_tmpDir=$( getconf DARWIN_USER_TEMP_DIR ) 38 | printf "%s\n" "TMPDIR=${path_tmpDir}" 39 | 40 | # My long way to solve the problem, don't use this. 41 | # List all processes for ${USER}, use regex to find Installer and set installerPID to it's PID (last match). 42 | #installerPID=$( ps -u${USER} -c -o user,pid,command | sed -nE 's/^'"${USER}"'.* ([0-9]+) Installer$/\1/p' | tail -1 ) 43 | #if [[ -n ${installerPID} ]]; then 44 | 45 | # Print environment variables for process with pid ${installerPID} and catch the value of variable TMPDIR. 46 | # This could easily be expanded or changed to get any other environment variable. 47 | # path_tmpDir=$( /bin/ps -p ${installerPID} -wwwE | /usr/bin/sed -nE 's/.*TMPDIR=(.*\/) .*=.*/\1/p' ) 48 | # printf "%s\n" "TMPDIR=${path_tmpDir}" 49 | #else 50 | # printf "%s\n" "[ERROR] Unable to get Installer PID!" 51 | # exit 1 52 | #fi 53 | 54 | exit 0 55 | -------------------------------------------------------------------------------- /random/README.md: -------------------------------------------------------------------------------- 1 | ## Random Scripts 2 | Scripts that doesn't fit any other category. 3 | 4 | * [createWeblocWithCustomIcon](https://github.com/erikberglund/Scripts/blob/master/random/createWeblocWithCustomIcon) 5 | Create a .webloc item on disk pointing at an URL, with option to use custom icon. 6 | 7 | * [dmgLoopDSCore](https://github.com/erikberglund/Scripts/blob/master/random/dmgLoopDSCore) 8 | Loops through DeployStudio installation dmgs, extract DSCore binary and does a binary grep for passed string. 9 | 10 | * [dmgLoopServerApp](https://github.com/erikberglund/Scripts/blob/master/random/dmgLoopServerApp) 11 | Loops through dmgs containing Server.app and extracting item at passed path. 12 | 13 | * [modifyAuthorizationDB](https://github.com/erikberglund/Scripts/tree/master/random/modifyAuthorizationDB) 14 | Reads, Modifies and Updates a rule in the authorization database 15 | 16 | * [modifyNetworkServiceDelete](https://github.com/erikberglund/Scripts/blob/master/random/modifyNetworkServiceDelete) 17 | Delete all network services whose name matches regex. 18 | 19 | * [modifyNetworkServiceEnabled](https://github.com/erikberglund/Scripts/blob/master/random/modifyNetworkServiceEnabled) 20 | Disable all network services except those whose name matches regex. 21 | 22 | * [modifyNetworkServiceOrder](https://github.com/erikberglund/Scripts/blob/master/random/modifyNetworkServiceOrder) 23 | Update network service order with prioritized services first and de-prioritized last. 24 | 25 | * [modifyNetworkServiceIPv6](https://github.com/erikberglund/Scripts/blob/master/random/modifyNetworkServiceIPv6) 26 | Disable IPv6 for all network services. 27 | 28 | * [printDHCPOptions](https://github.com/erikberglund/Scripts/blob/master/random/printDHCPOptions) 29 | Print all DHCP-options for active or selected interface. Optionally print the option code name. 30 | 31 | * [printSIPStatus](https://github.com/erikberglund/Scripts/blob/master/random/printSIPStatus) 32 | Print the current SIP status of the running system. 33 | 34 | * [reconnectWiFiNetwork](https://github.com/erikberglund/Scripts/blob/master/random/reconnectWiFiNetwork) 35 | Reconnect to configured SSID (if in range) if: Disonnected, Another SSID selected, Wi-Fi card powered off. 36 | 37 | * [saveUserPictureToFile](https://github.com/erikberglund/Scripts/blob/master/random/saveUserPictureToFile) 38 | Save a OS X user's account picture to a file. 39 | -------------------------------------------------------------------------------- /random/createWeblocWithCustomIcon/README.md: -------------------------------------------------------------------------------- 1 | ## createWeblocWithCustomIcon 2 | 3 | -------------------------------------------------------------------------------- /random/createWeblocWithCustomIcon/createWeblocWithCustomIcon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This creates a clickable file that opens the selected URL in the user's default browser 14 | # Optionally you may also choose a custom .icns-file to use as file icon 15 | 16 | #////////////////////////////////////////////////////////////////////////////////////////////////// 17 | ### 18 | ### VARIABLES 19 | ### 20 | #////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | ## URL for the webloc 23 | webloc_url="https://google.com" 24 | 25 | ## File name for the webloc (This is the name without a file extension i.e. don't add .webloc to the name) 26 | webloc_name="Google" 27 | 28 | ## Folder where the webloc should be created 29 | webloc_folder_path="/Users/erikberglund/Desktop" 30 | 31 | ## Custom icon to use for the webloc 32 | webloc_icon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ProfileBackgroundColor.icns" 33 | 34 | #////////////////////////////////////////////////////////////////////////////////////////////////// 35 | ### 36 | ### MAIN SCRIPT 37 | ### 38 | #////////////////////////////////////////////////////////////////////////////////////////////////// 39 | 40 | ## Create webloc path from script variables 41 | webloc_path="${webloc_folder_path}/${webloc_name}.webloc" 42 | 43 | ## Create the webloc 44 | /usr/libexec/PlistBuddy -c "Add :URL string ${webloc_url}" "${webloc_path}" > /dev/null 2>&1 45 | 46 | if [[ -n ${webloc_icon} ]]; then 47 | 48 | ## Set icns as icon for the webloc 49 | python - "${webloc_icon}" "${webloc_path}"<< END 50 | import Cocoa 51 | import sys 52 | Cocoa.NSWorkspace.sharedWorkspace().setIcon_forFile_options_(Cocoa.NSImage.alloc().initWithContentsOfFile_(sys.argv[1].decode('utf-8')), sys.argv[2].decode('utf-8'), 0) or sys.exit("Unable to set file icon") 53 | END 54 | fi 55 | 56 | ## Hide .webloc file extension and tell file it's using a custom icon 57 | ## NOTE: SetFile is only available on systems with developer tools installed, should add a check for that if wanting to hide the file extension 58 | # /usr/bin/SetFile -a CE "${webloc_path}" 59 | 60 | exit 0 61 | -------------------------------------------------------------------------------- /random/dmgLoopDSCore/README.md: -------------------------------------------------------------------------------- 1 | ## dmgLoopDSCore 2 | 3 | -------------------------------------------------------------------------------- /random/dmgLoopDSCore/dmgLoopDSCore: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Loops through all .dmg files (expects DeployStudio installation dmg) in passed path or working directory. 14 | # Extract DSCore binary and does a binary grep to see if it contains a string. 15 | 16 | #////////////////////////////////////////////////////////////////////////////////////////////////// 17 | ### 18 | ### USAGE 19 | ### 20 | #////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | # Usage: ./dmgLoopDSCore [options] ... 23 | # 24 | # Options: 25 | # -i (Optional) Input directory to search for .dmg files 26 | # -q Query string 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### FUNCIONS 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | create_temporary_directories() { 35 | mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create mountpoint" 36 | extraction_dir=$( mktemp -d /private/tmp/pax.XXXXX ) || error "Unable to create extraction_dir" 37 | } 38 | 39 | remove_temporary_directories() { 40 | 41 | # If anything is attached to the mountpoint, try to detach it first. 42 | if diskutil info "${mountpoint}" >/dev/null 2>&1; then 43 | detach_image 44 | fi 45 | 46 | for dir in "${mountpoint}" "${extraction_dir}"; do 47 | 48 | # Remove temporary mountpoint if: 49 | # * The variable contains an expected path 50 | # * The path exists and is a directory 51 | if [[ ${dir} =~ ^/private/tmp/(dmg|pax).[a-zA-Z0-9]{5}$ ]] && [[ -d ${dir} ]]; then 52 | rm -rf "${dir}" 53 | fi 54 | done 55 | } 56 | 57 | usage() { 58 | printf "%s\n" "Usage: ./${0##*/} [options] ..." 59 | printf "%s\n" "Options:" 60 | printf " %s\t%s\n" "-i" "(Optional) Input directory" 61 | printf " %s\t%s\n" "-q" "Query string" 62 | printf "\n" 63 | } 64 | 65 | error() { 66 | printf "%s\n" "${1}, exiting script..." >&2; exit 1 67 | } 68 | 69 | parse_opts() { 70 | while getopts "p:" opt; do 71 | case ${opt} in 72 | i) input_directory="${OPTARG}" ;; 73 | q) query_string="${OPTARG}" ;; 74 | \?) usage; exit 1 ;; 75 | :) usage; exit 1 ;; 76 | esac 77 | done 78 | 79 | if [[ -n ${input_directory} ]] && ! [[ -d ${input_directory} ]]; then 80 | error "${input_directory} is not a directory" 81 | fi 82 | 83 | if [[ -z ${query_string} ]]; then 84 | usage; exit 1 ;; 85 | fi 86 | } 87 | 88 | parse_image() { 89 | 90 | # Image is attached and mounted at ${mountpoint} when this function is called. 91 | 92 | # Get version from the mpkg name, not the best way but seems to be consistent. 93 | ds_version=$( echo "${mountpoint}"/DeployStudio*.mpkg | sed -nE 's/.*_v?(.*)\.mpkg.*/\1/p' ) 94 | 95 | # Another weak check, but better to exit here than to try extraction as it probably will fail if the version couldn't be found. 96 | if [[ -z ${ds_version} ]]; then 97 | printf "%s\n" "Found no DeployStudio version number, probably not a DeployStudio dmg, ignoring..." 98 | return 0 99 | fi 100 | 101 | # Extract DSCore.framework binary to extraction_dir. 102 | if (cd ${extraction_dir} && gunzip -c "${mountpoint}"/DeployStudio*.mpkg/Contents/Packages/deploystudioAdmin.pkg/Contents/Archive.pax.gz | pax -r -s ":./DeployStudio Admin.app/Contents/Frameworks/DSCore.framework/Versions/A:${extraction_dir}:" "./DeployStudio Admin.app/Contents/Frameworks/DSCore.framework/Versions/A/DSCore"); then 103 | if grep -q "${query_string}" "${extraction_dir}/DSCore"; then 104 | printf "%s\n" "DeployStudio version: ${ds_version} - FOUND" 105 | else 106 | printf "%s\n" "DeployStudio version: ${ds_version} - NOT FOUND" 107 | fi 108 | else 109 | error "Extracting DSCore failed" 110 | fi 111 | 112 | # Remove the extracted DSCore binary to clean up before next iteration. 113 | if ! rm "${extraction_dir}/DSCore"; then 114 | error "Removing DSCore failed" 115 | fi 116 | } 117 | 118 | detach_image() { 119 | hdiutil detach "${mountpoint}" -force -quiet || error "Detach image failed" 120 | } 121 | 122 | #////////////////////////////////////////////////////////////////////////////////////////////////// 123 | ### 124 | ### MAIN SCRIPT 125 | ### 126 | #////////////////////////////////////////////////////////////////////////////////////////////////// 127 | 128 | # Parse passed arguments. 129 | parse_opts "${@}" 130 | 131 | # Create temporary directories. 132 | create_temporary_directories 133 | 134 | # Setup trap to remove temporary direcotries on script exit. 135 | trap remove_temporary_directories INT EXIT 136 | 137 | # Stop globbing from printing itself if there are no matches. 138 | shopt -s nullglob 139 | 140 | # Loop through all .dmg-files found in passed directory (or current working directory if no directory was passed). 141 | for dmg in "${input_directory:-${PWD}}"/*\.dmg; do 142 | 143 | # If anything is attached to the mountpoint, try to detach it first. 144 | if diskutil info "${mountpoint}" >/dev/null 2>&1; then 145 | detach_image 146 | fi 147 | 148 | # If current dmg is already mounted, exit script and print mountpoint. 149 | dmg_mountpath=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='image-path']/following-sibling::string[1][contains(., \"${dmg}\")]/../key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string/text()" 2>/dev/null ) 150 | if [[ -n ${dmg_mountpath} ]]; then 151 | error "Image already mounted at: ${dmg_mountpath}" 152 | fi 153 | 154 | # Attach current dmg at mountpoint 155 | if hdiutil attach "${dmg}" -noverify -nobrowse -readonly -owners on -mountpoint "${mountpoint}" -quiet; then 156 | parse_image 157 | detach_image 158 | else 159 | error "Attach image failed" 160 | fi 161 | done 162 | 163 | # Restore globbing behaviour. 164 | shopt -u nullglob 165 | 166 | exit 0 167 | -------------------------------------------------------------------------------- /random/dmgLoopServerApp/README.md: -------------------------------------------------------------------------------- 1 | ## dmgLoopServerApp 2 | 3 | -------------------------------------------------------------------------------- /random/dmgLoopServerApp/dmgLoopServerApp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Loops through all .dmg files (expects Server.app at the root of the dmg) in passed path or working directory. 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### USAGE 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Usage: ./dmgLoopServerApp [options] ... 22 | # 23 | # Options: 24 | # -e Path rooted at /Server.app/Contents/ to file or folder to extract from Server.app 25 | # -i (Optional) Input directory to search for .dmg files 26 | # -o Output directory for extracted files 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### FUNCIONS 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | create_temporary_directories() { 35 | mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create mountpoint" 36 | } 37 | 38 | remove_temporary_directories() { 39 | 40 | # If anything is attached to the mountpoint, try to detach it first. 41 | if diskutil info "${mountpoint}" >/dev/null 2>&1; then 42 | detach_image 43 | fi 44 | 45 | for dir in "${mountpoint}"; do 46 | 47 | # Remove temporary mountpoint if: 48 | # * The variable contains an expected path 49 | # * The path exists and is a directory 50 | if [[ ${dir} =~ ^/private/tmp/(dmg|cp).[a-zA-Z0-9]{5}$ ]] && [[ -d ${dir} ]]; then 51 | rm -rf "${dir}" 52 | fi 53 | done 54 | } 55 | 56 | create_folder() { 57 | # https://github.com/erikberglund/Scripts/blob/master/functions/Bash/create_folder/create_folder.sh 58 | for create_folder_folder in "${@}"; do 59 | 60 | # If folder path contains a mounted volume, check if volume is mounted before creating folder 61 | if [[ ${create_folder_folder} =~ ^/Volumes ]]; then 62 | local create_folder_folder_volume_mountpoint=$( awk -F"/" '{ print "/"$2"/"$3 }' <<< "${create_folder_folder}" ) 63 | if [[ ! -d "${create_folder_folder_volume_mountpoint}" ]]; then 64 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Unable to create folder: ${create_folder_folder}" >&2 65 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Mountpoint referenced in target path does not exist" >&2 66 | exit 1 67 | fi 68 | fi 69 | 70 | # Check if folder exists, else create it 71 | if [[ -d ${create_folder_folder} ]]; then 72 | if [[ -w ${create_folder_folder} ]]; then 73 | printf "%s %s\n" "[${FUNCNAME}]" "Folder exist and current user ($( /usr/bin/id -un )) have write permissions." 74 | else 75 | printf "%s %s\n" "[${FUNCNAME}]" "Folder exist but current user ($( /usr/bin/id -un )) don't have write permissions." 76 | fi 77 | 78 | # Check if folder path exists and is a file, exit with error 79 | elif [[ -f ${create_folder_folder} ]]; then 80 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Unable to create folder: ${create_folder_folder}" >&2 81 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "A file already exist at path" >&2 82 | exit 1 83 | 84 | # If passed all checks and folder doesn't exist, create it 85 | else 86 | create_folder_mkdir_output=$( /bin/mkdir -p "${create_folder_folder/#\~/$HOME}" 2>&1 ) 87 | if (( ${?} == 0 )); then 88 | printf "%s %s\n" "[${FUNCNAME}]" "Folder '${create_folder_folder##*/}' was created successfully." 89 | else 90 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "Error creating folder: ${create_folder_folder}" >&2 91 | printf "%s %s\n" "[$( basename ${BASH_SOURCE[0]}):${FUNCNAME}:${LINENO}]" "$( /usr/bin/awk -F": " '{ print $3 }' <<< "${create_folder_mkdir_output}" )" >&2 92 | exit 1 93 | fi 94 | fi 95 | done 96 | } 97 | 98 | usage() { 99 | printf "%s\n" "Usage: ./${0##*/} [options] ..." 100 | printf "%s\n" "Options:" 101 | printf " %s\t%s\n" "-e" "Path rooted at \"/Server.app/Contents/\" to file or folder to extract from Server.app" 102 | printf " %s\t%s\n" "-i" "(Optional) Input directory" 103 | printf " %s\t%s\n" "-o" "Output directory" 104 | printf "\n" 105 | } 106 | 107 | error() { 108 | printf "%s\n" "${1}, exiting script..." >&2; exit 1 109 | } 110 | 111 | parse_opts() { 112 | while getopts "e:i:o:" opt; do 113 | case ${opt} in 114 | e) extraction_path="${OPTARG%/}" ;; 115 | i) input_directory="${OPTARG%/}" ;; 116 | o) output_directory="${OPTARG%/}" ;; 117 | \?) usage; exit 1 ;; 118 | :) usage; exit 1 ;; 119 | esac 120 | done 121 | 122 | if [[ -n ${input_directory} ]] && ! [[ -d ${input_directory} ]]; then 123 | error "${input_directory} is not a directory" 124 | fi 125 | 126 | if [[ -z ${extraction_path} ]]; then 127 | usage; exit 1 128 | fi 129 | 130 | if [[ -z ${output_directory} ]]; then 131 | usage; exit 1 132 | elif ! [[ -d ${output_directory} ]]; then 133 | create_folder "${output_directory}" 134 | fi 135 | } 136 | 137 | parse_image() { 138 | 139 | # Image is attached and mounted at ${mountpoint} when this function is called. 140 | 141 | # Get version from the Server.app Info.plist 142 | server_version=$( /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${mountpoint}/Server.app/Contents/Info.plist" 2>&1 ) 143 | if [[ -z ${server_version} ]] || [[ ${server_version} =~ "Does Not Exist" ]]; then 144 | printf "%s\n" "Found no Server.app version number, probably not a Server.app dmg, ignoring..."; return 0 145 | fi 146 | 147 | printf "%s\n" "Server Version: ${server_version}" 148 | 149 | if ! [[ -e ${mountpoint}/Server.app/Contents/${extraction_path} ]]; then 150 | printf "${mountpoint}/Server.app/Contents/${extraction_path}: No such file or folder"; return 0 151 | fi 152 | 153 | current_output_folder="${output_directory}/${server_version}" 154 | 155 | if ! [[ -d ${current_output_folder} ]]; then 156 | create_folder "${current_output_folder}" 157 | fi 158 | 159 | printf "%s\n" "Extracting ${extraction_path##*/}..." 160 | 161 | if ! cp -r "${mountpoint}/Server.app/Contents/${extraction_path}" "${current_output_folder}"; then 162 | error "Extraction failed!" 163 | fi 164 | 165 | printf "%s\n" "Extraction complete" 166 | } 167 | 168 | detach_image() { 169 | hdiutil detach "${mountpoint}" -force -quiet || error "Detach image failed" 170 | } 171 | 172 | #////////////////////////////////////////////////////////////////////////////////////////////////// 173 | ### 174 | ### MAIN SCRIPT 175 | ### 176 | #////////////////////////////////////////////////////////////////////////////////////////////////// 177 | 178 | # Parse passed arguments. 179 | parse_opts "${@}" 180 | 181 | # Create temporary directories. 182 | create_temporary_directories 183 | 184 | # Setup trap to remove temporary direcotries on script exit. 185 | trap remove_temporary_directories INT EXIT 186 | 187 | # Stop globbing from printing itself if there are no matches. 188 | shopt -s nullglob 189 | 190 | # Loop through all .dmg-files found in passed directory (or current working directory if no directory was passed). 191 | for dmg in "${input_directory:-${PWD}}"/*\.dmg; do 192 | 193 | # If anything is attached to the mountpoint, try to detach it first. 194 | if diskutil info "${mountpoint}" >/dev/null 2>&1; then 195 | detach_image 196 | fi 197 | 198 | # If current dmg is already mounted, exit script and print mountpoint. 199 | dmg_mountpath=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='image-path']/following-sibling::string[1][contains(., \"${dmg}\")]/../key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string/text()" 2>/dev/null ) 200 | if [[ -n ${dmg_mountpath} ]]; then 201 | error "Image already mounted at: ${dmg_mountpath}" 202 | fi 203 | 204 | # Attach current dmg at mountpoint 205 | if hdiutil attach "${dmg}" -noverify -nobrowse -readonly -owners on -mountpoint "${mountpoint}" -quiet; then 206 | parse_image 207 | detach_image 208 | else 209 | error "Attach image failed" 210 | fi 211 | done 212 | 213 | # Restore globbing behaviour. 214 | shopt -u nullglob 215 | 216 | exit 0 217 | -------------------------------------------------------------------------------- /random/modifyAuthorizationDB/README.md: -------------------------------------------------------------------------------- 1 | ## modifyAuthorizationDB 2 | 3 | -------------------------------------------------------------------------------- /random/modifyAuthorizationDB/modifyAuthorizationDB: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script will: 14 | # 1. Print the system.login.console authorization db rule to a temporary file, 15 | # 2. Iterate over the items in the 'mechanisms' array and removes any item defined in the script. 16 | # 3. Update the authorization db rule with the modified plist 17 | 18 | # This is for a discussion on macadmins.slack.com where @owen.pragel asked for methods to modify the authorization db 19 | 20 | #////////////////////////////////////////////////////////////////////////////////////////////////// 21 | ### 22 | ### VARIABLES 23 | ### 24 | #////////////////////////////////////////////////////////////////////////////////////////////////// 25 | 26 | # Path for temporary rule plist 27 | authdb_rule_plist="/tmp/authdb_rule.plist" 28 | 29 | #////////////////////////////////////////////////////////////////////////////////////////////////// 30 | ### 31 | ### MAIN SCRIPT 32 | ### 33 | #////////////////////////////////////////////////////////////////////////////////////////////////// 34 | 35 | # Print the 'system.login.console' rule to a temporary file 36 | security authorizationdb read system.login.console 2> /dev/null > "${authdb_rule_plist}" 37 | 38 | counter=0 39 | 40 | # Loop through all items in the 'mechanisms' array 41 | while read mechanism; do 42 | 43 | # If mechanism contains 'TeamViewerAuthPlugin', remove it from temporary file 44 | if [[ ${mechanism} =~ "TeamViewerAuthPlugin" ]]; then 45 | /usr/libexec/PlistBuddy -c "Delete mechanisms:${counter}" "${authdb_rule_plist}" 46 | else 47 | ((counter++)) 48 | fi 49 | done < <( /usr/libexec/PlistBuddy -c "Print mechanisms" "${authdb_rule_plist}" | sed '1d; $d' ) 50 | 51 | # Write the updated 'system.login.consol' rule back in the authorization db 52 | security authorizationdb write system.login.console < "${authdb_rule_plist}" 53 | 54 | exit 0 55 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceDelete/README.md: -------------------------------------------------------------------------------- 1 | ## modifyNetworkServiceDelete 2 | 3 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceDelete/modifyNetworkServiceDelete: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script loops through all network services in the configuration file and removes any whose name matches the regex provided. 14 | 15 | # This is for a discussion on macadmins.slack.com where @lukeisslacking wanted help with a similar script. 16 | 17 | #////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ### 19 | ### VARIABLES 20 | ### 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | # Path to network service preferences 24 | path_systemConfigurationPreferences="/Library/Preferences/SystemConfiguration/preferences.plist" 25 | 26 | # Regex for all network service names to remove 27 | network_services_delete_regex="" 28 | 29 | #////////////////////////////////////////////////////////////////////////////////////////////////// 30 | ### 31 | ### MAIN SCRIPT 32 | ### 33 | #////////////////////////////////////////////////////////////////////////////////////////////////// 34 | 35 | # Require root 36 | if (( ${EUID} != 0 )); then 37 | printf "%s\n" "This script must be run as root" 1>&2 38 | exit 1 39 | fi 40 | 41 | # Create backup of the preference file 42 | if [[ -f ${path_systemConfigurationPreferences} ]]; then 43 | /bin/cp -f "${path_systemConfigurationPreferences}"{,.bak} 44 | else 45 | printf "%s\n" "${path_systemConfigurationPreferences}: File does not exist" 1>&2 46 | exit 1 47 | fi 48 | 49 | # Loop through all active network services and remove any that doesn't match ${network_services_delete_regex}. 50 | while read networkServicesDict; do 51 | while read networkService; do 52 | networkServiceName=$( /usr/libexec/PlistBuddy -c "Print :$( sed -E 's/[ :]/\\&/g' <<< ${networkServicesDict} ):${networkService}:UserDefinedName" "${path_systemConfigurationPreferences}" 2>&1 ) 53 | printf "%s\n" "Checking network service name: ${networkServiceName}" 54 | if [[ ${networkServiceName} =~ "Does Not Exist" ]]; then 55 | /usr/libexec/PlistBuddy -c "Print" "${path_systemConfigurationPreferences}" 56 | elif [[ ${networkServiceName} =~ ${network_services_delete_regex} ]]; then 57 | printf "%s\n" "Deleting: NetworkServices:${networkService}" 58 | /usr/libexec/PlistBuddy -c "Delete :$( sed -E 's/[ :]/\\&/g' <<< ${networkServicesDict} ):${networkService}" "${path_systemConfigurationPreferences}" 59 | /usr/libexec/PlistBuddy -c Save "${path_systemConfigurationPreferences}" 60 | fi 61 | done < <( /usr/bin/xpath "${path_systemConfigurationPreferences}" "/plist/dict/key[.='${networkServicesDict}']/following-sibling::*[1]/key" 2>/dev/null | sed -E -e 's/<\/key>/\'$'\n/g' -e 's/(|<\/key>)//g' ) 62 | done < <( /usr/bin/xpath "${path_systemConfigurationPreferences}" "/plist/dict/key[contains(text(), 'NetworkServices')]" 2>/dev/null | sed -E -e 's/<\/key>/\'$'\n/g' -e 's/(|<\/key>)//g' ) 63 | 64 | exit 0 -------------------------------------------------------------------------------- /random/modifyNetworkServiceEnabled/README.md: -------------------------------------------------------------------------------- 1 | ## modifyNetworkServiceEnabled 2 | 3 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceEnabled/modifyNetworkServiceEnabled: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script loops through all current network services and disabled any whose name doesn't match 14 | # the regex provided 15 | 16 | # This is for a discussion on macadmins.slack.com where @qomsiya wanted to disable all network 17 | # interfaces except Wi-Fi 18 | 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | ### 21 | ### VARIABLES 22 | ### 23 | #////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | # Regex for all network service names to keep enabled 26 | network_services_enabled_regex=".*Wi-Fi.*" 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### MAIN SCRIPT 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | # Loop through all active network services and disable any that doesn't match ${network_services_enabled_regex}. 35 | while read networkService; do 36 | if ! [[ ${networkService} =~ ${network_services_enabled_regex} ]]; then 37 | networksetup -setnetworkserviceenabled "${networkService}" off 38 | fi 39 | done < <( networksetup -listnetworkserviceorder | awk '/^\([0-9]/{$1 ="";gsub("^ ","");print}' ) 40 | 41 | exit 0 42 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceIPv6/README.md: -------------------------------------------------------------------------------- 1 | ## modifyNetworkServiceIPv6 2 | 3 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceIPv6/modifyNetworkServiceIPv6: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script loops through all current network services and disabled IPv6. 14 | 15 | # This is for a discussion on macadmins.slack.com where @dirtydan asked how to do this 16 | 17 | #////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ### 19 | ### MAIN SCRIPT 20 | ### 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | # Loop through all active network services and disable IPv6. 24 | while read networkService; do 25 | networksetup -setv6off "${networkService}" 26 | done < <( networksetup -listnetworkserviceorder | awk '/^\([0-9]/{$1 ="";gsub("^ ","");print}' ) 27 | 28 | exit 0 29 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceOrder/README.md: -------------------------------------------------------------------------------- 1 | ## modifyNetworkServiceOrder 2 | 3 | -------------------------------------------------------------------------------- /random/modifyNetworkServiceOrder/modifyNetworkServiceOrder: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script loops through all current network services. 14 | # It creates a new list with the prioritized services at the top. 15 | # Then it updates the network service order with the new list. 16 | 17 | # This is a combination of an old script I had laying around, and a discussion on macadmins.slack.com 18 | # Where @bskillets asked about using awk to create a correct service list and @pmbuko provided the awk regex. 19 | # User @elvisizer also added a deprioritizedServices array to move services to the end of the service order. 20 | 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | ### 23 | ### MAIN SCRIPT 24 | ### 25 | #////////////////////////////////////////////////////////////////////////////////////////////////// 26 | 27 | # Loop through all network services and separate prioritized services from other services. 28 | while read networkService; do 29 | if [[ ${networkService} =~ .*Ethernet.* ]] || [[ ${networkService} =~ .*Thunderbolt.* ]]; then 30 | prioritizedServices+=( "${networkService}" ) 31 | elif [[ ${networkService} =~ .*Bluetooth.* ]] || [[ ${networkService} =~ .*FireWire.* ]]; then 32 | deprioritizedServices+=( "${networkService}" ) 33 | else 34 | otherServices+=( "${networkService}" ) 35 | fi 36 | done < <( networksetup -listnetworkserviceorder | awk '/^\([0-9]/{$1 ="";gsub("^ ","");print}' ) 37 | 38 | # Update network service order with prioritized services at the top. 39 | networksetup -ordernetworkservices "${prioritizedServices[@]}" "${otherServices[@]}" "${deprioritizedServices[@]}" 40 | 41 | exit 0 42 | -------------------------------------------------------------------------------- /random/printDHCPOptions/README.md: -------------------------------------------------------------------------------- 1 | ## printDHCPOptions 2 | 3 | -------------------------------------------------------------------------------- /random/printDHCPOptions/printDHCPOptions: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Prints all current dhcp-options for selected interface 14 | 15 | # Example Output: 16 | # Option 1: 255.255.255.0 17 | # Option 3: 172.16.98.1 18 | # Option 6: 172.16.98.1 19 | # Option 15: bredbandsbolaget.se 20 | # ... 21 | 22 | # Example Output with -n 23 | # Option 1 (subnet_mask): 255.255.255.0 24 | # Option 3 (router): 172.16.98.1 25 | # Option 6 (domain_name_server): 172.16.98.1 26 | # Option 15 (domain_name): bredbandsbolaget.se 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### USAGE 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | # Usage: ./printDHCPOptions.bash [options] ... 35 | # 36 | # Options: 37 | # -i (Optional) Interface Name (en0, en1...) 38 | # -n (Optional) Print option code names 39 | 40 | #////////////////////////////////////////////////////////////////////////////////////////////////// 41 | ### 42 | ### FUNCTIONS 43 | ### 44 | #////////////////////////////////////////////////////////////////////////////////////////////////// 45 | 46 | print_usage() { 47 | printf "\n%s\n\n" "Usage: ./${0##*/} [options] ..." 48 | printf "%s\n" "Options:" 49 | printf " %s\t%s\n" "-i" "(Optional) Interface Name (en0, en1...)" 50 | printf " %s\t%s\n" "-n" "(Optional) Print option code names" 51 | printf "\n" 52 | } 53 | 54 | parse_command_line_options() { 55 | while getopts "i:n" opt; do 56 | case ${opt} in 57 | i) interface="${OPTARG}";; 58 | n) names="true";; 59 | \?) print_usage; exit 1 ;; 60 | :) print_usage; exit 1 ;; 61 | esac 62 | done 63 | } 64 | 65 | name_for_option() { 66 | # DHCP options from https://opensource.apple.com/source/xnu/xnu-3248.20.55/bsd/netinet/dhcp_options.h 67 | case $1 in 68 | 0) name="pad" ;; 69 | 1) name="subnet_mask" ;; 70 | 2) name="time_offset" ;; 71 | 3) name="router" ;; 72 | 4) name="time_server" ;; 73 | 5) name="name_server" ;; 74 | 6) name="domain_name_server" ;; 75 | 7) name="log_server" ;; 76 | 8) name="cookie_server" ;; 77 | 9) name="lpr_server" ;; 78 | 10) name="impress_server" ;; 79 | 11) name="resource_location_server" ;; 80 | 12) name="host_name" ;; 81 | 13) name="boot_file_size" ;; 82 | 14) name="merit_dump_file" ;; 83 | 15) name="domain_name" ;; 84 | 16) name="swap_server" ;; 85 | 17) name="root_path" ;; 86 | 18) name="extensions_path" ;; 87 | 19) name="ip_forwarding" ;; 88 | 20) name="non_local_source_routing" ;; 89 | 21) name="policy_filter" ;; 90 | 22) name="max_dgram_reassembly_size" ;; 91 | 23) name="default_ip_time_to_live" ;; 92 | 24) name="path_mtu_aging_timeout" ;; 93 | 25) name="path_mtu_plateau_table" ;; 94 | 95 | # Unfinished list 96 | 97 | *) name="-" ;; 98 | esac 99 | printf "%s" "${name}" 100 | } 101 | 102 | #////////////////////////////////////////////////////////////////////////////////////////////////// 103 | ### 104 | ### MAIN SCRIPT 105 | ### 106 | #////////////////////////////////////////////////////////////////////////////////////////////////// 107 | 108 | # Parse all passed command line options 109 | parse_command_line_options "${@}" 110 | 111 | for ((i=0; i<256; i++)); do 112 | option_output=$( ipconfig getoption "${interface}" ${i} ) 113 | if [[ -n ${option_output} ]]; then 114 | if [[ ${names} == true ]]; then 115 | option_name="${i} ($( name_for_option ${i} ))" 116 | fi 117 | printf "%s\n" "Option ${option_name:-${i}}: ${option_output}" 118 | fi 119 | done 120 | 121 | exit 0 122 | -------------------------------------------------------------------------------- /random/printSIPStatus/README.md: -------------------------------------------------------------------------------- 1 | ## printSIPStatus 2 | 3 | Print the current SIP status of the running system. 4 | 5 | Reimplementation of [this](https://github.com/rtrouton/rtrouton_scripts/blob/master/rtrouton_scripts/check_system_integrity_protection_status/check_system_integrity_protection_status.sh) script by @rtrouton for a discussion on using temporary files when processing command output. 6 | 7 | ### Example 8 | 9 | ```console 10 | ./printSIPStatus 11 | System Integrity Protection status: Active 12 | Apple Internal: disabled 13 | DTrace Restrictions: disabled 14 | ``` -------------------------------------------------------------------------------- /random/printSIPStatus/printSIPStatus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This is from a discussion on macadmins.slack.com where @allister asked about creating tempfiles 14 | # and i recreated the script posted by @rtrouton to not use any tempfile while processing. 15 | # Link to original script by @rtrouton: https://github.com/rtrouton/rtrouton_scripts/blob/master/rtrouton_scripts/check_system_integrity_protection_status/check_system_integrity_protection_status.sh 16 | 17 | #////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ### 19 | ### MAIN SCRIPT 20 | ### 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | osvers=$( sw_vers -productVersion ) 24 | osvers_major=$( /usr/bin/awk -F. '{print $1}' <<< "${osvers}" ) 25 | osvers_minor=$( /usr/bin/awk -F. '{print $2}' <<< "${osvers}" ) 26 | 27 | if [[ ${osvers_major} -ne 10 ]]; then 28 | printf "%s\n" "Unknown Version of Mac OS X" 29 | elif [[ ${osvers_minor} -lt 11 ]]; then 30 | printf "%s\n" "System Integrity Protection Not Available For ${osvers}" 31 | elif [[ ${osvers_minor} -ge 11 ]]; then 32 | sip_output=$( /usr/bin/csrutil status ) 33 | sip_status=$( /usr/bin/awk '/status/ { gsub(/.$/,""); print $5 }' <<< "${sip_output}" ) 34 | 35 | if [[ ${sip_status} == "disabled" ]]; then 36 | printf "%s\n" "System Integrity Protection status: Disabled" 37 | elif [[ ${sip_status} == "enabled" ]]; then 38 | printf "%s\n" "System Integrity Protection status: Active" 39 | 40 | while read sip_configuration_status; do 41 | if [[ $( awk '{ print $NF }' <<< "${sip_configuration_status}" ) == disabled ]]; then 42 | /usr/bin/awk '{ gsub(/^[ \t]+|[ \t]+$/,""); print; }' <<< "${sip_configuration_status}" 43 | fi 44 | done < <( /usr/bin/awk '/Configuration/ {flag=1;next} /^$/{flag=0} flag {print}' <<< "${sip_output}" ) 45 | fi 46 | fi 47 | 48 | exit 0 49 | -------------------------------------------------------------------------------- /random/printUserWithMostLoggedInTime/README.md: -------------------------------------------------------------------------------- 1 | ## printUserWithMostLoggedInTime -------------------------------------------------------------------------------- /random/printUserWithMostLoggedInTime/printUserWithMostLoggedInTime: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This is from a discussion on macadmins.slack.com where @sohail posted a scrip that I got the wrong output for. 14 | # The error was because of my locale setting in my bash environment. 15 | # To fix that I wrote this snippet to simplify the original script, and to convert the floating point numbers to integers 16 | # to avoid the error I got from the floating point arithmetic. (It was the wrong decimal character in my locale) 17 | 18 | #////////////////////////////////////////////////////////////////////////////////////////////////// 19 | ### 20 | ### MAIN SCRIPT 21 | ### 22 | #////////////////////////////////////////////////////////////////////////////////////////////////// 23 | 24 | # NOTE - This convert's the time output from ac to rounded integers, which might case some erroneous results. 25 | # But the reason is to avoid a floating point math error discovered for my locale. 26 | 27 | # Print user with most accumulated connect time (logged-in) 28 | /usr/sbin/ac -p | /usr/bin/awk '/total/ {next}; {if (int($NF) > max) {max = int($NF); user=$1}} END{print user}' 29 | 30 | # Print user with most accumulated connect time (logged-in) inside a VALUE block for use in Casper Suite extension attribute 31 | #/usr/sbin/ac -p | /usr/bin/awk '/total/ {next}; {if (int($NF) > max) {max = int($NF); user=$1}} END{print ""user""}' 32 | 33 | exit 0 -------------------------------------------------------------------------------- /random/reconnectWiFiNetwork/README.md: -------------------------------------------------------------------------------- 1 | # reconnectWiFiNetwork 2 | -------------------------------------------------------------------------------- /random/reconnectWiFiNetwork/com.github.erikberglund.reconnectWiFiNetwork.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LaunchEvents 8 | 9 | com.apple.notifyd.matching 10 | 11 | com.apple.network_change 12 | 13 | Notification 14 | com.apple.system.config.network_change 15 | 16 | 17 | 18 | 19 | 20 | Label 21 | com.github.erikberglund.reconnectWiFiNetwork 22 | 23 | 24 | Program 25 | /Users/erikberglund/GitHub/Scripts/random/reconnectWiFiNetwork/reconnectWiFiNetwork 26 | 27 | 28 | StandardOutPath 29 | /tmp/com.github.erikberglund.reconnectWiFiNetwork-stdout 30 | 31 | 32 | StandardErrorPath 33 | /tmp/com.github.erikberglund.reconnectWiFiNetwork-stderr 34 | 35 | 36 | -------------------------------------------------------------------------------- /random/reconnectWiFiNetwork/reconnectWiFiNetwork: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Reconnects to specified Wi-Fi network SSID if netork state changes and the configured SSID is in range 14 | # Used in our stores to force computers to the store Wi-Fi, but if stolen allows connection to 15 | # any wifi if the store network isn't in range. 16 | 17 | #////////////////////////////////////////////////////////////////////////////////////////////////// 18 | ### 19 | ### VARIABLES 20 | ### 21 | #////////////////////////////////////////////////////////////////////////////////////////////////// 22 | 23 | # Number of tries to enable Wi-Fi power (Default 10) 24 | wifi_power_max_tries="5" 25 | 26 | # Number of tries to connect to Wi-Fi network (Default 10) 27 | wifi_network_max_tries="5" 28 | 29 | # SSID to try and connect to 30 | wifi_network_ssid="" 31 | 32 | # Password to selected SSID 33 | # It's possible to use the keychain, but then you would have to enable access to the wifi password for this script first, 34 | # or create it using the same script. I haven't covered that in this script, but have used that technique before 35 | wifi_network_password="" 36 | 37 | #////////////////////////////////////////////////////////////////////////////////////////////////// 38 | ### 39 | ### FUNCTIONS 40 | ### 41 | #////////////////////////////////////////////////////////////////////////////////////////////////// 42 | 43 | wifi_power() { 44 | counter=0 45 | until [[ $( current_wifi_power_state ) == ${1} ]]; do 46 | if (( ${wifi_power_max_tries:-10} <= ${counter} )); then 47 | printf "%s\n" "Could not enable Wi-Fi power on interface ${wifi_interface}"; exit 1 48 | fi 49 | /usr/sbin/networksetup -setairportpower "${wifi_interface}" "${1}" 50 | sleep 2 51 | counter=$((${counter}+1)) 52 | done 53 | } 54 | 55 | current_wifi_power_state() { 56 | printf "%s" "$( /usr/sbin/networksetup -getairportpower ${wifi_interface} | awk '{ print tolower($NF) }' )" 57 | } 58 | 59 | wifi_network() { 60 | counter=0 61 | until [[ $( current_wifi_network ) == ${1} ]]; do 62 | if (( ${wifi_network_max_tries:-10} <= ${counter} )); then 63 | printf "%s\n" "Could not connect to network with ssid: ${1}"; exit 1 64 | fi 65 | /usr/sbin/networksetup -setairportnetwork "${wifi_interface}" "${1}" "${wifi_network_password}" 66 | sleep 2 67 | counter=$((${counter}+1)) 68 | done 69 | } 70 | 71 | current_wifi_network() { 72 | printf "%s" "$( /usr/sbin/networksetup -getairportnetwork ${wifi_interface} | awk -F"Network: " '{ print $2 }' )" 73 | } 74 | 75 | #////////////////////////////////////////////////////////////////////////////////////////////////// 76 | ### 77 | ### MAIN SCRIPT 78 | ### 79 | #////////////////////////////////////////////////////////////////////////////////////////////////// 80 | 81 | if [[ -z ${wifi_network_ssid} ]]; then 82 | printf "%s\n" "No SSID selected" 83 | fi 84 | 85 | # Get first Wi-Fi interface (enX) 86 | wifi_interface=$( networksetup -listallhardwareports | awk '/Wi-Fi/ { getline; print $NF; exit; }' ) 87 | if [[ -z ${wifi_interface} ]]; then 88 | printf "%s\n" "Could not get Wi-Fi hardware interface"; exit 1 89 | fi 90 | 91 | # Activate Wi-Fi power if it's off 92 | wifi_power on 93 | 94 | # Connect to ${wifi_network_ssid} if it's in range 95 | wifi_network ${wifi_network_ssid} 96 | 97 | exit 0 98 | -------------------------------------------------------------------------------- /random/saveUserPictureToFile/README.md: -------------------------------------------------------------------------------- 1 | ## saveUserPictureToFile 2 | 3 | -------------------------------------------------------------------------------- /random/saveUserPictureToFile/saveUserPictureToFile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Ouptuts a user's account picture to passed file 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### USAGE 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Usage: ./printDHCPOptions.bash [options] ... 22 | # 23 | # Options: 24 | # -f Output file path 25 | # -u Username (short) 26 | 27 | #////////////////////////////////////////////////////////////////////////////////////////////////// 28 | ### 29 | ### FUNCTIONS 30 | ### 31 | #////////////////////////////////////////////////////////////////////////////////////////////////// 32 | 33 | print_usage() { 34 | printf "\n%s\n\n" "Usage: ./${0##*/} [options] ..." 35 | printf "%s\n" "Options:" 36 | printf " %s\t%s\n" "-f" "Output file path" 37 | printf " %s\t%s\n" "-u" "Username (short)" 38 | printf "\n" 39 | } 40 | 41 | parse_command_line_options() { 42 | while getopts "u:f:" opt; do 43 | case ${opt} in 44 | f) 45 | file="${OPTARG}" 46 | if [[ ${file##*.} != .jpg ]]; then 47 | file="${file}.jpg" 48 | fi 49 | ;; 50 | u) user="${OPTARG}";; 51 | \?) print_usage; exit 1 ;; 52 | :) print_usage; exit 1 ;; 53 | esac 54 | done 55 | 56 | if [[ -z ${file} ]] || [[ -z ${user} ]]; then 57 | print_usage; exit 1 58 | fi 59 | } 60 | 61 | #////////////////////////////////////////////////////////////////////////////////////////////////// 62 | ### 63 | ### MAIN SCRIPT 64 | ### 65 | #////////////////////////////////////////////////////////////////////////////////////////////////// 66 | 67 | # Parse all passed command line options 68 | parse_command_line_options "${@}" 69 | 70 | # Write picture to file 71 | dscl . -read /Users/"${user}" JPEGPhoto | tail -1 | xxd -r -p > "${file}" 72 | -------------------------------------------------------------------------------- /snippets/README.md: -------------------------------------------------------------------------------- 1 | ## Snippets 2 | 3 | Snippets I use in my scripts. 4 | 5 | * [Disk Images](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md) 6 | Snippets for working with disk images. 7 | 8 | * [Directory Services](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_directoryservices.md) 9 | Snippets for interacting with directory services. 10 | 11 | * [Hardware](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md) 12 | Snippets for hardware information. 13 | 14 | * [NetBoot](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_netboot.md) 15 | Snippets for netboot environments. 16 | 17 | * [Operating System](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_os.md) 18 | Snippets for os information. 19 | -------------------------------------------------------------------------------- /snippets/macos_certificates.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: Certificates 2 | 3 | The following snippets are used to interact with certificates. 4 | 5 | ### Index 6 | 7 | * [Get Certificate from SHA-1 hash](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_os.md#os-version) 8 | 9 | ## Get Certificate from SHA-1 hash 10 | 11 | Find the certificate that matches the supplied SHA-1 hash. 12 | 13 | **BASH** 14 | ```bash 15 | hash="F6BE3A02D876EC1F96C6CA983934FF14EEA99409" 16 | security find-certificate -a -Z | awk '/'"${hash}"'/{flag=1;next}/SHA-1 hash:/{flag=0}flag' 17 | ``` 18 | 19 | Output: 20 | 21 | ```console 22 | keychain: "/Users/erikberglund/Library/Keychains/login.keychain-db" 23 | version: 512 24 | class: 0x80001000 25 | attributes: 26 | "alis"="Apple Application Integration Certification Authority" 27 | "cenc"=0x00000003 28 | "ctyp"=0x00000001 29 | "hpky"=0x31EA76A92374A5DFD4FDEEA0C1A69EC6110E11EC "1\352v\251#t\245\337\324\375\356\240\301\246\236\306\021\016\021\354" 30 | "issu"=0x3062310B300906035504061302555331133011060355040A130A4150504C4520494E432E31263024060355040B131D4150504C452043455254494649434154494F4E20415554484F52495459311630140603550403130D4150504C4520524F4F54204341 "0b1\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\023\012APPLE INC.1&0$\006\003U\004\013\023\035APPLE CERTIFICATION AUTHORITY1\0260\024\006\003U\004\003\023\015APPLE ROOT CA" 31 | "labl"="Apple Application Integration Certification Authority" 32 | "skid"=0x31EA76A92374A5DFD4FDEEA0C1A69EC6110E11EC "1\352v\251#t\245\337\324\375\356\240\301\246\236\306\021\016\021\354" 33 | "snbr"=0x5618E82ADBE2DBF3 "V\030\350*\333\342\333\363" 34 | "subj"=0x30818A310B300906035504061302555331133011060355040A0C0A4170706C6520496E632E31263024060355040B0C1D4170706C652043657274696669636174696F6E20417574686F72697479313E303C06035504030C354170706C65204170706C69636174696F6E20496E746567726174696F6E2043657274696669636174696F6E20417574686F72697479 "0\201\2121\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\014\012Apple Inc.1&0$\006\003U\004\013\014\035Apple Certification Authority1>0<\006\003U\004\003\0145Apple Application Integration Certification Authority" 35 | ``` 36 | -------------------------------------------------------------------------------- /snippets/macos_diskimages.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: Disk Images 2 | 3 | The following snippets are used to interact with disk images. 4 | 5 | _Unless otherwise stated, all examples will be using the El Captian InstallESD.dmg disk image for example output:_ 6 | 7 | ```bash 8 | disk_image="/Applications/Install OS X El Capitan.app/Contents/SharedSupport/InstallESD.dmg" 9 | ``` 10 | 11 | ### Index 12 | 13 | * [Disk Image for Mountpoint](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#disk-image-for-mountpoint) 14 | * [Format](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#format) 15 | * [Mountpoint for Disk Image](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#mountpoint-for-disk-image) 16 | * [Partition Scheme](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#partition-scheme) 17 | * [Partition Size](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#partition-size) 18 | * [Recovery Partition](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#recovery-partition) 19 | * [Scanned](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_diskimages.md#scanned) 20 | 21 | ## Disk Image for Mountpoint 22 | 23 | Returns the disk image path for mountpoint. 24 | 25 | **BASH** 26 | ```bash 27 | #!/bin/bash 28 | 29 | # Define the mountpoint to check 30 | disk_image_mountpoint="/Volumes/OS X Install ESD" 31 | 32 | # Return the path to the disk image mounted at mountpoint 33 | disk_image=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string[text()=\"${disk_image_mountpoint}\"]/../../../key[.='image-path']/following-sibling::string[1]/text()" 2>/dev/null ) 34 | 35 | # Check that a path was returned 36 | if [[ -n ${disk_image} ]]; then 37 | printf "%s\n" "Mountpoint: ${disk_image_mountpoint} is mounted from disk image: ${disk_image}" 38 | else 39 | printf "%s\n" "Mountpoint: ${disk_image_mountpoint} is NOT mounted from a disk image" 40 | fi 41 | ``` 42 | 43 | Example using the El Capitan installer InstallESD.dmg disk image: 44 | 45 | Output if mounted from a disk image: 46 | ```console 47 | Mountpoint: /Volumes/OS X Install ESD is mounted from disk image: /Applications/Install OS X El Capitan.app/Contents/SharedSupport/InstallESD.dmg 48 | ``` 49 | 50 | Output if NOT mounted from a disk image: 51 | ```console 52 | Mountpoint: /Volumes/OS X Install ESD is NOT mounted from a disk image 53 | ``` 54 | 55 | ## Format 56 | 57 | Returns the current format for disk image at path. 58 | 59 | **BASH** 60 | ```bash 61 | # Return the format of the disk image 62 | # Using plist output 63 | disk_image_format=$( /usr/libexec/PlistBuddy -c "Print Format" /dev/stdin <<< $( hdiutil imageinfo "${disk_image}" -plist ) ) 64 | 65 | # Using standard output 66 | # disk_image_format=$( hdiutil imageinfo "${disk_image}" | awk '/Format:/ { print $NF }' ) 67 | 68 | # Print output 69 | printf "%s\n" "Disk Image: ${disk_image##*/} has format: ${disk_image_format}" 70 | ``` 71 | 72 | Example using the El Capitan installer InstallESD.dmg disk image: 73 | 74 | ``` 75 | # Output 76 | Disk Image: InstallESD.dmg has format: UDZO 77 | ``` 78 | 79 | Format is any one of the following abbreviations: 80 | 81 | | Format | Description | 82 | |:-------|:----------------------| 83 | | UDRW | UDIF read/write image | 84 | | UDRO | UDIF read-only image | 85 | | UDCO | UDIF ADC-compressed image | 86 | | UDZO | UDIF zlib-compressed image | 87 | | ULFO | UDIF lzfse-compressed image (OS X 10.11+ only) | 88 | | UDBZ | UDIF bzip2-compressed image (Mac OS X 10.4+ only) | 89 | | UDTO | DVD/CD-R master for export | 90 | | UDSP | SPARSE (grows with content) | 91 | | UDSB | SPARSEBUNDLE (grows with content; bundle-backed) | 92 | | UFBI | UDIF entire image with MD5 checksum | 93 | | UDRo | UDIF read-only (obsolete format) | 94 | | UDCo | UDIF compressed (obsolete format) | 95 | | RdWr | NDIF read/write image (deprecated) | 96 | | Rdxx | NDIF read-only image (Disk Copy 6.3.3 format; deprecated) | 97 | | ROCo | NDIF compressed image (deprecated) | 98 | | Rken | NDIF compressed (obsolete format) | 99 | | DC42 | Disk Copy 4.2 image (obsolete format) | 100 | 101 | ## Mountpoint for Disk Image 102 | 103 | Returns the mountpoint for disk image at path. 104 | 105 | **BASH** 106 | ```bash 107 | # Set the path to the disk image 108 | disk_image="/Applications/Install OS X El Capitan.app/Contents/SharedSupport/InstallESD.dmg" 109 | 110 | # Return the path (mountpoint) where the disk image is mounted 111 | disk_image_mountpoint=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='image-path']/following-sibling::string[1][contains(., \"${disk_image}\")]/../key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string/text()" 2>/dev/null ) 112 | 113 | # Check that a path was returned, and that it is a folder 114 | if [[ -n ${disk_image_mountpoint} ]] && [[ -d ${disk_image_mountpoint} ]]; then 115 | printf "%s\n" "Disk Image: ${disk_image##*/} is mounted at: ${disk_image_mountpoint}" 116 | else 117 | printf "%s\n" "Disk Image: ${disk_image##*/} is NOT mounted" 118 | fi 119 | ``` 120 | 121 | **PYTHON** 122 | ```python 123 | import os 124 | import plistlib 125 | import subprocess 126 | 127 | # Path to the disk image 128 | disk_image_path = '/Applications/Install OS X El Capitan.app/Contents/SharedSupport/InstallESD.dmg' 129 | 130 | def getDiskImageMountpoint(image_path): 131 | 132 | # Run command 'hdiutil info -plist' 133 | hdiutil_cmd = ['hdiutil', 'info', '-plist'] 134 | hdiutil_subprocess = subprocess.Popen(hdiutil_cmd, stdout=subprocess.PIPE) 135 | 136 | # Read plist returned into variable 137 | hdiutil_plist = plistlib.readPlist(hdiutil_subprocess.stdout) 138 | 139 | # Loop through all images mounted 140 | for image in hdiutil_plist['images']: 141 | 142 | # Check if current 'image' is the one we're looking for 143 | if not image['image-path'] == image_path: 144 | continue 145 | 146 | # Loop through all entries in the image 'system-entities' array 147 | for entity in image['system-entities']: 148 | 149 | # Loop through all key-value pairs in entity dictionary 150 | for key, value in entity.iteritems(): 151 | 152 | # If key 'mount-point' is found, return that value as disk image mountpoint 153 | if key == 'mount-point': 154 | return value 155 | return '' 156 | 157 | # Return the path (mountpoint) where the disk image is mounted 158 | disk_image_mountpoint = getDiskImageMountpoint(disk_image_path) 159 | 160 | # Check that a path was returned, and that it is a folder 161 | if disk_image_mountpoint and os.path.isdir(disk_image_mountpoint): 162 | print('Disk Image: ' + os.path.basename(disk_image_path) + ' is mounted at: ' + disk_image_mountpoint) 163 | else: 164 | print('Disk Image: ' + os.path.basename(disk_image_path) + ' is NOT mounted') 165 | ``` 166 | 167 | Example using the El Capitan installer InstallESD.dmg disk image: 168 | 169 | Output if mounted: 170 | ```console 171 | Disk Image: InstallESD.dmg is mounted at: /Volumes/OS X Install ESD 172 | ``` 173 | 174 | Output if NOT mounted: 175 | ```console 176 | Disk Image: InstallESD.dmg is NOT mounted 177 | ``` 178 | 179 | ## Partition Scheme 180 | 181 | Returns the partition scheme for disk image at path. 182 | 183 | **BASH** 184 | ```bash 185 | # Return the partition scheme of the disk image 186 | # Using plist output 187 | disk_image_partition_scheme=$( /usr/libexec/PlistBuddy -c "Print partitions:partition-scheme" /dev/stdin <<< $( hdiutil imageinfo "${disk_image}" -plist ) ) 188 | 189 | # Using standard output 190 | # disk_image_partition_scheme=$( hdiutil imageinfo "${disk_image}" | awk '/partition-scheme:/ { print $NF }' ) 191 | 192 | # Print output 193 | printf "%s\n" "Disk Image: ${disk_image##*/} has partition scheme: ${disk_image_partition_scheme}" 194 | ``` 195 | 196 | Output: 197 | 198 | ```console 199 | Disk Image: InstallESD.dmg has partition scheme: GUID 200 | ``` 201 | 202 | ## Partition Size 203 | 204 | Check the block size of a partition. 205 | 206 | **BASH** 207 | ```bash 208 | # Return the partition size for the partition name in 'partition_name' of the disk image 209 | # Partition Name 210 | partition_name="Recovery HD" 211 | 212 | # Using plist output 213 | disk_image_partition_size=$( hdiutil imageinfo "${disk_image}" -plist | xpath "/plist/dict/key[.='partitions']/following-sibling::*[1]/key[.='partitions']/following-sibling::array/dict/key[.='partition-name']/following-sibling::string[1][contains(., \"${partition_name}\")]/../key[.='partition-length']/following-sibling::integer[1]/text()" 2>/dev/null ) 214 | 215 | # Print output 216 | printf "%s\n" "Partition named: ${partition_name} has current block size: ${disk_image_partition_size}" 217 | printf "%s\n" "Partition named: ${partition_name} has current byte size: $((${disk_image_partition_size}*512))" 218 | ``` 219 | 220 | Output using a macOS System disk image created using AutoDMG: 221 | 222 | ```console 223 | Partition named: Recovery HD has current block size: 1269536 224 | Partition named: Recovery HD has current byte size: 650002432 225 | ``` 226 | 227 | ## Recovery Partition 228 | 229 | Check if disk image have a recovery partition. 230 | 231 | **BASH** 232 | ```bash 233 | if (( $( hdiutil pmap "${disk_image}" | awk '/Apple_Boot/ || /Recovery HD/ { print 1 }' ) )); then 234 | printf "%s\n" "Disk Image: ${disk_image##*/} have a recovery partition" 235 | else 236 | printf "%s\n" "Disk Image: ${disk_image##*/} does NOT have a recovery partition" 237 | fi 238 | ``` 239 | 240 | Output using the El Capitan installer InstallESD.dmg disk image: 241 | 242 | ```console 243 | Disk Image: InstallESD.dmg does NOT have a recovery partition 244 | ``` 245 | 246 | Output using a macOS System disk image created using AutoDMG: 247 | 248 | ```console 249 | Disk Image: osx_10.11.5_15F34.hfs.dmg have a recovery partition 250 | ``` 251 | ## Scanned 252 | 253 | Check if disk image have been scanned for restore. 254 | 255 | **BASH** 256 | ```bash 257 | # Return 'true' or 'false' depending on if the disk image have been scanned for restore 258 | # Using plist output 259 | disk_image_scanned=$( /usr/libexec/PlistBuddy -c "Print udif-ordered-chunks" /dev/stdin <<< $( hdiutil imageinfo "${disk_image}" -plist ) ) 260 | 261 | # Using standard output 262 | # disk_image_scanned=$( hdiutil imageinfo "${disk_image}" | awk '/udif-ordered-chunks/ { print $NF }' ) 263 | 264 | if [[ ${disk_image_scanned} == true ]]; then 265 | printf "%s\n" "Disk Image: ${disk_image##*/} is scanned for restore" 266 | else 267 | printf "%s\n" "Disk Image: ${disk_image##*/} is NOT scanned for restore" 268 | fi 269 | ``` 270 | -------------------------------------------------------------------------------- /snippets/macos_finder.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: Finder 2 | 3 | The following snippets are used to modify the Finder 4 | 5 | ### Index 6 | 7 | * [Favorite Servers](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_finder.md#favorite-servers) 8 | * [Favorite Servers](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_finder.md#sidebar) 9 | 10 | ## Favorite Servers 11 | 12 | Add a favorite server to the connect to server dialog 13 | 14 | **NOTE: sfltool requires OS X 10.11 or later** 15 | 16 | **BASH** 17 | ```bash 18 | # Adds an entry with only the hostname or IP showing in the dialog 19 | /usr/bin/sfltool add-item com.apple.LSSharedFileList.FavoriteServers "smb://192.168.0.1/Share" 20 | 21 | # Adds an entry with a custom name ("Company Share") showing in the dialog 22 | /usr/bin/sfltool add-item -n "Company Share" com.apple.LSSharedFileList.FavoriteServers "smb://192.168.0.1/Share" 23 | ``` 24 | 25 | ## Sidebar 26 | 27 | Add an item in the sidebar 28 | 29 | **NOTE: sfltool requires OS X 10.11 or later** 30 | 31 | **BASH** 32 | ```bash 33 | # Adds an item named "Shared" that points to the folder at /Users/Shared 34 | /usr/bin/sfltool add-item com.apple.LSSharedFileList.FavoriteItems file:///Users/Shared 35 | ``` 36 | 37 | You can also add "-v" at the end for verbose output for the add-item command -------------------------------------------------------------------------------- /snippets/macos_hardware.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: Hardware 2 | 3 | The following snippets are used to extract hardware information from a running macOS system. 4 | 5 | ### Index 6 | 7 | * [Serial Number (Computer)](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#serial-number-computer) 8 | * [Serial Number (Logic Board)](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#serial-number-logic-board) 9 | * [MAC Address](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#mac-address) 10 | * [MAC Address (Logic Board)](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#mac-address-logic-board) 11 | * [Battery Percentage](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#battery-percentage) 12 | * [Display Inches](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#display-inches) 13 | * [Board ID](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#board-id) 14 | * [Model Identifier / Machine Model](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#model-identifier--machine-model) 15 | * [RAM Installed](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#ram-installed) 16 | * [Marketing Name](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#marketing-name) 17 | * [Boot ROM Version](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#boot-rom-version) 18 | * [Boot Time/Last Reboot](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#boot-time-last-reboot) 19 | * [Uptime](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#uptime) 20 | * [Virtual Machine](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_hardware.md#virtual-machine) 21 | 22 | ## Serial Number (Computer) 23 | 24 | Serial number for the computer 25 | 26 | **BASH** 27 | ```bash 28 | nvram 4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:SSN | awk '{ gsub(/\%.*/, ""); print $NF }' 29 | ``` 30 | 31 | Alternate Method: 32 | 33 | ```bash 34 | ioreg -d2 -c IOPlatformExpertDevice | awk -F\" '/IOPlatformSerialNumber/ { print $(NF-1) }' 35 | ``` 36 | 37 | Output: 38 | 39 | ```console 40 | C02*****G8WP 41 | ``` 42 | 43 | ## Serial Number (Logic Board) 44 | 45 | Serial number for the main logic board (MLB) 46 | 47 | **BASH** 48 | ```bash 49 | nvram 4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:MLB | awk '{ print $NF }' 50 | ``` 51 | 52 | Output: 53 | 54 | ```console 55 | C0252******GF2C1H 56 | ``` 57 | 58 | ## MAC Address 59 | 60 | MAC address for interface ( using `en0` in the example ) 61 | 62 | **BASH** 63 | ```bash 64 | ifconfig en0 | awk '/ether/{ gsub(":",""); print $2 }' 65 | ``` 66 | 67 | Output: 68 | 69 | ```console 70 | a45e60****** 71 | ``` 72 | 73 | Uppercase output: 74 | 75 | **BASH** 76 | ```bash 77 | ifconfig en0 | awk '/ether/{ gsub(":",""); print toupper($2) }' 78 | ``` 79 | 80 | Output: 81 | 82 | ```console 83 | A45E60****** 84 | ``` 85 | 86 | ## MAC Address (Logic Board) 87 | 88 | MAC address for the main logic board (MLB) 89 | 90 | **BASH** 91 | ```bash 92 | nvram 4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:ROM | awk '{ gsub(/\%/, ""); print $NF }' 93 | ``` 94 | 95 | Output: 96 | 97 | ```console 98 | 0cbc9f****** 99 | ``` 100 | 101 | Uppercase output: 102 | 103 | **BASH** 104 | ```bash 105 | nvram 4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:ROM | awk '{ gsub(/\%/, ""); print toupper($NF) }' 106 | ``` 107 | 108 | Output: 109 | 110 | ```console 111 | 0CBC9F****** 112 | ``` 113 | 114 | ## Battery Percentage 115 | 116 | Current battery charge percentage: 117 | 118 | **BASH** 119 | ```bash 120 | ioreg -rd1 -c AppleSmartBattery | awk '/MaxCapacity/ {max=$NF}; /CurrentCapacity/ {current=$NF} END{OFMT="%.2f%%"; print((current/max) * 100)}' 121 | ``` 122 | 123 | Output: 124 | 125 | ```console 126 | 52,96% 127 | ``` 128 | 129 | ## Display Inches 130 | 131 | Physical size (in inches) for the internal display 132 | 133 | **PYTHON** 134 | ```python 135 | #!/usr/bin/python 136 | 137 | import Quartz 138 | from math import sqrt 139 | 140 | # Get online display data 141 | (online_err, displays, num_displays) = Quartz.CGGetOnlineDisplayList(2, None, None) 142 | 143 | # Loop through all online displays 144 | for display in displays: 145 | 146 | # Make sure we use the built in display 147 | if (Quartz.CGDisplayIsBuiltin(display)): 148 | 149 | # Get size of display in mm (returns an NSSize object) 150 | size = Quartz.CGDisplayScreenSize(display) 151 | 152 | # Divide size by 25.4 to get inches 153 | # Calculate diagonal inches using square root of heigh^2 + width^2 154 | inch = round(sqrt(pow((size.height / 25.4), 2.0) + pow((size.width / 25.4), 2.0)),1) 155 | 156 | print('Internal Display Inches: ' + str(inch)) 157 | ``` 158 | 159 | Output: 160 | 161 | ```console 162 | Internal Display Inches: 15.4 163 | ``` 164 | 165 | ## Board ID 166 | 167 | ID for the motherboard 168 | 169 | **BASH** 170 | ```bash 171 | nvram 4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:HW_BID | awk '{ print $NF }' 172 | ``` 173 | 174 | Alternate Method 175 | 176 | ```bash 177 | ioreg -d2 -c IOPlatformExpertDevice | awk -F\" '/board-id/{ print $(NF-1) }' 178 | ``` 179 | 180 | Output: 181 | 182 | ```console 183 | Mac-06F11F11946D27C5 184 | ``` 185 | 186 | ## Model Identifier / Machine Model 187 | 188 | Model Identifier / Machine Model for the computer 189 | 190 | **BASH** 191 | ```bash 192 | sysctl -n hw.model 193 | ``` 194 | 195 | Output: 196 | 197 | ```console 198 | MacBookPro11,5 199 | ``` 200 | 201 | ## Laptop/Desktop 202 | 203 | Check if computer is laptop or desktop 204 | 205 | **BASH** 206 | ```bash 207 | if [[ $( sysctl -n hw.model ) =~ [Bb]ook ]]; then 208 | printf "%s" "Laptop" 209 | else 210 | printf "%s" "Desktop" 211 | fi 212 | ``` 213 | 214 | Output: 215 | 216 | ```console 217 | Laptop 218 | ``` 219 | 220 | ## RAM Installed 221 | 222 | RAM installed (in GB without unit) 223 | 224 | **BASH** 225 | ```bash 226 | # Get RAM installed in GB 227 | ram_gb=$(( $( sysctl -n hw.memsize ) >> 30 )) 228 | 229 | # Print value to stdout 230 | printf "%s\n" "${ram_gb}" 231 | ``` 232 | 233 | Output: 234 | 235 | ```console 236 | 16 237 | ``` 238 | 239 | RAM installed (in MB without unit) 240 | 241 | **BASH** 242 | ```bash 243 | # Get RAM installed in MB 244 | ram_mb=$(( $( sysctl -n hw.memsize ) >> 20 )) 245 | 246 | # Print value to stdout 247 | printf "%s\n" "${ram_mb}" 248 | ``` 249 | 250 | Output: 251 | 252 | ```console 253 | 16384 254 | ``` 255 | 256 | ## Marketing Name 257 | 258 | **NOTE! Requires an internet connection** 259 | 260 | Marketing name for computer 261 | 262 | **BASH** 263 | ```bash 264 | curl -s http://support-sp.apple.com/sp/product?cc=$( ioreg -c IOPlatformExpertDevice -d 2 | awk -F\" '/IOPlatformSerialNumber/{ sn=$(NF-1); if (length(sn) == 12) count=3; else if (length(sn) == 11) count=2; print substr(sn, length(sn) - count, length(sn)) }' ) | xpath '/root/configCode/text()' 2>/dev/null 265 | ``` 266 | 267 | Output: 268 | 269 | ```console 270 | MacBook Pro (Retina, 15-inch, Mid 2015) 271 | ``` 272 | 273 | ## Boot ROM Version 274 | 275 | Return the current boot ROM (EFI) version 276 | 277 | **BASH** 278 | ```bash 279 | ioreg -p IODeviceTree -n rom@0 -r | awk -F\" '/version/{ print $(NF-1) }' 280 | ``` 281 | 282 | Output: 283 | 284 | ```console 285 | MBP114.88Z.0172.B10.1610201519 286 | ``` 287 | 288 | ## Boot Time/Last Reboot 289 | 290 | Get boot time (last reboot) in unix timestamp or as a date string 291 | 292 | **BASH** 293 | ```bash 294 | # Get boot time from kernel in unix timestamp 295 | boot_time_unix=$( sysctl -n kern.boottime | awk -F'[^0-9]*' '{ print $2 }' ) 296 | 297 | # Get boot time from kernel in unix timestamp and convert to date string 298 | # Using this format as output: "+%F %T %z" 299 | boot_time_date=$( sysctl -n kern.boottime | awk -F'[^0-9]*' '{ print $2 }' | xargs date -jf "%s" "+%F %T %z" ) 300 | 301 | # Print value to stdout 302 | printf "%s\n" "boot_time_unix=${boot_time_unix}" 303 | printf "%s\n" "boot_time_date=${boot_time_date}" 304 | ``` 305 | 306 | Output: 307 | 308 | ```console 309 | boot_time_unix=1508047230 310 | boot_time_date=2017-10-15 08:00:30 +0200 311 | ``` 312 | 313 | ## Uptime 314 | 315 | Get system uptime in seconds 316 | 317 | **BASH** 318 | ```bash 319 | # Get boot time from kernel and calculate difference from current time 320 | uptime=$(( $( date +%s ) - $( sysctl -n kern.boottime | awk -F'[^0-9]*' '{ print $2 }' ) )) 321 | 322 | # Print value to stdout 323 | printf "%s\n" "${uptime}" 324 | ``` 325 | 326 | Output: 327 | 328 | ```console 329 | 1107 330 | ``` 331 | 332 | ## Virtual Machine 333 | 334 | Check if system is running in a virtual machine 335 | 336 | **BASH** 337 | ```bash 338 | if sysctl -n machdep.cpu.features | grep -q "VMM"; then 339 | printf "%s" "VM" 340 | else 341 | printf "%s" "Not VM" 342 | fi 343 | ``` 344 | 345 | Output: 346 | 347 | ```console 348 | Not VM 349 | ``` 350 | -------------------------------------------------------------------------------- /snippets/macos_netboot.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: NetBoot 2 | 3 | The following snippets are used in a NetBoot environment. 4 | 5 | Here is a blogpost I wrote related to NetBoot environment variables: [Get BSDP Server IP from a NetBoot client](http://erikberglund.github.io/2016/Get-BSDP-Server-IP-from-a-NetBoot-client/) 6 | 7 | ### Index 8 | 9 | * [BSDP Server IP](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_netboot.md#bsdp-server-ip) 10 | * [DHCP Server IP](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_netboot.md#dhcp-server-ip) 11 | * [Is NetBooted](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_netboot.md#is-netbooted) 12 | * [NBI Name](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_netboot.md#nbi-name) 13 | 14 | 15 | ### BSDP Variables 16 | 17 | ```bash 18 | ipconfig netbootoption shadow_mount_path 19 | ipconfig netbootoption shadow_file_path 20 | ipconfig netbootoption machine_name 21 | ipconfig netbootoption 17 22 | ipconfig netbootoption 43 23 | ipconfig netbootoption 53 24 | ipconfig netbootoption 54 25 | ipconfig netbootoption 60 26 | ipconfig netbootoption 66 27 | ipconfig netbootoption 67 28 | ``` 29 | 30 | ## BSDP Server IP 31 | 32 | Get the IP for the server currently netbooted from. 33 | 34 | **BASH** 35 | ```bash 36 | ipconfig netbootoption 17 | awk -F'/' '{ print $3 }' 37 | ``` 38 | 39 | Alternate method: 40 | 41 | ```bash 42 | # Get device id for the boot volume ( example: /dev/disk1s1 ) 43 | boot_device_id=$( diskutil info / | awk '/Device Node:/ { print $NF }' ) 44 | 45 | # Get path for the disk image mounted at "${boot_device_id}" 46 | boot_disk_image_path=$( hdiutil info | awk -v device_id="${boot_device_id}" '{ 47 | if ( $1 == "image-path" ) { 48 | disk_image_path=$NF; 49 | } else if ( $1 == device_id ) { 50 | print disk_image_path; exit 0 51 | } }' ) 52 | 53 | # Print the IP for the BSDP Server 54 | awk -F'/' '{ print $3 }' <<< "${boot_disk_image_path}" 55 | ``` 56 | 57 | Output: 58 | 59 | ```console 60 | 10.2.0.10 61 | ``` 62 | 63 | ## DHCP Server IP 64 | 65 | Get the IP for the DHCP server. 66 | 67 | **BASH** 68 | ```bash 69 | ipconfig netbootoption 54 70 | ``` 71 | 72 | Output: 73 | 74 | ```console 75 | 10.2.0.1 76 | ``` 77 | 78 | ## Is NetBooted 79 | 80 | Check if the computer is currently netbooted 81 | 82 | **BASH** 83 | ```bash 84 | if [[ $( sysctl -n kern.netboot ) ]]; then 85 | echo "Not NetBooted"; 86 | else 87 | echo "NetBooted"; 88 | fi 89 | ``` 90 | 91 | Output: 92 | 93 | ```console 94 | NetBooted 95 | ``` 96 | 97 | ## NBI Name 98 | 99 | Get the name of the NBI currently booted from. 100 | 101 | **BASH** 102 | ```bash 103 | ipconfig netbootoption 17 | sed -nE 's/.*\/(.*\.nbi)\/.*/\1/p' 104 | ``` 105 | 106 | Output: 107 | 108 | ```console 109 | 10.12-16A323_Imagr.nbi 110 | ``` 111 | -------------------------------------------------------------------------------- /snippets/macos_network.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: Network 2 | 3 | The following snippets are used te get networking information. 4 | 5 | ### Index 6 | 7 | * [Active Network Interface](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_network.md#active-network-interface) 8 | * [IP for Network Interface](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_network.md#ip-for-network-interface) 9 | * [Hardware Port for Network Interface](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_network.md#hardware-port-for-network-interface) 10 | * [Renew DHCP Address for Network Interface](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_network.md#renew-dhcp-address-for-network-interface) 11 | 12 | ## Active Network Interface 13 | 14 | Get the currently active (primary) network interface. 15 | 16 | **BASH** 17 | ```bash 18 | scutil <<< "show State:/Network/Global/IPv4" | awk '/PrimaryInterface/ { print $NF }' 19 | ``` 20 | 21 | Alternate method: 22 | 23 | ```bash 24 | 25 | ``` 26 | 27 | Output: 28 | 29 | ```console 30 | en0 31 | ``` 32 | 33 | ## IP for Network Interface 34 | 35 | Get the primary IP for the passed network interface. 36 | 37 | **BASH** 38 | ```bash 39 | # Get network interface to check (See 'Active Network Interface' to get current interface) 40 | interface=en0 41 | 42 | # Print the IP for the network interface 43 | scutil <<< "show State:/Network/Interface/${interface}/IPv4" | awk '/\ Addresses\ / { getline; print $NF }' 44 | ``` 45 | 46 | Output: 47 | 48 | ```console 49 | 192.168.2.52 50 | ``` 51 | 52 | ## Hardware Port for Network Interface 53 | 54 | Get the hardware port (Ethernet, Wi-Fi etc.) for the passed network interface. 55 | 56 | **BASH** 57 | ```bash 58 | # Get network interface to check (See 'Active Network Interface' to get current interface) 59 | interface=en0 60 | 61 | # Print the hardware port for the network interface 62 | networksetup -listallhardwareports | awk '/Hardware Port:/ { line = $NF }; /Device: '"${interface}"'/ { print line }' 63 | ``` 64 | 65 | Output: 66 | 67 | ```console 68 | Ethernet 69 | ``` 70 | 71 | ## Renew DHCP Address for Network Interface 72 | 73 | Request a new DHCP Address for passed network interface. 74 | 75 | **BASH** 76 | ```bash 77 | # Get network interface to check (See 'Active Network Interface' to get current interface) 78 | interface=en0 79 | 80 | # 81 | sudo scutil <<< "add State:/Network/Interface/${interface}/RefreshConfiguration temporary" 82 | ``` -------------------------------------------------------------------------------- /snippets/macos_os.md: -------------------------------------------------------------------------------- 1 | # macOS Snippets: OS 2 | 3 | The following snippets are used to extract os information from a macOS system. 4 | 5 | ### Index 6 | 7 | * [OS Version](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_os.md#os-version) 8 | * [OS Build Version](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_os.md#os-build-version) 9 | * [OS Marketing Name](https://github.com/erikberglund/Scripts/blob/master/snippets/macos_os.md#os-marketing-name) 10 | 11 | ## OS Version 12 | 13 | On a running system you can use the `sw_vers` command to query the os version. 14 | 15 | **BASH** 16 | ```bash 17 | sw_vers -productVersion 18 | ``` 19 | 20 | Output: 21 | 22 | ```console 23 | 10.11.5 24 | ``` 25 | 26 | You can also read the `SystemVersion.plist` file directly (useful for checking mounted systems): 27 | 28 | **BASH** 29 | ```bash 30 | /usr/libexec/PlistBuddy -c "Print ProductVersion" "/System/Library/CoreServices/SystemVersion.plist" 31 | ``` 32 | 33 | Output: 34 | 35 | ```console 36 | 10.11.5 37 | ``` 38 | 39 | If you need each component of the version string in separate variables, use the `read` command: 40 | 41 | **BASH** 42 | ```bash 43 | IFS='.' read -r major minor patch < <( /usr/bin/sw_vers -productVersion ) 44 | 45 | # Now the variables hold the following values: 46 | # major=10 47 | # minor=11 48 | # patch=5 49 | ``` 50 | 51 | ## OS Build Version 52 | 53 | On a running system you can use the `sw_vers` command to query the os build version. 54 | 55 | **BASH** 56 | ```bash 57 | sw_vers -buildVersion 58 | ``` 59 | 60 | Output: 61 | 62 | ```console 63 | 15F34 64 | ``` 65 | 66 | You can also read the `SystemVersion.plist` file directly (useful for checking mounted systems): 67 | 68 | **BASH** 69 | ```bash 70 | /usr/libexec/PlistBuddy -c "Print ProductBuildVersion" "/System/Library/CoreServices/SystemVersion.plist" 71 | ``` 72 | 73 | Output: 74 | 75 | ```console 76 | 15F34 77 | ``` 78 | 79 | ## OS Marketing Name 80 | 81 | **NOTE! Requires an internet connection** 82 | 83 | This retrieves the marketing name for an OS X version string from Apple's server. 84 | 85 | **BASH** 86 | ```bash 87 | curl -s http://support-sp.apple.com/sp/product?edid=$( sw_vers -productVersion ) | xpath '/root/configCode/text()' 2>/dev/null 88 | ``` 89 | 90 | Output: 91 | 92 | ```console 93 | OS X El Capitan 94 | ``` 95 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | ## Tools 2 | These are scripts with a utility like feature to be used as tools. 3 | 4 | * [jekyllServe](https://github.com/erikberglund/Scripts/blob/master/tools/jekyllServe) 5 | Small convenience script to start serving a jekyll site (and open it in a browser). 6 | 7 | * [letsEncryptJSS](https://github.com/erikberglund/Scripts/blob/master/tools/letsEncryptJSS) 8 | Enable and update Let's Encrypt certificate for a JSS running on Ubuntu. 9 | 10 | * [modelUTIInfo](https://github.com/erikberglund/Scripts/blob/master/tools/modelUTIInfo) 11 | Get marketing name and icon path for Apple product by modelID or modelCode. 12 | 13 | * [osxImageModifier](https://github.com/erikberglund/Scripts/blob/master/tools/osxImageModifier) 14 | Update contents in or reconfigure an OS X Disk Image. 15 | 16 | * [osxInstallerArchiver](https://github.com/erikberglund/Scripts/blob/master/tools/osxInstallerArchiver) 17 | Find and create disk images for OS X Installer applications. 18 | 19 | * [privilegedHelperToolReset](https://github.com/erikberglund/Scripts/blob/master/tools/privilegedHelperToolReset) 20 | Stop and remove a privileged helper tool and launchd job. 21 | 22 | * [privilegedHelperToolStatus](https://github.com/erikberglund/Scripts/blob/master/tools/privilegedHelperToolStatus) 23 | Get status of PrivilegedHelper tools and their parent applications. 24 | 25 | * [serverAppArchiver](https://github.com/erikberglund/Scripts/blob/master/tools/serverAppArchiver) 26 | Find and create disk images for OS X Server applications. 27 | 28 | * [sharedLibraryDependencyChecker](https://github.com/erikberglund/Scripts/blob/master/tools/sharedLibraryDependencyChecker) 29 | List missing linked libraries on target volume recursively for one or more binaries. 30 | -------------------------------------------------------------------------------- /tools/jekyllServe/README.md: -------------------------------------------------------------------------------- 1 | ## jekyllServe 2 | 3 | Small convenience script to start serving a jekyll site (and open it in a browser). -------------------------------------------------------------------------------- /tools/jekyllServe/jekyllServe: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Starts serving a jekyll site with passed options, and opens the site in a web browser 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### VARIABLES 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Path to the jekyll site root folder 22 | site_folder="/Users/erikberglund/Documents/GitHub Private/erikberglund.github.io" 23 | 24 | #////////////////////////////////////////////////////////////////////////////////////////////////// 25 | ### 26 | ### FUNCIONS 27 | ### 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | 30 | parse_opts() { 31 | options="" 32 | while getopts "d" opt; do 33 | case ${opt} in 34 | d) options="${options} --draft" ;; 35 | \?) printf "%s\n" "Invalid option: -${OPTARG}" >&2; exit 1;; 36 | :) printf "%s\n" "Option -${OPTARG} requires an argument." >&2; exit 1;; 37 | esac 38 | done 39 | } 40 | 41 | #////////////////////////////////////////////////////////////////////////////////////////////////// 42 | ### 43 | ### MAIN SCRIPT 44 | ### 45 | #////////////////////////////////////////////////////////////////////////////////////////////////// 46 | 47 | # Parse passed arguments 48 | parse_opts "${@}" 49 | 50 | # Open site in web browser (before serving site, as that command will run until Command-C) 51 | open "http://127.0.0.1:4000" & 52 | 53 | # Change directory and start serving site 54 | ( cd "${site_folder}" && bundle exec jekyll serve ${options} ) 55 | 56 | exit 0 57 | -------------------------------------------------------------------------------- /tools/letsEncryptJSS/README.md: -------------------------------------------------------------------------------- 1 | ## letsEncryptJSS 2 | 3 | This script sets up and manages Let's Encrypt for a JSS running on Ubuntu 14.04. 4 | 5 | **NOTE! This script only handles a single JSS configuration in the tomcat settings.** 6 | 7 | ### Configuration 8 | 9 | Configure the following variables before using the script: 10 | 11 | **sslEmail** 12 | 13 | ```bash 14 | # E-mail address for the certificate CA 15 | sslEmail="ca@example.com" 16 | ``` 17 | 18 | **sslDomain** 19 | 20 | ```bash 21 | # Domain for the certificate 22 | sslDomain="jss.example.com" 23 | ``` 24 | 25 | **tomcatKeystorePassword** 26 | 27 | ```bash 28 | # Password for Tomcat keystore 29 | tomcatKeystorePassword="passw0rd" 30 | ``` 31 | 32 | ### Execution 33 | 34 | The script will create a backup of the jss server xml before modifying it. 35 | 36 | If nothing was modified, the backup is removed to only keep actual configuration changes as backup. 37 | -------------------------------------------------------------------------------- /tools/letsEncryptJSS/letsEncryptJSS: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | 8 | #////////////////////////////////////////////////////////////////////////////////////////////////// 9 | ### 10 | ### VARIABLES 11 | ### 12 | #////////////////////////////////////////////////////////////////////////////////////////////////// 13 | 14 | # 15 | # CHANGE THESE VARIABLES 16 | # 17 | 18 | # E-mail address for the certificate CA 19 | sslEmail="" 20 | 21 | # Domain for the certificate 22 | sslDomain="" 23 | 24 | # Password for Tomcat keystore 25 | tomcatKeystorePassword="" 26 | 27 | # 28 | # Let's Encrypt Variables 29 | # 30 | 31 | # Path to Let's Encrypt client script 32 | letsEncrypt="/usr/local/sbin/certbot-auto" 33 | 34 | # Path to Let's Encrypt certificates 35 | letsEncryptCertificatesPath="/etc/letsencrypt/live" 36 | 37 | # 38 | # Tomcat Variables 39 | # 40 | 41 | # Path to Tomcat installation 42 | tomcatPath="/usr/local/jss/tomcat" 43 | 44 | # Path to Tomcat configuration 45 | tomcatConfigPath="${tomcatPath}/conf/server.xml" 46 | 47 | # Path to Tomcat keystore 48 | tomcatKeystorePath="${tomcatPath}/keystore" 49 | 50 | # Unallowed characters for Tomcat keystore password 51 | # (precaution to not make errors when escaping it when passed to sed for insertion in server config) 52 | tomcatKeystorePasswordUnallowedCharacters="/" 53 | 54 | #////////////////////////////////////////////////////////////////////////////////////////////////// 55 | ### 56 | ### FUNCIONS 57 | ### 58 | #////////////////////////////////////////////////////////////////////////////////////////////////// 59 | 60 | verifyVariables() { 61 | 62 | if [[ -z ${sslEmail} ]]; then 63 | printf "%s\n" "Variable 'sslEmail' cannot be empty" >&2 64 | exit 1 65 | fi 66 | 67 | if [[ -z ${sslDomain} ]]; then 68 | printf "%s\n" "Variable 'sslDomain' cannot be empty" >&2 69 | exit 1 70 | fi 71 | 72 | if [[ -z ${tomcatKeystorePassword} ]]; then 73 | printf "%s\n" "Variable 'tomcatKeystorePassword' cannot be empty" >&2 74 | exit 1 75 | elif [[ ${tomcatKeystorePassword} =~ ${tomcatKeystorePasswordUnallowedCharacters} ]]; then 76 | printf "%s\n" "Variable 'tomcatKeystorePassword' cannot contain the following characters: ${tomcatKeystorePasswordUnallowedCharacters}" >&2 77 | exit 1 78 | fi 79 | } 80 | 81 | verifyTomcatSettings () { 82 | 83 | printf "%s\n" "${tomcatConfigPath}" 84 | 85 | } 86 | 87 | # Install Let's Encrypt 88 | installLetsEncrypt () { 89 | 90 | # Download Let's Encrypt client 91 | sudo curl -o "${letsEncrypt}" https://dl.eff.org/certbot-auto 92 | 93 | # Verify the Let's Encrypt client was downloaded 94 | if ! [[ -f ${letsEncrypt} ]]; then 95 | printf "%s\n" "${letsEncrypt}: No such file" >&2 96 | exit 1 97 | fi 98 | 99 | # Correct permissions on Let's Encrypt client 100 | sudo chmod a+x "${letsEncrypt}" 101 | 102 | # Verify the Let's Encrypt client is executable 103 | if ! [[ -x ${letsEncrypt} ]]; then 104 | printf "%s\n" "${letsEncrypt} needs to be executable!" >&2 105 | exit 1 106 | fi 107 | 108 | # Run inital setup 109 | sudo "${letsEncrypt}" -n -h 110 | 111 | # Stop Tomcat 112 | if ! sudo /etc/init.d/jamf.tomcat8 stop; then 113 | printf "%s\n" "Stopping tomcat failed!" >&2 114 | exit 1 115 | fi 116 | 117 | # Generate initial certificate files 118 | sudo -H "${letsEncrypt}" certonly --standalone -m "${sslEmail}" -d "${sslDomain}" --agree-tos 119 | 120 | # Replace Tomcat keystore with new certificate 121 | replaceKeystoreWithCertificate 122 | 123 | # Start Tomcat 124 | sudo /etc/init.d/jamf.tomcat8 start 125 | } 126 | 127 | renewCertificate () { 128 | 129 | # Stop Tomcat 130 | if ! sudo /etc/init.d/jamf.tomcat8 stop; then 131 | printf "%s\n" "Stopping tomcat failed!" >&2 132 | exit 1 133 | fi 134 | 135 | # Renew certificate files (if they are eligeble) 136 | sudo -H "${letsEncrypt}" renew --quiet --no-self-upgrade 137 | 138 | # Replace Tomcat keystore with new certificate 139 | replaceKeystoreWithCertificate 140 | 141 | # Start Tomcat 142 | sudo /etc/init.d/jamf.tomcat8 start 143 | } 144 | 145 | replaceKeystoreWithCertificate () { 146 | 147 | # Remove current keystore 148 | if [[ -f ${tomcatKeystorePath}/keystore.jks ]]; then 149 | rm "${tomcatKeystorePath}/keystore.jks" 150 | fi 151 | 152 | # Create keystore path if it doesn't exist 153 | if ! [[ -d ${tomcatKeystorePath} ]]; then 154 | mkdir "${tomcatKeystorePath}" 155 | chown "jamftomcat:jamftomcat" "${tomcatKeystorePath}" 156 | chmod 755 "${tomcatKeystorePath}" 157 | fi 158 | 159 | # Combine Let's Encrypt certificate files into PKCS12 160 | openssl pkcs12 \ 161 | -export \ 162 | -in "${letsEncryptCertificatesPath}/${sslDomain}/fullchain.pem" \ 163 | -inkey "${letsEncryptCertificatesPath}/${sslDomain}/privkey.pem" \ 164 | -out "${tomcatKeystorePath}/${sslDomain}.p12" \ 165 | -password pass:"${tomcatKeystorePassword}" \ 166 | -name tomcat 167 | 168 | # Convert PKCS12 into java keystore 169 | keytool -importkeystore \ 170 | -deststorepass "${tomcatKeystorePassword}" \ 171 | -destkeypass "${tomcatKeystorePassword}" \ 172 | -destkeystore "${tomcatKeystorePath}/keystore.jks" \ 173 | -srckeystore "${tomcatKeystorePath}/${sslDomain}.p12" \ 174 | -srcstoretype PKCS12 \ 175 | -srcstorepass "${tomcatKeystorePassword}" \ 176 | -alias tomcat 177 | 178 | # Remove temporary PKCS12 file 179 | rm "${tomcatKeystorePath}/${sslDomain}.p12" 180 | 181 | # Update Tomcat config to match keystore path and password 182 | updateTomcatKeystoreConfig 183 | } 184 | 185 | updateTomcatKeystoreConfig () { 186 | 187 | # Backup current configuration 188 | tomcatConfigBackupPath="${tomcatConfigPath%.*}-$( date +%F:%H:%M:%S ).xml" 189 | cp "${tomcatConfigPath}" "${tomcatConfigBackupPath}" 190 | 191 | if [[ -f ${tomcatConfigBackupPath} ]]; then 192 | 193 | # Update keystore path (use ; as delimiter as the path contains slashes) 194 | sed -i'' -r "s;keystoreFile=\".*\"( .*?|>);keystoreFile=\"${tomcatKeystorePath}/keystore.jks\"\1;" "${tomcatConfigPath}" 195 | 196 | # Update keystore password 197 | if grep "keystorePass=\"" "${tomcatConfigPath}"; then 198 | sed -i'' -r "s/keystorePass=\".*\"( .*?|>)/keystorePass=\"${tomcatKeystorePassword}\"\1/" "${tomcatConfigPath}" 199 | else 200 | sed -i'' -r "s/^(.*keystoreFile.*)( \/>)/\1 keystorePass=\"${tomcatKeystorePassword}\"\2/" "${tomcatConfigPath}" 201 | fi 202 | 203 | # Update or set keyalias variable 204 | if grep "keyAlias=\"" "${tomcatConfigPath}"; then 205 | sed -i'' -r "s/keyAlias=\".*\"( .*?|>)/keyAlias=\"tomcat\"\1/" "${tomcatConfigPath}" 206 | else 207 | sed -i'' -r "s/^(.*keystoreFile.*)( \/>)/\1 keyAlias=\"tomcat\"\2/" "${tomcatConfigPath}" 208 | fi 209 | 210 | # Remove backup if nothing has changed (to avoid lot's of duplicate copies) 211 | if cmp --silent "${tomcatConfigPath}" "${tomcatConfigBackupPath}"; then 212 | printf "%s\n" "Backup is equal to current config, removing unneccesary backup!" >&2 213 | rm "${tomcatConfigBackupPath}" 214 | fi 215 | else 216 | printf "%s\n" "Backup Tomcat server config failed!" >&2 217 | printf "%s\n" "No modifications made!" >&2 218 | fi 219 | } 220 | 221 | #////////////////////////////////////////////////////////////////////////////////////////////////// 222 | ### 223 | ### MAIN SCRIPT 224 | ### 225 | #////////////////////////////////////////////////////////////////////////////////////////////////// 226 | 227 | # Make sure the script is running on the required platform 228 | if ! [[ $( lsb_release -s -d 2>&1 ) =~ ^'Ubuntu 14.04' ]]; then 229 | printf "%s\n" "This script requires Ubutnu 14.04" >&2 230 | exit 1 231 | fi 232 | 233 | # Make sure all required variables are present and valid 234 | verifyVariables 235 | 236 | # Make sure we only configure Tomcat if we can be sure to be successful 237 | verifyTomcatSettings 238 | 239 | # Install Let's Encrypt if not already installed 240 | if ! [[ -f "${letsEncrypt}" ]]; then 241 | installLetsEncrypt 242 | else 243 | # Renew Let's Encrypt certificate (if it's eligeble) 244 | renewCertificate 245 | fi 246 | 247 | exit 0 -------------------------------------------------------------------------------- /tools/modelUTIInfo/README.md: -------------------------------------------------------------------------------- 1 | ## modelUTIInfo 2 | 3 | This script was mostly a test for parsing plist files in Python. 4 | 5 | You can pass a model identifier or model code and get information about: 6 | 7 | * Marketing Name 8 | * Model Code (Mobile Devices) 9 | * Icon Path 10 | * Uniform Type Identifier 11 | 12 | It's parsing the registered [UTIs](https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html#//apple_ref/doc/uid/TP40001319-CH202-SW1) for apple products found in the following locations: 13 | 14 | 15 | _Mobile Devices:_ 16 | 17 | ```console 18 | /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Info.plist 19 | ``` 20 | 21 | _Other Devices:_ 22 | 23 | ```console 24 | /System/Library/CoreServices/CoreTypes.bundle/Contents/Info.plist 25 | ``` 26 | 27 | ### Usage 28 | 29 | ```console 30 | usage: modelUTIInfo.py [-h] [-c MODELCODE] [-i] [-l] [-m MODELID] [-n] 31 | ``` 32 | 33 | ### Example 34 | 35 | **List all available product modelIDs and their corresponding marketing name:** 36 | 37 | ```console 38 | ./modelUTIInfo.py -l 39 | AirPort4,102, AirPort4,107 = AirPort Express 40 | AirPort5,104, AirPort5,105, AirPort5,108, AirPort5,114, AirPort5,117 = AirPort Extreme 41 | AirPort6,106, TimeCapsule6,106, TimeCapsule6,109, TimeCapsule6,113, TimeCapsule6,116 = Time Capsule 42 | AirPort7,120 = AirPort Extreme 43 | AppleTV1,1 = Apple TV 44 | AppleTV2,1 = Apple TV (2nd generation) 45 | AppleTV3,1 = Apple TV (3rd generation) 46 | AppleTV3,2 = Apple TV (3rd generation Rev A) 47 | AppleTV5,3 = Apple TV 48 | ... 49 | ``` 50 | 51 | **Information for modelID (iPhone8,2):** 52 | 53 | ```console 54 | ./modelUTIInfo.py -m iPhone8,2 55 | Marketing Name: iPhone 6s Plus 56 | Model IDs: iPhone8,2 57 | Model Codes: N66AP, N66mAP 58 | Type Identifier: com.apple.iphone-6s-plus-b9b7ba 59 | Model Icons: [Rose Gold]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-6s-plus-e4c1b9.icns 60 | [Space Grey]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-6s-plus-b9b7ba.icns 61 | [Gold]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-6s-plus-e1ccb7.icns 62 | [Silver]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-6s-plus-dadcdb.icns 63 | ``` 64 | 65 | **Marketing Name for modelCode (N66mAP):** 66 | 67 | ```console 68 | ./modelUTIInfo.py -c N66mAP -n 69 | iPhone 6s Plus 70 | ``` 71 | 72 | **Available Icons for modelID (iPhone5,4):** 73 | 74 | ```console 75 | ./modelUTIInfo.py -m iPhone5,4 -i 76 | [Blue]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-5c-46abe0.icns 77 | [Pink]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-5c-fe767a.icns 78 | [White]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-5c-f5f4f7.icns 79 | [Green]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-5c-a1e877.icns 80 | [Yellow]: /System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources/com.apple.iphone-5c-faf189.icns 81 | ``` -------------------------------------------------------------------------------- /tools/modelUTIInfo/modelUTIInfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import plistlib 5 | import re 6 | import sys 7 | import subprocess 8 | from subprocess import Popen, PIPE 9 | 10 | mobile_devices_info_plist="/System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Info.plist" 11 | mobile_devices_resources="/System/Library/CoreServices/CoreTypes.bundle/Contents/Library/MobileDevices.bundle/Contents/Resources" 12 | 13 | mac_devices_info_plist="/System/Library/CoreServices/CoreTypes.bundle/Contents/Info.plist" 14 | mac_devices_resources="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources" 15 | 16 | model_id_regex=re.compile("^[a-zA-Z]+[0-9]+?,?[0-9]+?($|@.*)") 17 | 18 | devices=[] 19 | 20 | class device: 21 | def __init__(self, device_type, marketing_name, model_icons, type_identifier, model_ids, model_codes): 22 | self.device_type = device_type 23 | self.model_icons = model_icons 24 | self.marketing_name = marketing_name 25 | self.model_type_identifier = type_identifier 26 | self.model_ids = model_ids 27 | self.model_codes = model_codes 28 | 29 | def get_devices(): 30 | 31 | for plist in [ mobile_devices_info_plist, mac_devices_info_plist ]: 32 | 33 | # Convert binary plist and store it in mdplist 34 | xmlplist = plistlib.readPlistFromString(subprocess.Popen(["plutil", "-convert", "xml1", "-o", "-", plist], stdout=PIPE).communicate()[0]) 35 | 36 | if plist == mobile_devices_info_plist: 37 | device_type = "mobile" 38 | device_resources = mobile_devices_resources 39 | elif plist == mac_devices_info_plist: 40 | device_type = "mac" 41 | device_resources = mac_devices_resources 42 | 43 | # Loop through all dicts in 'UTExportedTypeDeclarations' 44 | for device_dict in xmlplist["UTExportedTypeDeclarations"]: 45 | 46 | # Only continue if an entry in [...]:UTTypeTagSpecification:com.apple.device-model-code exists 47 | if device_dict.get("UTTypeTagSpecification", {}).get("com.apple.device-model-code", []): 48 | 49 | model_ids = [] 50 | model_codes = [] 51 | color_name = "" 52 | add_device = True 53 | 54 | # Loop through all model codes and add to class 55 | for model_code in device_dict.get("UTTypeTagSpecification", {}).get("com.apple.device-model-code", []): 56 | if model_id_regex.match(model_code): 57 | model_ids.append(model_code) 58 | elif model_code not in ['iPhone', 'iPod', 'iPad', 'Watch', 'AppleTV']: 59 | model_codes.append(model_code) 60 | 61 | # Get color name from the icon path 62 | icon_path = device_dict.get("UTTypeIconFile", "") 63 | if icon_path: 64 | color_name = color_from_icon_path(icon_path) 65 | 66 | # Loop through all added devices if device info info already exist 67 | for d in devices: 68 | if d.model_ids == model_ids and d.model_codes == model_codes: 69 | add_device = False 70 | if d.model_icons: 71 | d.model_icons[color_name] = device_resources + "/" + device_dict.get("UTTypeIconFile", "") 72 | else: 73 | d.model_icons = { color_name : device_resources + "/" + device_dict.get("UTTypeIconFile", "")} 74 | break 75 | 76 | # If add_devices is 'True' and Model ID has been set, add device to list 77 | if add_device and model_ids: 78 | devices.append(device(device_type, device_dict.get("UTTypeDescription", ""), { color_name : device_resources + "/" + device_dict.get("UTTypeIconFile", "")}, device_dict.get("UTTypeIdentifier", ""), model_ids, model_codes)) 79 | 80 | def color_from_icon_path(icon_path): 81 | if any(color in icon_path for color in ["black", "3b3b3c"]): 82 | return "Black" 83 | elif any(color in icon_path for color in ["white", "e1e4e3", "f5f4f7"]): 84 | return "White" 85 | elif any(color in icon_path for color in ["e4c1b9"]): 86 | return "Rose Gold" 87 | elif any(color in icon_path for color in ["e1ccb5", "e1ccb7", "d4c5b3"]): 88 | return "Gold" 89 | elif any(color in icon_path for color in ["dadcdb", "d7d9d8"]): 90 | return "Silver" 91 | elif any(color in icon_path for color in ["b4b5b9", "b9b7ba", "99989b"]): 92 | return "Space Grey" 93 | elif any(color in icon_path for color in ["faf189"]): 94 | return "Yellow" 95 | elif any(color in icon_path for color in ["fe767a"]): 96 | return "Pink" 97 | elif any(color in icon_path for color in ["a1e877"]): 98 | return "Green" 99 | elif any(color in icon_path for color in ["46abe0"]): 100 | return "Blue" 101 | else: 102 | return "" 103 | 104 | def main(argv): 105 | 106 | # Parse input arguments 107 | parser = argparse.ArgumentParser() 108 | parser.add_argument('-c', '--modelcode', type=str) 109 | parser.add_argument('-i', '--icon', action='store_true') 110 | parser.add_argument('-l', '--list', action='store_true') 111 | parser.add_argument('-m', '--modelid', type=str) 112 | parser.add_argument('-n', '--name', action='store_true') 113 | args = parser.parse_args() 114 | 115 | # Generate list of devices 116 | get_devices() 117 | 118 | # If option '-m' (Model ID) or '-c' (Model Code) is passed, only print info for that model 119 | if args.modelid or args.modelcode: 120 | 121 | found_devices = [] 122 | 123 | # Add all devices matching passed id or code 124 | for device in devices: 125 | if args.modelid: 126 | if args.modelid.lower() in (model_id.lower() for model_id in device.model_ids ): 127 | found_devices.append(device) 128 | elif args.modelcode: 129 | if args.modelcode.lower() in (model_code.lower() for model_code in device.model_codes ): 130 | found_devices.append(device) 131 | 132 | # Loop through all matched devices and print their info 133 | if found_devices: 134 | for idx, device in enumerate(found_devices): 135 | 136 | # If option '-n' (Marketing Name) was used with a modelid or modelcode, only print the marketing name(s) 137 | if args.name is True: 138 | print device.marketing_name 139 | break 140 | 141 | # If option '-i' (Icon) was used with a modelid or modelcode, only print the icon path(s) 142 | elif args.icon is True: 143 | for key in device.model_icons: 144 | print "[" + key + "]: " + device.model_icons[key] 145 | break 146 | 147 | # If no special option except model id or model code was passed, print all info for found devices 148 | else: 149 | if idx == 0 and 1 < len(found_devices): 150 | print '-' * 17 151 | 152 | # Markting Name 153 | print '%18s' % "Marketing Name: " + device.marketing_name 154 | 155 | # Model IDs 156 | print '%18s' % "Model IDs: " + ', '.join(device.model_ids) 157 | 158 | # Model Codes 159 | if device.device_type is "mobile": 160 | print '%18s' % "Model Codes: " + ', '.join(device.model_codes) 161 | 162 | # Type Identifier 163 | print '%18s' % "Type Identifier: " + device.model_type_identifier 164 | 165 | # Model Icons 166 | for cidx, key in enumerate(device.model_icons): 167 | if cidx == 0: 168 | print '%18s' % "Model Icons: [" + key + "]: " + device.model_icons[key] 169 | else: 170 | print '%18s' % "[" + key + "]: " + device.model_icons[key] 171 | 172 | if 1 < len(found_devices): 173 | print '-' * 17 174 | 175 | # If no device was found, print error 176 | else: 177 | if args.modelid: 178 | print >> sys.stderr, "No device with model identifier: " + args.modelid + " was found" 179 | elif args.modelcode: 180 | print >> sys.stderr, "No device with model code: " + args.modelcode + " was found" 181 | 182 | # If option '-l' us used, print all devices and their "Marketing Name" 183 | elif args.list: 184 | unique_devices = [] 185 | for device in devices: 186 | if ', '.join(device.model_ids) + " = " + device.marketing_name not in unique_devices: 187 | unique_devices.append(', '.join(device.model_ids) + " = " + device.marketing_name) 188 | print("\n".join(sorted(unique_devices))) 189 | 190 | if __name__ == "__main__": 191 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /tools/osxImageModifier/README.md: -------------------------------------------------------------------------------- 1 | ## osxImageModifier 2 | 3 | -------------------------------------------------------------------------------- /tools/osxImageModifier/osxImageModifier: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### USAGE 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Usage: ./osxImageModifier [options] ... 22 | # 23 | # Options: 24 | # -i (Optional) Input directory to search for os x images 25 | # -o (Optional) Output directory 26 | # -s Script path 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### VARIABLES 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | redirect_out="1> /dev/null" 35 | 36 | #////////////////////////////////////////////////////////////////////////////////////////////////// 37 | ### 38 | ### FUNCIONS 39 | ### 40 | #////////////////////////////////////////////////////////////////////////////////////////////////// 41 | 42 | parse_opts() { 43 | while getopts "i:o:s:" opt; do 44 | case ${opt} in 45 | i) input_directory="${OPTARG%/}" ;; 46 | o) output_directory="${OPTARG%/}" ;; 47 | s) path_script="${OPTARG%/}" ;; 48 | \?) usage; exit 1;; 49 | :) usage; exit 1;; 50 | esac 51 | done 52 | 53 | if [[ -z ${input_directory} ]]; then 54 | input_directory="${PWD}" 55 | elif ! [[ -d ${input_directory} ]]; then 56 | error "${input_directory} is not a directory" 57 | fi 58 | 59 | printf "%s\n" "Input directory: ${input_directory}" 60 | 61 | if [[ -z ${output_directory} ]]; then 62 | output_directory="${input_directory}" 63 | elif ! [[ -d ${output_directory} ]]; then 64 | error "${output_directory} is not a directory" 65 | fi 66 | 67 | printf "%s\n" "Output directory: ${output_directory}" 68 | 69 | if [[ -z ${path_script} ]]; then 70 | usage; exit 1 71 | elif ! [[ -f ${path_script} ]]; then 72 | error "${path_script}: No such file or directory." 73 | fi 74 | } 75 | 76 | usage() { 77 | printf "%s\n" "Usage: ./${0##*/} [options] ..." 78 | printf "%s\n" "Options:" 79 | printf " %s\t%s\n" "-i" "(Optional) Input directory" 80 | printf " %s\t%s\n" "-i" "(Optional) Output directory" 81 | printf " %s\t%s\n" "-s" "Script to run" 82 | printf "\n" 83 | } 84 | 85 | error() { 86 | printf "%s\n" "${1}, exiting script..." >&2; exit 1 87 | } 88 | 89 | #////////////////////////////////////////////////////////////////////////////////////////////////// 90 | ### 91 | ### MAIN SCRIPT 92 | ### 93 | #////////////////////////////////////////////////////////////////////////////////////////////////// 94 | 95 | # Verify script is run with administrator privileges 96 | if [[ ${EUID} -ne 0 ]]; then 97 | error "This script must be run as root!" 98 | fi 99 | 100 | # Stop globbing from printing itself if there are no matches 101 | shopt -s nullglob 102 | 103 | # Parse passed arguments 104 | parse_opts "${@}" 105 | 106 | # Loop through all images and modify them if needed 107 | for osx_image in "${input_directory}"/*\.dmg; do 108 | 109 | # Reset variables 110 | osx_image_add_recovery="False" 111 | osx_image_modified="False" 112 | osx_image_recreate="False" 113 | osx_image_convert="False" 114 | osx_image_scan="False" 115 | 116 | printf "%s\n" "Checking ${osx_image##*/}..." 117 | 118 | # If image is already mounted, exit script and print it's current mountpoint. 119 | # FIXME - This check should allow the script to use the mounted path instead of skipping, but for now just skip. 120 | osx_image_mountpoint=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='image-path']/following-sibling::string[1][contains(., \"${osx_image}\")]/../key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string/text()" 2>/dev/null ) 121 | if [[ -d ${osx_image_mountpoint} ]]; then 122 | printf "%s\n" "${osx_image##*/} is already mounted at: ${osx_image_mountpoint}, skipping" >&2 123 | continue 124 | fi 125 | 126 | # Create mountpoint for image 127 | osx_image_mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create image mountpoint" 128 | osx_image_shadow="/private/tmp/shadow.$( env LC_CTYPE=C tr -dc "a-zA-Z0-9-_\$\?" < /dev/urandom | head -c 5 )" 129 | 130 | # Attach current dmg at 'osx_image_mountpoint' 131 | if hdiutil attach "${osx_image}" -noverify -nobrowse -readwrite -owners on -mountpoint "${osx_image_mountpoint}" -shadow "${osx_image_shadow}" ; then 132 | 133 | # Add dmg mountpoint to mountpoints to remove after checking has finished 134 | mountpoints+=( "${osx_image_mountpoint}" ) 135 | 136 | # Verify SystemVersion.plist exists 137 | systemversion_path="${osx_image_mountpoint}/System/Library/CoreServices/SystemVersion.plist" 138 | if [[ -d ${osx_image_mountpoint} ]] && [[ -f ${systemversion_path} ]]; then 139 | 140 | # Get os build and version 141 | os_version=$( /usr/libexec/PlistBuddy -c "Print :ProductUserVisibleVersion" "${systemversion_path}" ) 142 | printf "%s\n" "OS Version: ${os_version}" 143 | 144 | os_build_version=$( /usr/libexec/PlistBuddy -c "Print :ProductBuildVersion" "${systemversion_path}" ) 145 | printf "%s\n" "OS Build: ${os_build_version}" 146 | else 147 | printf "%s\n" "SystemVersion.plist not found inside ${osx_image}, skipping image..." >&2 148 | continue 149 | fi 150 | 151 | # Prepare image output name and path 152 | osx_image_name=$( basename "${osx_image}" ) 153 | if [[ ${input_directory} == ${output_directory} ]]; then 154 | osx_image_output_path="${output_directory}/$( sed -E "s/(\.hfs\.dmg|\.dmg)/_$( date +%F_%H%M%S ).hfs.dmg/" <<< ${osx_image_name} )" 155 | else 156 | osx_image_output_path="${output_directory}/${osx_image_name}" 157 | fi 158 | osx_image_output_name=$( basename "${osx_image_output_path}" ) 159 | 160 | # Run the passed script 161 | printf "%s\n" "Running script: ${path_script##*/}" 162 | source "${path_script}" 163 | 164 | # Get size for disk image 165 | osx_image_size=$( df "${osx_image_mountpoint}" | awk -v mountpoint="${osx_image_mountpoint}" '{ if ($9 == mountpoint ) print $2; }' ) 166 | if [[ ${osx_image_size} =~ ^[0-9]+$ ]]; then 167 | printf "%s\n" "Volume size (bytes): $((${osx_image_size}*512))" 168 | else 169 | printf "%s\n" "Volume size returned for volume at path: ${osx_image_mountpoint} is not valid!" >&2 170 | continue 171 | fi 172 | 173 | # Get used size for disk image 174 | osx_image_size_used=$( df "${osx_image_mountpoint}" | awk -v mountpoint="${osx_image_mountpoint}" '{ if ($9 == mountpoint ) print $3; }' ) 175 | if [[ ${osx_image_size_used} =~ ^[0-9]+$ ]]; then 176 | printf "%s\n" "Volume size used (bytes): $((${osx_image_size_used}*512))" 177 | else 178 | printf "%s\n" "Volume size used returned for volume at path: ${osx_image_mountpoint} is not valid!" >&2 179 | continue 180 | fi 181 | 182 | if [[ ${osx_image_recreate} == True ]]; then 183 | printf "%s\n" "Recreating image to use GUID partition scheme..." 184 | 185 | # Update values for osx_image as this will be the new target from here on 186 | osx_image="$( dirname "${osx_image_output_path}" )/$( sed -E 's/(\.hfs\.dmg|\.dmg)/_GUID.hfs.sparsebundle/' <<< ${osx_image_output_name} )" 187 | 188 | # Add the size of a recovery partition (or if that's missing, 1GB (2097152 512-byte sectors)) to allow adding a recovery partiton 189 | if ! hdiutil create -srcfolder "${osx_image_mountpoint}" -sectors $((${osx_image_size_used}+2097152)) -volname "Macintosh HD" -format UDSB -layout GPTSPUD "${osx_image}" ; then 190 | printf "%s\n" "Recreating image mounted at: ${osx_image_mountpoint} failed" >&2 191 | continue 192 | fi 193 | 194 | exit 1 195 | 196 | # Remove free space 197 | #if ! hdiutil compact "${osx_image}"; then 198 | # printf "%s\n" "Removing free space from image: ${osx_image} failed" >&2 199 | # continue 200 | #fi 201 | 202 | osx_image_mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create image mountpoint" 203 | 204 | # Attach the newly created disk image 205 | if ! hdiutil attach "${osx_image}" -noverify -nobrowse -readwrite -owners on -mountpoint "${osx_image_mountpoint}" ; then 206 | printf "%s\n" "Attaching: ${osx_image} failed" >&2 207 | continue 208 | fi 209 | 210 | # Add dmg mountpoint to mountpoints to remove after checking has finished 211 | mountpoints+=( "${osx_image_mountpoint}" ) 212 | 213 | # Set to add recovery partition 214 | osx_image_add_recovery='True' 215 | osx_image_convert='True' 216 | fi 217 | 218 | if [[ ${osx_image_add_recovery} == True ]]; then 219 | printf "%s\n" "Adding recovery partition..." 220 | 221 | # Verify recovery image path is set and valid 222 | if ! [[ -f ${recovery_image} ]]; then 223 | printf "%s\n" "Recovery Image: ${recovery_image} NOT found!" >&2 224 | continue 225 | fi 226 | 227 | # Verify the recovery source image have a recovery partition 228 | # FIXME - This requires that no volume from 'recovery_image' is mounted, possibly check for that or use diskutil if mounted 229 | if ! (( $( hdiutil pmap "${recovery_image}" | awk '/Apple_Boot/ || /Recovery HD/ { print 1 }' ) )); then 230 | printf "%s\n" "Source disk image: ${recovery_image##*/} have NO recovery partition!" >&2 231 | fi 232 | 233 | recovery_image_mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create recovery image mountpoint" 234 | 235 | # Attach the recovery source image 236 | if ! hdiutil attach "${recovery_image}" -noverify -nobrowse -readonly -owners on -mountpoint "${recovery_image_mountpoint}"; then 237 | printf "%s\n" "Attaching: ${recovery_image##*/} failed" >&2 238 | continue 239 | fi 240 | 241 | # Add dmg mountpoint to mountpoints to remove after checking has finished 242 | mountpoints+=( "${recovery_image_mountpoint}" ) 243 | 244 | # Get the recovery hd device identifier 245 | recovery_image_volume_device_identifier="$( diskutil list "${recovery_image_mountpoint}" | awk '/Apple_Boot/ || /Recovery HD/ { print $NF }' )" 246 | 247 | # Get the image system volume device node 248 | osx_image_volume_device_node=$( diskutil info "${osx_image_mountpoint}" | awk '/Device Node:/ { print $NF }' ) 249 | 250 | # Add dmg mountpoint to mountpoints to remove after checking has finished 251 | mountpoints+=( "${osx_image_volume_device_node}" ) 252 | 253 | # Resize the image system volume to fit recovery partition 254 | # FIXME - This assumes the disk has free space for the recovery partition, should check 255 | if ! diskutil quiet resizeVolume "${osx_image_volume_device_node}" "${osx_image_size_used}S" JHFS+ EmptyRecoveryHD 1m; then 256 | printf "%s\n" "Resizing volume at device node: ${osx_image_volume_device_node} failed" >&2 257 | continue 258 | fi 259 | 260 | # Get the new image recovery volume device identifier 261 | osx_recovery_image_volume_device_identifier="$( diskutil list "${osx_image_volume_device_node}" | awk '/EmptyRecoveryHD/ { print $NF }' )" 262 | 263 | if [[ ${recovery_image_volume_device_identifier} =~ disk ]] && [[ ${osx_recovery_image_volume_device_identifier} =~ disk ]]; then 264 | printf "%s\n" "Restoring source recovery partition on disk image..." 265 | 266 | # Restore recovery partition from source image to os x image 267 | if ! asr restoreexact --source "/dev/${recovery_image_volume_device_identifier}" --target "/dev/${osx_recovery_image_volume_device_identifier}" --erase --noprompt; then 268 | printf "%s\n" "Restoring source recovery partition failed!" 269 | continue 270 | fi 271 | else 272 | printf "%s\n" "A device identifier could not be found!" >&2 273 | printf "%s\n" "recovery_image_volume_device_identifier=${recovery_image_volume_device_identifier}" >&2 274 | printf "%s\n" "osx_recovery_image_volume_device_identifier=${osx_recovery_image_volume_device_identifier}" >&2 275 | exit 1 276 | fi 277 | osx_image_convert='True' 278 | fi 279 | 280 | # Detach mounted dmgs 281 | printf "%s\n" "Unmounting volumes at mountpoints: ${mountpoints[@]}" 282 | for mountpoint in "${mountpoints[@]}"; do 283 | 284 | if ! hdiutil detach "${mountpoint}" -force ; then 285 | printf "%s\n" "Detaching image mounted at: ${mountpoint} failed" >&2 286 | mountpoint="/Volumes/$( basename "${mountpoint}" )" 287 | else 288 | rm -rf "${mountpoint}" || printf "%s\n" "Removing mountpoint folder: ${mountpoint} failed!" >&2 289 | continue 290 | fi 291 | 292 | # Try again 293 | if ! hdiutil detach "${mountpoint}" -force ; then 294 | printf "%s\n" "Detaching image mounted at: ${mountpoint} failed" >&2 295 | else 296 | rm -rf "${mountpoint}" || printf "%s\n" "Removing mountpoint folder: ${mountpoint} failed!" >&2 297 | continue 298 | fi 299 | done 300 | 301 | # If image was modified, write shadow data into dmg 302 | if [[ ${osx_image_recreate} != True ]] && [[ ${osx_image_modified} == True ]]; then 303 | printf "%s\n" "Converting image and shadow to output: ${osx_image_output_path}..." 304 | if ! hdiutil convert -format UDZO -o "${osx_image_output_path}" "${osx_image}" -shadow "${osx_image_shadow}" ; then 305 | printf "%s\n" "Converting image and shadow failed!" 306 | continue 307 | fi 308 | osx_image_scan='True' 309 | osx_image_convert='False' 310 | fi 311 | 312 | # Convert to UDZO 313 | if [[ ${osx_image_convert} == True ]]; then 314 | printf "%s\n" "Converting image to output: ${osx_image_output_path}..." 315 | if ! hdiutil convert -format UDZO -o "${osx_image_output_path}" "${osx_image}" ; then 316 | printf "%s\n" "Converting image and shadow failed!" 317 | continue 318 | fi 319 | osx_image_scan='True' 320 | fi 321 | 322 | # Scan image for restore 323 | if [[ ${osx_image_scan} == True ]]; then 324 | printf "%s\n" "Scanning image for restore..." 325 | if ! asr imagescan --source "${osx_image_output_path:-${osx_image}}" ; then 326 | printf "%s\n" "Scanning image for restore failed!" 327 | exit 1 328 | fi 329 | fi 330 | else 331 | error "Attaching: ${osx_image} failed" 332 | fi 333 | 334 | # Remove temporary images created (GUID) 335 | for guid_image in "${output_directory}"/*_GUID\.hfs\.dmg; do 336 | rm -rf "${guid_image}" 337 | done 338 | 339 | # Remove temporary image mountpoint if still exists 340 | if [[ -f ${osx_image_mountpoint} ]]; then 341 | rm -rf "${osx_image_mountpoint}" || printf "%s\n" "Removing folder: ${osx_image_mountpoint} failed!" >&2 342 | fi 343 | 344 | # Remove temporary shadow file if still exists 345 | if [[ -f ${osx_image_shadow} ]]; then 346 | rm -rf "${osx_image_shadow}" || printf "%s\n" "Removing folder: ${osx_image_shadow} failed!" >&2 347 | fi 348 | done 349 | 350 | # Restore globbing behaviour. 351 | shopt -u nullglob 352 | 353 | exit 0 -------------------------------------------------------------------------------- /tools/osxImageModifier/osxImageModifierScript.bash: -------------------------------------------------------------------------------- 1 | # 2 | # VARIABLES 3 | # 4 | # The following variables are available to this script: 5 | # 6 | # osx_image Path to dmg 7 | # osx_image_mountpoint Path to dmg r/w mounted volume 8 | # os_version OS Version 9 | # os_build_version OS Build 10 | 11 | # If any modification was done, remember to set the variable osx_image_modified to True 12 | # Else the script won't write the updated image to output folder. 13 | 14 | # Input Variables 15 | #osx_image - Path to the disk image to modify 16 | #osx_image_mountpoint - Path to the disk image mountpoint 17 | 18 | # Static Variables 19 | #osx_image_add_recovery="False|True" 20 | #osx_image_modified="False|True" 21 | #osx_image_recreate="False|True" 22 | #osx_image_convert="False|True" 23 | #osx_image_scan="False|True" 24 | 25 | # 26 | # MAIN SCRIPT 27 | # 28 | 29 | # 30 | # Verify image format is 'UDZO', else convert it 31 | # 32 | if [[ $( hdiutil imageinfo "${osx_image}" | awk '/Format:/ { print $NF }' ) != UDZO ]]; then 33 | osx_image_convert='True' 34 | fi 35 | 36 | # 37 | # Verify image partition scheme is 'GUID', else recreate image 38 | # 39 | if [[ $( hdiutil imageinfo "${osx_image}" | awk '/partition-scheme:/ { print $NF }' ) != GUID ]]; then 40 | osx_image_recreate='True' 41 | fi 42 | 43 | # 44 | # Verify /var/db/.AppleSetupDone exists 45 | # 46 | if ! [[ -f "${osx_image_mountpoint}/var/db/.AppleSetupDone" ]]; then 47 | if touch "${osx_image_mountpoint}/var/db/.AppleSetupDone"; then 48 | osx_image_modified='True' 49 | printf "%s\n" "Added: .AppleSetupDone" 50 | fi 51 | elif [[ -f "${osx_image_mountpoint}/var/db/.AppleSetupDone" ]]; then 52 | if rm -f "${osx_image_mountpoint}/var/db/.AppleSetupDone"; then 53 | osx_image_modified='True' 54 | printf "%s\n" "Deleted: .AppleSetupDone" 55 | fi 56 | else 57 | printf "%s\n" "Verified .AppleSetupDone did not exist!" 58 | fi 59 | 60 | # 61 | # Remove /var/db/.RunLanguageChooserToo if it exists 62 | # 63 | if [[ -f "${osx_image_mountpoint}/var/db/.RunLanguageChooserToo" ]]; then 64 | if rm -f "${osx_image_mountpoint}/var/db/.RunLanguageChooserToo"; then 65 | osx_image_modified='True' 66 | printf "%s\n" "Deleted .RunLanguageChooserToo" 67 | fi 68 | else 69 | printf "%s\n" "Verified .RunLanguageChooserToo did not exist!" 70 | fi 71 | 72 | # 73 | # Check if image has a recovery partition 74 | # 75 | if (( $( hdiutil pmap "${osx_image}" | awk '/Apple_Boot/ || /Recovery HD/ { print 1 }' ) )); then 76 | osx_image_has_recovery='YES' 77 | else 78 | osx_image_has_recovery='NO' 79 | osx_image_add_recovery='True' 80 | 81 | # ****** IMPORTANT ****** 82 | # Set this variable to a path with a disk image containing a recovery partition you would like to add to the current disk image. 83 | # *********************** 84 | recovery_image="" 85 | if [[ -z ${recovery_image} ]]; then 86 | printf "%s\n" "**** ERROR ****" 87 | printf "%s\n" "No path was defined for a disk image containing the recovery partition you want to add" 88 | exit 1 89 | fi 90 | fi 91 | printf "%s\n" "Has Recovery: ${osx_image_has_recovery}" 92 | 93 | # 94 | # Check if image is imagescanned 95 | # 96 | udif_ordered_chunks=$( /usr/libexec/PlistBuddy -c "Print udif-ordered-chunks" /dev/stdin <<< $( hdiutil imageinfo "${osx_image}" -plist ) ) 97 | if [[ ${udif_ordered_chunks} != true ]]; then 98 | osx_image_scan='True' 99 | printf "%s\n" "Image have NOT been imagescanned!" 100 | else 101 | printf "%s\n" "Image is already imagescanned!" 102 | fi 103 | 104 | # 105 | # Remove user(s) 106 | # 107 | </dev/null 2>/dev/null; then 112 | printf "%s\n" "User ${user} exists, removing..." 113 | user_database_path="/Local/Default/Users/${user}" 114 | user_home_folder="${osx_image_mountpoint}/$( dscl -f "${image_node_path}" localonly read "${user_database_path}" NFSHomeDirectory | awk -F': ' '{ print $2 }' )" 115 | if [[ ${user_home_folder} != ${osx_image_mountpoint} ]] && [[ -d ${user_home_folder} ]]; then 116 | printf "%s\n" "Deleting user home folder at: ${user_home_folder}..." 117 | if rm -rf "${user_home_folder}"; then 118 | osx_image_modified='True' 119 | printf "%s\n" "Deleted: ${user_home_folder}" 120 | fi 121 | fi 122 | 123 | printf "%s\n" "Deleting user record from database..." 124 | if dscl -f "${image_node_path}" localonly delete "${user_database_path}"; then 125 | osx_image_modified='True' 126 | printf "%s\n" "Deleted user record!" 127 | else 128 | printf "%s\n" "Deleting user record FAILED!" 129 | exit 1 130 | fi 131 | else 132 | printf "%s\n" "User ${user} does NOT exist!" 133 | fi 134 | done 135 | COMMENT 136 | 137 | # 138 | # Check version of Application 139 | # 140 | <&1 ) 145 | printf "%s\n" "${application_name} Version: ${application_version}" 146 | 147 | if [[ ${application_version} =~ ^11 ]]; then 148 | printf "%s\n" "Removing incorrect version..." 149 | if ! rm -rf "${application_path}"; then 150 | printf "%s\n" "Removing ${application_path} failed!" 151 | exit 1 152 | fi 153 | 154 | printf "%s\n" "Copying correct version..." 155 | application_local_path="/Volumes/Seagate/BTSync/Academedia/Applications_Projects/TeamViewer_QuickSupport/Applications/TeamViewerQS.app" 156 | if ! cp -R "${application_local_path}" "${application_path}"; then 157 | printf "%s\n" "Copying ${application_local_path} failed!" 158 | exit 1 159 | fi 160 | 161 | osx_image_modified='True' 162 | fi 163 | else 164 | printf "%s\n" "${application_path}: No such file or directory" 165 | fi 166 | COMMENT 167 | 168 | # Print if image was modified (and requires saving) 169 | printf "%s\n" "Image Modified: ${osx_image_modified:-False}" 170 | printf "%s\n" "Image Add Recovery: ${osx_image_add_recovery:-False}" 171 | printf "%s\n" "Image Recreate: ${osx_image_recreate:-False}" 172 | printf "%s\n" "Image Convert: ${osx_image_convert:-False}" 173 | printf "%s\n" "Image Imagescanned: ${osx_image_scan:-False}" -------------------------------------------------------------------------------- /tools/osxInstallerArchiver/README.md: -------------------------------------------------------------------------------- 1 | ## osxInstallerArchiver 2 | 3 | -------------------------------------------------------------------------------- /tools/osxInstallerArchiver/osxInstallerArchiver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Create disk images from OS X Installer applications (for archiving) 14 | 15 | # Specify a folder containing OS X Installer Applications with the '-i' option. 16 | # Scrip will create a dmg and put the OS X Installer inside. 17 | # Output folder can be specified with the '-o' option, else current working direcotry will be used. 18 | # Using the '-a' option will call mdfind to find all installer application on disk. 19 | 20 | # Only works with "Mac App Store" OS X installer applications (10.7+) 21 | 22 | #////////////////////////////////////////////////////////////////////////////////////////////////// 23 | ### 24 | ### USAGE 25 | ### 26 | #////////////////////////////////////////////////////////////////////////////////////////////////// 27 | 28 | # Usage: ./osxInstallerArchiver [options] ... 29 | # 30 | # Options: 31 | # -a (Optional) Find and archive all installers on system (ignores -i option) 32 | # -i (Optional) Input directory to search for installers 33 | # -o (Optional) Output directory for archives (defaults to working directory) 34 | # -u (Optional) Uploads all dmgs created to ftp and delete local dmg copy on success (ignores -o option) 35 | 36 | #////////////////////////////////////////////////////////////////////////////////////////////////// 37 | ### 38 | ### VARIABLES 39 | ### 40 | #////////////////////////////////////////////////////////////////////////////////////////////////// 41 | 42 | ftp_server="" 43 | ftp_user="" 44 | ftp_pass="" 45 | 46 | #////////////////////////////////////////////////////////////////////////////////////////////////// 47 | ### 48 | ### FUNCIONS 49 | ### 50 | #////////////////////////////////////////////////////////////////////////////////////////////////// 51 | 52 | parse_opts() { 53 | while getopts "adi:o:u" opt; do 54 | case ${opt} in 55 | a) search_applications='True' ;; 56 | d) include_developer_previews='True' ;; 57 | i) input_directory="${OPTARG%/}" ;; 58 | o) output_directory="${OPTARG%/}" ;; 59 | u) upload='True' ;; 60 | \?) usage; exit 1;; 61 | :) usage; exit 1;; 62 | esac 63 | done 64 | 65 | # Check 'output_directory' options, set to 'PWD' if none was passed. 66 | if [[ ${upload} == True ]]; then 67 | output_directory="/tmp" 68 | elif [[ -z ${output_directory} ]]; then 69 | output_directory="${PWD}" 70 | elif ! [[ -d ${output_directory} ]]; then 71 | error "${output_directory} is not a directory" 72 | fi 73 | 74 | printf "%s\n" "Output directory: ${output_directory}" 75 | 76 | # Check if current user has write capabilities for output_directory 77 | if ! [[ -w ${output_directory} ]]; then 78 | error "User: ${USER} doesn't have write permissions for output folder: ${output_directory}" 79 | fi 80 | 81 | # Check if option '-a' was passed, then use mdfind to find all installers matching bundle id wildcard search: 'com.apple.InstallAssistant.*' 82 | if [[ ${search_applications} == True ]]; then 83 | old_ifs="${IFS}"; IFS=$'\n' 84 | osx_installers=( $( mdfind "kMDItemCFBundleIdentifier == 'com.apple.InstallAssistant.*'c && kMDItemContentType=com.apple.application-bundle" ) ) 85 | IFS="${old_ifs}" 86 | fi 87 | 88 | if [[ ${search_applications} != True ]] || (( ${#osx_installers[@]} == 0 )); then 89 | # Check 'input_directory' options, set to '/Applications' if non was passed. 90 | if [[ -z ${input_directory} ]]; then 91 | input_directory="/Applications" 92 | elif ! [[ -d ${input_directory} ]]; then 93 | error "${input_directory} is not a directory" 94 | fi 95 | 96 | printf "%s\n" "Input directory: ${input_directory}" 97 | 98 | # Add all OS X Installer Applications passing test to array 'osx_installers' 99 | for app in "${input_directory}"/*\.app/; do 100 | if [[ -f "${app}/Contents/Info.plist" ]] && [[ "$( /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${app}/Contents/Info.plist" )" =~ ^com.apple.InstallAssistant.* ]]; then 101 | osx_installers+=( "${app%/}" ) 102 | fi 103 | done 104 | fi 105 | 106 | } 107 | 108 | usage() { 109 | printf "%s\n" "Usage: ./${0##*/} [options] ..." 110 | printf "%s\n" "Options:" 111 | printf " %s\t%s\n" "-a" "(Optional) All installer applications on computer (uses mdfind)" 112 | printf " %s\t%s\n" "-i" "(Optional) Input directory" 113 | printf " %s\t%s\n" "-o" "(Optional) Output directory" 114 | printf "\n" 115 | } 116 | 117 | error() { 118 | printf "%s\n" "${1}, exiting script..." >&2; exit 1 119 | } 120 | 121 | check_upload_status() { 122 | if [[ $( /usr/bin/curl --connect-timeout 30 --retry 3 -l -u "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}" 2>&1 | grep -E ^${1}$ ) == ${1} ]]; then 123 | printf "%s" "exists" 124 | else 125 | printf "%s" "no" 126 | fi 127 | } 128 | 129 | upload_dmg() { 130 | curl_output=$( curl --connect-timeout 30 --retry 3 -S -T "${1}" -u "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}/" 2>&1 ) 131 | if [[ ${?} -ne 0 ]]; then 132 | error "Upload of file ${1} to server ${ftp_server} failed with error: "${curl_output}"" 133 | fi 134 | } 135 | 136 | #////////////////////////////////////////////////////////////////////////////////////////////////// 137 | ### 138 | ### MAIN SCRIPT 139 | ### 140 | #////////////////////////////////////////////////////////////////////////////////////////////////// 141 | 142 | # Stop globbing from printing itself if there are no matches 143 | shopt -s nullglob 144 | 145 | # Parse passed arguments 146 | parse_opts "${@}" 147 | 148 | printf "%s\n" "Found the following OS X Installer Applications:" 149 | printf "%s\n" "${osx_installers[@]}" 150 | 151 | declare -a osx_installer_dmgs 152 | 153 | # Loop through all installers and create dmg in output directory 154 | for osx_installer in "${osx_installers[@]}"; do 155 | 156 | printf "%s\n" "Checking ${osx_installer}..." 157 | 158 | # Verify InstallESD.dmg exists 159 | if [[ ! -f ${osx_installer}/Contents/SharedSupport/InstallESD.dmg ]]; then 160 | printf "%s\n" "${osx_installer}/Contents/SharedSupport/InstallESD.dmg, no such file or directory" >&2 161 | continue 162 | fi 163 | 164 | # Ingore developer preview installers in include_developer_previews='True' 165 | if [[ ${include_developer_previews} != True ]]; then 166 | application_bundle_identifier=$( /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${osx_installer}/Contents/Info.plist" 2>&1 ) 167 | if [[ ${application_bundle_identifier} =~ [Ss]eed ]]; then 168 | printf "%s\n" "${osx_installer} is a developer preview, skipping..." >&2 169 | continue 170 | fi 171 | fi 172 | 173 | # Get installer name 174 | installer_name=$( /usr/libexec/PlistBuddy -c "Print :CFBundleDisplayName" "${osx_installer}/Contents/Info.plist" ) 175 | 176 | # If InstallESD.dmg is already mounted, exit script and print it's current mountpoint. 177 | # FIXME - This check should allow the script to use the mounted path instead of skipping, but for now just skip. 178 | install_esd_mountpoint=$( hdiutil info -plist | xpath "/plist/dict/key[.='images']/following-sibling::array/dict/key[.='image-path']/following-sibling::string[1][contains(., \"${osx_installer}/Contents/SharedSupport/InstallESD.dmg\")]/../key[.='system-entities']/following-sibling::array/dict/key[.='mount-point']/following-sibling::string/text()" 2>/dev/null ) 179 | if [[ -n ${install_esd_mountpoint} ]]; then 180 | printf "%s\n" "${osx_installer}/Contents/SharedSupport/InstallESD.dmg is already mounted at: ${install_esd_mountpoint}, skipping" >&2 181 | continue 182 | fi 183 | 184 | # Create mountpoint for InstallESD.dmg 185 | install_esd_mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create InstallESD mountpoint" 186 | 187 | # Attach current dmg at 'install_esd_mountpoint' 188 | if hdiutil attach "${osx_installer}/Contents/SharedSupport/InstallESD.dmg" -noverify -nobrowse -readonly -owners on -mountpoint "${install_esd_mountpoint}" 1> /dev/null; then 189 | 190 | # Add InstallESD mountpoint to mountpoints to remove after checking has finished 191 | mountpoints=( "${install_esd_mountpoint}" ) 192 | 193 | if [[ -f ${install_esd_mountpoint}/BaseSystem.dmg ]]; then 194 | 195 | # Create mountpoint for BaseSystem.dmg 196 | base_system_mountpoint=$( mktemp -d /private/tmp/dmg.XXXXX ) || error "Unable to create BaseSystem mountpoint" 197 | 198 | # Attach BaseSystem.dmg at 'base_system_mountpoint' 199 | if hdiutil attach "${install_esd_mountpoint}/BaseSystem.dmg" -noverify -nobrowse -readonly -owners on -mountpoint "${base_system_mountpoint}" 1> /dev/null; then 200 | 201 | # Add mountpoint to mountpoints to remove after checking has finished 202 | mountpoints+=( "${base_system_mountpoint}" ) 203 | 204 | if [[ -f ${base_system_mountpoint}/System/Library/CoreServices/SystemVersion.plist ]]; then 205 | systemversion_path="${base_system_mountpoint}/System/Library/CoreServices/SystemVersion.plist" 206 | fi 207 | else 208 | error "Attach ${install_esd_mountpoint}/BaseSystem.dmg failed" 209 | fi 210 | else 211 | systemversion_path="${install_esd_mountpoint}/System/Library/CoreServices/SystemVersion.plist" 212 | fi 213 | 214 | # Verify SystemVersion.plist exists 215 | if [[ -f ${systemversion_path} ]]; then 216 | 217 | # Get installer os build and version 218 | installer_os_version=$( /usr/libexec/PlistBuddy -c "Print :ProductUserVisibleVersion" "${systemversion_path}" ) 219 | installer_os_build_version=$( /usr/libexec/PlistBuddy -c "Print :ProductBuildVersion" "${systemversion_path}" ) 220 | else 221 | printf "%s\n" "SystemVersion.plist not found inside ${osx_installer}/Contents/SharedSupport/InstallESD.dmg, skipping installer..." >&2 222 | continue 223 | fi 224 | 225 | # Detach mounted dmgs 226 | for mountpoint in "${mountpoints[@]}"; do 227 | if ! hdiutil detach "${mountpoint}" -force 1> /dev/null; then 228 | printf "%s\n" "Detaching image mounted at: ${mountpoint} failed" >&2 229 | rm -rf "${mountpoint}" || printf "%s\n" "Removing folder: ${mountpoint} failed!" >&2 230 | fi 231 | done 232 | else 233 | error "Attaching ${osx_installer}/Contents/SharedSupport/InstallESD.dmg failed" 234 | fi 235 | 236 | # Remove temporary InstallESD mountpoint if still exists 237 | if [[ -f ${install_esd_mountpoint} ]]; then 238 | rm -rf "${install_esd_mountpoint}" || printf "%s\n" "Removing folder: ${mountpoint} failed!" >&2 239 | fi 240 | 241 | # Assemble name for dmg file and volume 242 | name=$( sed 's/\ //g' <<< "${installer_name}_${installer_os_version}-${installer_os_build_version}" ) 243 | 244 | # Check if target dmg already exist in selected ouptut directory 245 | if [[ -f ${output_directory}/${name}.dmg ]]; then 246 | if [[ ${upload} == True ]]; then 247 | rm "${output_directory}/${name}.dmg" 248 | else 249 | printf "%s\n" "File: ${output_directory}/${name} already exist, skipping..." >&2 250 | continue 251 | fi 252 | fi 253 | 254 | if [[ ${upload} == True ]] && [[ $( check_upload_status "${name}.dmg" ) == exists ]]; then 255 | printf "%s\n" "File: ${name}.dmg already exist on the FTP, skipping..." >&2 256 | continue 257 | fi 258 | 259 | # Remove quarantine attribute if present 260 | xattr -d -r com.apple.quarantine "${osx_installer}" > /dev/null 2>&1 261 | 262 | # Create installer dmg archive 263 | printf "%s\n" "Creating ${output_directory}/${name}.dmg..." 264 | if ! hdiutil create -srcfolder "${osx_installer}" -volname "${name}" "${output_directory}/${name}" 1> /dev/null; then 265 | error "Creating ${output_directory}/${name}.dmg failed" 266 | fi 267 | 268 | osx_installer_dmgs+=( "${output_directory}/${name}.dmg" ) 269 | 270 | if [[ ${upload} == True ]]; then 271 | printf "%s\n" "Uploading ${output_directory}/${name}.dmg..." 272 | upload_dmg "${output_directory}/${name}.dmg" 273 | fi 274 | done 275 | 276 | # Remove all local dmgs if 'upload' == True 277 | if [[ ${upload} == True ]]; then 278 | for application_dmg in "${osx_installer_dmgs[@]}"; do 279 | if [[ ${application_dmg} =~ \.dmg$ ]]; then 280 | rm "${application_dmg}" 281 | else 282 | printf "%s\n" "Unknown dmg in all_application_dmgs: ${application_dmg}" 283 | fi 284 | done 285 | fi 286 | 287 | # Restore globbing behaviour. 288 | shopt -u nullglob 289 | 290 | exit 0 -------------------------------------------------------------------------------- /tools/privilegedHelperToolReset/README.md: -------------------------------------------------------------------------------- 1 | ## resetHelper 2 | 3 | -------------------------------------------------------------------------------- /tools/privilegedHelperToolReset/privilegedHelperToolReset: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script is designed to remove an installed privileged helper tool for an OS X Applicaton. 14 | # You can either define the helper to remove in this script directly, or pass an OS X Application with the -a option. 15 | 16 | #////////////////////////////////////////////////////////////////////////////////////////////////// 17 | ### 18 | ### USAGE 19 | ### 20 | #////////////////////////////////////////////////////////////////////////////////////////////////// 21 | 22 | # Usage: ./privilegedHelperToolReset.bash [options] ... 23 | # 24 | # Options: 25 | # -a (Optional) Path to application (.app) 26 | 27 | 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | ### 30 | ### VARIABLES 31 | ### 32 | #////////////////////////////////////////////////////////////////////////////////////////////////// 33 | 34 | helperLaunchdFilename="" # Example: "com.github.NBICreatorHelper.plist" 35 | helperBinaryFilename="" # Example: "com.github.NBICreatorHelper" 36 | 37 | #////////////////////////////////////////////////////////////////////////////////////////////////// 38 | ### 39 | ### STATIC VARIABLES 40 | ### 41 | #////////////////////////////////////////////////////////////////////////////////////////////////// 42 | 43 | # Setup padding for status messages 44 | paddingCharacter="." 45 | paddingLength="40" 46 | paddingString=$( printf '%0.1s' "${paddingCharacter}"{1..100} ) 47 | 48 | #////////////////////////////////////////////////////////////////////////////////////////////////// 49 | ### 50 | ### FUNCTIONS 51 | ### 52 | #////////////////////////////////////////////////////////////////////////////////////////////////// 53 | 54 | print_usage() { 55 | printf "\n%s\n\n" "Usage: ./${0##*/} [options] ..." 56 | printf "%s\n" "Options:" 57 | printf " %s\t%s\n" "-a" "(Optional) Path to application (.app)" 58 | printf "\n" 59 | } 60 | 61 | parse_command_line_options() { 62 | while getopts "a:" opt; do 63 | case ${opt} in 64 | a) path_applicationBundle="${OPTARG}";; 65 | \?) print_usage; exit 1 ;; 66 | :) print_usage; exit 1 ;; 67 | esac 68 | done 69 | } 70 | 71 | printStatusOKForMessage() { 72 | # Print padding with [OK] at the end 73 | printf '%*.*s' 0 $(( ${paddingLength} - ${#1} )) "${paddingString}" 74 | printf " [\e[1;32m%s\e[m]\n" "OK" 75 | 76 | } 77 | 78 | printStatusErrorForMessage() { 79 | # Print padding with [ERROR] at the end 80 | printf '%*.*s' 0 $(( ${paddingLength} - ${#1} )) "${paddingString}" 81 | printf " [\e[1;31m%s\e[m]\n" "ERROR" 82 | } 83 | 84 | printError() { 85 | printf "\t%s\n" "${1}" 86 | } 87 | 88 | readHelperFromApplicationBundleAtPath() { 89 | 90 | # Verify passed application bundle path not empty and ends with .app 91 | if [[ -n ${1} ]] && [[ ${1} =~ .*\.app ]]; then 92 | local path_applicationBundle="${1}" 93 | else 94 | printError "Invalid application bundle path: ${1}" 95 | exit 1 96 | fi 97 | 98 | if [[ -d ${path_applicationBundle} ]]; then 99 | 100 | plistBuddyOutput=$( /usr/libexec/PlistBuddy -x -c "Print SMPrivilegedExecutables:" "${path_applicationBundle}/Contents/Info.plist" 2>&1 ) 101 | plistBuddyExitStatus=${?} 102 | 103 | if (( ${plistBuddyExitStatus} != 0 )); then 104 | printError "Reading 'SMPrivilegedExecutables' from application bundle's Info.plist failed" 105 | printError "plistBuddyExitStatus=${plistBuddyExitStatus}" 106 | printError "plistBuddyOutput=${plistBuddyOutput}" 107 | exit 1 108 | fi 109 | 110 | # Loop through every privileged helper tool defined in application bundle's Info.plist and remove it. 111 | while read helperBinaryFilename; do 112 | 113 | printf "%s\n" "Resetting helper: ${helperBinaryFilename}..." 114 | 115 | # Currently assumes the helper launchd plist has the same name as the binary 116 | helperLaunchdFilename="${helperBinaryFilename}.plist" 117 | 118 | # Remove helper launchd plist 119 | removeHelperLaunchdPlistWithName "${helperLaunchdFilename}" 120 | 121 | # Remove helper binary 122 | removeHelperBinaryWithName "${helperBinaryFilename}" 123 | 124 | done < <( /usr/bin/sed -nE 's/(.*)<\/key>/\1/p' <<< "${plistBuddyOutput}" ) 125 | else 126 | printf "%s\n" "Application bundle at path: "${path_applicationBundle}" does not exist" 127 | exit 1 128 | fi 129 | 130 | } 131 | 132 | removeHelperLaunchdPlistWithName() { 133 | 134 | # Verify passed helper launchd plist name is not empty and ends with .plist 135 | if [[ -n ${1} ]] && [[ ${1} =~ .*\.plist ]]; then 136 | local path_helperLaunchdPlist="/Library/LaunchDaemons/${1}" 137 | else 138 | printError "Invalid helper launchd plist name: ${1}" 139 | exit 1 140 | fi 141 | 142 | if [[ -f ${path_helperLaunchdPlist} ]]; then 143 | printf "%s" "Unloading helper launchd plist..." 144 | 145 | launchctlUnloadOutput=$( /bin/launchctl unload "${path_helperLaunchdPlist}" 2>&1 ) 146 | launchctlExitStatus=${?} 147 | 148 | if (( ${launchctlExitStatus} == 0 )); then 149 | printStatusOKForMessage "Unloading helper launchd plist..." 150 | else 151 | printStatusErrorForMessage "Unloading helper launchd plist..." 152 | printError "launchctlExitStatus=${launchctlExitStatus}" 153 | printError "launchctlUnloadOutput=${launchctlUnloadOutput}" 154 | exit 1 155 | fi 156 | 157 | printf "%s" "Removing helper launchd plist..." 158 | 159 | rmOutput=$( /bin/rm "${path_helperLaunchdPlist}" 2>&1 ) 160 | rmExitStatus=${?} 161 | 162 | if (( ${rmExitStatus} == 0 )); then 163 | printStatusOKForMessage "Removing helper launchd plist..." 164 | else 165 | printStatusErrorForMessage "Removing helper launchd plist..." 166 | printError "rmExitStatus=${rmExitStatus}" 167 | printError "rmOutput=${rmOutput}" 168 | exit 1 169 | fi 170 | else 171 | printf "%s\n" "Helper launchd plist with name "${helperLaunchdFilename}" is not installed" 172 | fi 173 | } 174 | 175 | removeHelperBinaryWithName() { 176 | 177 | # Verify passed helper binary name is not empty 178 | if [[ -n ${1} ]]; then 179 | local path_helperBinary="/Library/PrivilegedHelperTools/${1}" 180 | else 181 | printError "Invalid helper launchd plist name: ${1}" 182 | exit 1 183 | fi 184 | 185 | if [[ -f ${path_helperBinary} ]]; then 186 | printf "%s" "Removing helper binary..." 187 | 188 | rmOutput=$( /bin/rm "${path_helperBinary}" 2>&1 ) 189 | rmExitStatus=${?} 190 | 191 | if (( ${rmExitStatus} == 0 )); then 192 | printStatusOKForMessage "Removing helper binary..." 193 | else 194 | printStatusErrorForMessage "Removing helper binary..." 195 | printError "rmExitStatus=${rmExitStatus}" 196 | printError "rmOutput=${rmOutput}" 197 | exit 1 198 | fi 199 | else 200 | printf "%s\n" "Helper binary with name "${helperBinaryFilename}" is not installed" 201 | fi 202 | } 203 | 204 | #////////////////////////////////////////////////////////////////////////////////////////////////// 205 | ### 206 | ### MAIN SCRIPT 207 | ### 208 | #////////////////////////////////////////////////////////////////////////////////////////////////// 209 | 210 | # Verify script is run with administrator privileges 211 | if [[ ${EUID} -ne 0 ]]; then 212 | printf "%s\n" "This script must be run as root!" 1>&2 213 | exit 1 214 | fi 215 | 216 | # Parse all passed options 217 | parse_command_line_options "${@}" 218 | 219 | if [[ -n ${path_applicationBundle} ]]; then 220 | 221 | # Read helper binary name(s) from application bundle Info.plist 222 | readHelperFromApplicationBundleAtPath "${path_applicationBundle}" 223 | else 224 | printf "%s\n" "Resetting helper: ${helperBinaryFilename}..." 225 | 226 | # Remove hardcoded helper launchd plist 227 | removeHelperLaunchdPlistWithName "${helperLaunchdFilename}" 228 | 229 | # Remove hardcoded helper binary 230 | removeHelperBinaryWithName "${helperBinaryFilename}" 231 | fi 232 | 233 | 234 | 235 | exit 0 236 | -------------------------------------------------------------------------------- /tools/privilegedHelperToolStatus/README.md: -------------------------------------------------------------------------------- 1 | ## privilegedHelperToolStatus 2 | 3 | -------------------------------------------------------------------------------- /tools/privilegedHelperToolStatus/privilegedHelperToolStatus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # CURRENTLY REQUIRES OS X 10.10 !!! 14 | 15 | # Inspect all privileged helper tools installed in /Library/PrivilegedHelperTools and print info 16 | # about their installation status. 17 | 18 | # DISCLAIMER: 19 | # This script is in no way a complete or recommended way to determine helper tool status. 20 | # It's just written to illustrate one possible way to inspect helpers and determine if they could/should be removed. 21 | 22 | # See my accompanying blog post here: http://erikberglund.github.io/2016/No_Privileged_Helper_Tool_Left_Behind/ 23 | 24 | #////////////////////////////////////////////////////////////////////////////////////////////////// 25 | ### 26 | ### FUNCTIONS 27 | ### 28 | #////////////////////////////////////////////////////////////////////////////////////////////////// 29 | 30 | sgr_variables() { 31 | # Colors 32 | red=$(tput setaf 1) # Red 33 | yel=$(tput setaf 3) # Yellow 34 | def=$'\e[39m' # Default (Foreground Color) 35 | 36 | # Attributes 37 | bld=$(tput bold) # Acctivate Bold 38 | nobld=$'\e[22m' # Deactivate Bold 39 | 40 | # Clear 41 | clr=$(tput sgr0) # Deactivate ALL sgr attributes and colors 42 | } 43 | 44 | #////////////////////////////////////////////////////////////////////////////////////////////////// 45 | ### 46 | ### FUNCTIONS - PLIST 47 | ### 48 | #////////////////////////////////////////////////////////////////////////////////////////////////// 49 | 50 | parse_plist_info_launchctl() { 51 | 52 | # Remove previous variables 53 | unset plist_info_error; unset helper_bundle_id; unset helper_bundle_name; unset helper_bundle_version; unset helper_application_bundle_ids 54 | 55 | # Try to retrieve the embedded Info.plist from the helper binary 56 | plist_info_launchctl=$( launchctl plist __TEXT,__info_plist "${1}" 2>&1 ) 57 | 58 | # Get helper info from it's info plist 59 | if [[ -n ${plist_info_launchctl} ]] && ! [[ ${plist_info_launchctl} =~ "does not have a __TEXT,__info_plist or is invalid."$ ]]; then 60 | helper_bundle_id=$( awk -F'"' '/CFBundleIdentifier/ { print $(NF-1) }' <<< "${plist_info_launchctl}" ) 61 | helper_bundle_name=$( awk -F'"' '/CFBundleName/ { print $(NF-1) }' <<< "${plist_info_launchctl}" ) 62 | helper_bundle_version=$( awk -F'"' '/CFBundleVersion/ { print $(NF-1) }' <<< "${plist_info_launchctl}" ) 63 | while read -a smauthorizedclient_string; do 64 | helper_application_bundle_ids+=( $( awk '/identifier$/ { getline; print }' <( printf '%s\n' "${smauthorizedclient_string[@]}" ) ) ) 65 | done < <( awk '/SMAuthorizedClients/ { flag=1; next } /\)\;/ { flag=0 } flag { print }' <<< "${plist_info_launchctl}" | sed 's/[="()]//g' ) 66 | else 67 | plist_info_error="${plist_info_launchctl}" 68 | fi 69 | } 70 | 71 | parse_plist_launchd_launchctl() { 72 | 73 | # Remove previous variables 74 | unset plist_launchd_error; unset helper_launchd_state; unset helper_launchd_label; unset helper_launchd_path 75 | 76 | # Try to retrieve the embedded Launchd.plist from the helper binary 77 | plist_launchd_launchctl=$( launchctl plist __TEXT,__launchd_plist "${1}" 2>&1 ) 78 | 79 | if [[ -n ${plist_launchd_launchctl} ]] && ! [[ ${plist_launchd_launchctl} =~ "does not have a __TEXT,__launchd_plist or is invalid."$ ]]; then 80 | 81 | # Get launchd label from extracted plist. 82 | helper_launchd_label=$( awk -F'"' '/Label/ { print $(NF-1) }' <<< "${plist_launchd_launchctl}" ) 83 | 84 | # Call 'launchctl print' to get launchd job status 85 | if [[ -n ${helper_launchd_label} ]]; then 86 | while read line; do 87 | if [[ ${line} =~ ^state ]]; then 88 | helper_launchd_state=$( awk -F= '{ gsub(/ /, ""); print $2 }' <<< "${line}" ) 89 | elif [[ ${line} =~ ^path ]]; then 90 | helper_launchd_path=$( awk -F= '{ gsub(/ /, ""); print $2 }' <<< "${line}" ) 91 | elif [[ ${line} =~ ^program ]]; then 92 | helper_launchd_program=$( awk -F= '{ gsub(/ /, ""); print $2 }' <<< "${line}" ) 93 | fi 94 | done < <( launchctl print system/"${helper_launchd_label}" | grep '\tstate\|\tpath\|\tprogram' ) 95 | 96 | # Sanity check so that the helper binary path is the same that's used as the program path in the launchd job 97 | if [[ -n ${helper_launchd_program} ]] && [[ ${helper_launchd_program} != ${helper_path} ]]; then 98 | printf "\n%s\n\n" "${bld}Current helpers path and path in launchd job is not matching!${clr}" 99 | fi 100 | fi 101 | else 102 | plist_launchd_error=${plist_launchd_launchctl} 103 | fi 104 | } 105 | 106 | #////////////////////////////////////////////////////////////////////////////////////////////////// 107 | ### 108 | ### FUNCTIONS - PRINT 109 | ### 110 | #////////////////////////////////////////////////////////////////////////////////////////////////// 111 | 112 | print_title() { 113 | printf "\n%22s%s\n" "[${1}]" 114 | } 115 | 116 | print_helper() { 117 | print_title "Helper" 118 | 119 | if [[ -z ${plist_launchd_error} ]]; then 120 | printf "%22s\t%s\n\n" "Path:" "${helper_path}" 121 | printf "%22s\t%-10s%s\n" "" "BundleID:" "${helper_bundle_id}" 122 | printf "%22s\t%-10s%s\n" "" "Name:" "${helper_bundle_name}" 123 | printf "%22s\t%-10s%s\n" "" "Version:" "${helper_bundle_version}" 124 | else 125 | printf "%22s\t%s\n" "Path:" "${helper_path}" 126 | printf "%22s\t%s\n" "Warning:" "${bld}${plist_info_error}${clr}" 127 | fi 128 | } 129 | 130 | print_helper_launchd() { 131 | print_title "Launchd" 132 | 133 | if [[ -z ${plist_launchd_error} ]]; then 134 | printf "%22s\t%s\n\n" "Path:" "${helper_launchd_path}" 135 | printf "%22s\t%-10s%s\n" "" "Label:" "${helper_launchd_label}" 136 | printf "%22s\t%-10s%s\n" "" "State:" "${helper_launchd_state}" 137 | else 138 | printf "%22s\t%s\n" "Warning:" "${bld}${plist_launchd_error}${clr}" 139 | fi 140 | } 141 | 142 | print_helper_authorizationdb() { 143 | print_title "Authorization DB" 144 | 145 | rule_count=0 146 | for bundle_id in ${helper_application_bundle_ids[@]} ${helper_bundle_id:-${helper_launchd_label}}; do 147 | while read helper_authorizationdb_rule_name; do 148 | ((rule_count++)) 149 | if (( rule_count == 1 )); then 150 | printf "%22s\t%s\n" "Rules:" "${helper_authorizationdb_rule_name}" 151 | else 152 | printf "%22s\t%s\n" "" "${helper_authorizationdb_rule_name}" 153 | fi 154 | done < <( sqlite3 /var/db/auth.db "SELECT name FROM rules WHERE identifier = '${bundle_id}'"; ) 155 | done 156 | 157 | # Print out explicit info that no authorization db rules were found. 158 | if (( rule_count == 0 )); then 159 | printf "%22s\t%s\n" "Info:" "" 160 | fi 161 | } 162 | 163 | print_helper_application() { 164 | print_title "Applications" 165 | 166 | application_found='False' 167 | for helper_application_bundle_id in ${helper_application_bundle_ids[@]}; do 168 | if [[ -n ${helper_application_bundle_id} ]]; then 169 | printf "%22s\t%s\n" "BundleID:" "${helper_application_bundle_id}" 170 | application_count=0 171 | while read helper_application_path; do 172 | application_found='True' 173 | ((application_count++)) 174 | helper_application_name=$( /usr/libexec/PlistBuddy -c "Print :CFBundleName" "${helper_application_path}/Contents/Info.plist" ) 175 | helper_application_version=$( /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${helper_application_path}/Contents/Info.plist" ) 176 | print_helper_application_info 177 | done < <( mdfind "kMDItemCFBundleIdentifier == ${helper_application_bundle_id}" ) 178 | 179 | # Print warning if no application matching the current bundle identifiers could be found 180 | if (( application_count == 0 )); then 181 | printf "%22s\t%s\n" "" "" 182 | fi 183 | else 184 | printf "%s\n" "Empty BundleID" 185 | fi 186 | done 187 | 188 | # Print error if no application matching any of the bundle identifiers entered in the helper tool's SMAuthorizedClients array 189 | if [[ ${application_found} != True ]]; then 190 | print_helper_left_behind 191 | fi 192 | } 193 | 194 | print_helper_application_info() { 195 | printf "\n" 196 | printf "%22s\t%-10s%s\n" "" "Name:" "${helper_application_name}" 197 | printf "%22s\t%-10s%s\n" "" "Path:" "${helper_application_path}" 198 | printf "%22s\t%-10s%s\n\n" "" "Version:" "${helper_application_version}" 199 | } 200 | 201 | print_helper_info() { 202 | printf "\n" 203 | printf "%0.1s" "*"{1..80} 204 | printf "\n" 205 | 206 | print_helper 207 | print_helper_launchd 208 | if [[ -z ${plist_info_error} ]]; then 209 | print_helper_authorizationdb 210 | print_helper_application 211 | fi 212 | } 213 | 214 | print_helper_left_behind() { 215 | printf "\n" 216 | printf "${red}%22s\t%s${clr}\n" "" "+------------------------------------------------------+" 217 | printf "${red}%22s\t%s${clr}\n" "" "| !!! WARNING !!! |" 218 | printf "${red}%22s\t%s${clr}\n" "" "| |" 219 | printf "${red}%22s\t%s${clr}\n" "" "| NO APPLICATION FOUND FOR PRIVILEGED HELPER TOOL |" 220 | printf "${red}%22s\t%s${clr}\n" "" "| |" 221 | printf "${red}%22s\t%s${clr}\n" "" "| IT MIGHT BE LEFT BEHIND |" 222 | printf "${red}%22s\t%s${clr}\n" "" "+------------------------------------------------------+" 223 | printf "\n" 224 | } 225 | 226 | #////////////////////////////////////////////////////////////////////////////////////////////////// 227 | ### 228 | ### MAIN SCRIPT 229 | ### 230 | #////////////////////////////////////////////////////////////////////////////////////////////////// 231 | 232 | # Verify script is run with administrator privileges 233 | if [[ ${EUID} -ne 0 ]]; then 234 | printf "%s\n" "This script must be run as root!" 1>&2 235 | exit 1 236 | elif (( $( sw_vers -productVersion | awk -F. '{ print $2 }' ) < 10 )); then 237 | printf "%s\n" "This script requires OS X 10.10 or higher (because of the use of launchctl plist)" 1>&2 238 | exit 1 239 | fi 240 | 241 | # Load variables 242 | sgr_variables 243 | 244 | # Loop through all binary files directly under "/Library/PrivilegedHelperTools" 245 | for helper_path in /Library/PrivilegedHelperTools/*; do 246 | if [[ -n ${helper_path} ]] && [[ -f ${helper_path} ]]; then 247 | 248 | # Extract and parse embedded plist files from helper at 'helper_path' 249 | parse_plist_info_launchctl "${helper_path}" 250 | parse_plist_launchd_launchctl "${helper_path}" 251 | 252 | # Print all available info for current helper tool to stdout 253 | print_helper_info 254 | else 255 | printf "\n" 256 | printf "%0.1s" "*"{1..80} 257 | printf "\n" 258 | 259 | printf "%s\n" "${helper_path} is not a file" 260 | fi 261 | done 262 | 263 | exit 0 264 | -------------------------------------------------------------------------------- /tools/resetVMWare/resetVMWare.bash: -------------------------------------------------------------------------------- 1 | rm -rf "/Library/Application Support/VMware" 2 | rm -rf "/Library/Application Support/VMware Fusion" 3 | rm -rf "/Library/Preferences/VMware Fusion" 4 | rm -rf "~/Library/Application Support/VMware Fusion" 5 | rm -rf "~/Library/Caches/com.vmware.fusion" 6 | rm -rf "~/Library/Preferences/VMware Fusion" 7 | rm -rf "~/Library/Preferences/com.vmware.fusion.LSSharedFileList.plist" 8 | rm -rf "~/Library/Preferences/com.vmware.fusion.LSSharedFileList.plist.lockfile" 9 | rm -rf "~/Library/Preferences/com.vmware.fusion.plist" 10 | rm -rf "~/Library/Preferences/com.vmware.fusion.plist.lockfile" 11 | rm -rf "~/Library/Preferences/com.vmware.fusionDaemon.plist" 12 | rm -rf "~/Library/Preferences/com.vmware.fusionDaemon.plist.lockfile" 13 | rm -rf "~/Library/Preferences/com.vmware.fusionStartMenu.plist" 14 | rm -rf "~/Library/Preferences/com.vmware.fusionStartMenu.plist.lockfile" -------------------------------------------------------------------------------- /tools/serverAppArchiver/README.md: -------------------------------------------------------------------------------- 1 | ## serverAppArchiver 2 | 3 | 4 | # OS X Server 5 | 6 | * iTunes ID: 883878097 7 | * iTunes Link: [OS X Server](https://itunes.apple.com/app/id883878097?mt=12) 8 | 9 | | Version | Release Date | Have | 10 | |:--------|:-------------|:-----| 11 | | 5.1.7 | 2016-07-18 | YES | 12 | | 5.1.5 | 2016-05-16 | YES | 13 | | 5.1 | 2016-03-21 | YES | 14 | | 5.0.15 | 2015-10-21 | YES | 15 | | 5.0.4 | 2015-09-21 | NO | 16 | | 5.0.3 | 2015-09-16 | NO | 17 | | 4.1.5 | 2015-08-13 | YES | 18 | | 4.1.3 | 2015-06-30 | NO | 19 | | 4.1 | 2015-04-08 | NO | 20 | | 4.0.3 | 2015-01-06 | YES | 21 | | 4.0 | 2014-10-16 | YES | 22 | 23 | 24 | # OS X Server (Mavericks) 25 | 26 | * iTunes ID: 714547929 27 | * iTunes Link: [OS X Server](https://itunes.apple.com/app/id714547929?mt=12) 28 | 29 | | Version | Release Date | Have | 30 | |:--------|:-------------|:-----| 31 | | 3.2.2 | 2014-10-16 | NO | 32 | | 3.2.1 | N/A | NO | 33 | | 3.1.2 | N/A | YES | 34 | | 3.1.1 | N/A | YES | 35 | | 3.1 | N/A | NO | 36 | | 3.0.3 | N/A | NO | 37 | | 3.0.2 | N/A | NO | 38 | | 3.0.1 | N/A | NO | 39 | | 3.0 | N/A | NO | 40 | 41 | # OS X Server (Mountain Lion) 42 | 43 | * iTunes ID: 537441259 44 | * iTunes Link: [OS X Server](https://itunes.apple.com/app/id537441259?mt=12) 45 | 46 | | Version | Release Date | Have | 47 | |:--------|:-------------|:-----| 48 | | 2.2.5 | 2014-10-16 | YES | 49 | | 2.2.4 | N/A | YES | 50 | | 2.2.3 | N/A | YES | 51 | | 2.2.2 | N/A | YES | 52 | | 2.2.1 | N/A | YES | 53 | | 2.2 | N/A | YES | 54 | | 2.1.0 | N/A | YES | 55 | | 2.0.23 | N/A | YES | 56 | 57 | # OS X Lion Server 58 | 59 | * iTunes ID: N/A 60 | * iTunes Link: N/A 61 | 62 | | Version | Release Date | Have | 63 | |:--------|:-------------|:-----| 64 | | 1.5.0 | N/A | YES | 65 | | 1.0.5 | N/A | YES | 66 | -------------------------------------------------------------------------------- /tools/serverAppArchiver/serverAppArchiver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # Create disk image of Server.app (for archiving) 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### USAGE 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Usage: ./serverAppArchiver [options] ... 22 | # 23 | # Options: 24 | # -a (Optional) Find and archive all server applications on system (ignores -i option) 25 | # -i (Optional) Input directory to search for applications 26 | # -o (Optional) Output directory for archives (defaults to working directory) 27 | # -u (Optional) Uploads all dmgs created to ftp and delete local dmg copy on success (ignores -o option) 28 | 29 | #////////////////////////////////////////////////////////////////////////////////////////////////// 30 | ### 31 | ### VARIABLES 32 | ### 33 | #////////////////////////////////////////////////////////////////////////////////////////////////// 34 | 35 | ftp_server="" 36 | ftp_user="" 37 | ftp_pass="" 38 | 39 | #////////////////////////////////////////////////////////////////////////////////////////////////// 40 | ### 41 | ### FUNCIONS 42 | ### 43 | #////////////////////////////////////////////////////////////////////////////////////////////////// 44 | 45 | parse_opts() { 46 | while getopts "ai:o:u" opt; do 47 | case ${opt} in 48 | a) search_applications='True' ;; 49 | i) input_directory="${OPTARG%/}" ;; 50 | o) output_directory="${OPTARG%/}" ;; 51 | u) upload='True' ;; 52 | \?) usage; exit 1;; 53 | :) usage; exit 1;; 54 | esac 55 | done 56 | 57 | # Check 'output_directory' options, set to 'PWD' if none was passed. 58 | if [[ ${upload} == True ]]; then 59 | output_directory="/tmp" 60 | elif [[ -z ${output_directory} ]]; then 61 | output_directory="${PWD}" 62 | elif ! [[ -d ${output_directory} ]]; then 63 | error "${output_directory} is not a directory" 64 | fi 65 | 66 | printf "%s\n" "Output directory: ${output_directory}" 67 | 68 | # Check if current user has write capabilities for output_directory 69 | if ! [[ -w ${output_directory} ]]; then 70 | error "User: ${USER} doesn't have write permissions for output folder: ${output_directory}" 71 | fi 72 | 73 | # Check if option '-a' was passed, then use mdfind to find all applications matching bundle id wildcard search: 'com.apple.Server.v*' 74 | if [[ ${search_applications} == True ]]; then 75 | old_ifs="${IFS}"; IFS=$'\n' 76 | applications+=( $( mdfind "kMDItemCFBundleIdentifier == 'com.apple.Server.v*'c" ) ) 77 | applications+=( $( mdfind "kMDItemCFBundleIdentifier == 'com.apple.Server'c" ) ) 78 | IFS="${old_ifs}" 79 | fi 80 | 81 | if [[ ${search_applications} != True ]] || (( ${#applications[@]} == 0 )); then 82 | # Check 'input_directory' options, set to '/Applications' if non was passed. 83 | if [[ -z ${input_directory} ]]; then 84 | input_directory="/Applications" 85 | elif ! [[ -d ${input_directory} ]]; then 86 | error "${input_directory} is not a directory" 87 | fi 88 | 89 | printf "%s\n" "Input directory: ${input_directory}" 90 | 91 | # Add all server applications passing test to array 'applications' 92 | for app in "${input_directory}"/*\.app/; do 93 | if [[ -f "${app}/Contents/Info.plist" ]] && [[ "$( /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${app}/Contents/Info.plist" 2>&1 )" =~ ^com.apple.Server.v* ]]; then 94 | applications+=( "${app%/}" ) 95 | fi 96 | done 97 | fi 98 | 99 | } 100 | 101 | usage() { 102 | printf "%s\n" "Usage: ./${0##*/} [options] ..." 103 | printf "%s\n" "Options:" 104 | printf " %s\t%s\n" "-a" "(Optional) All server applications on computer (uses mdfind)" 105 | printf " %s\t%s\n" "-i" "(Optional) Input directory" 106 | printf " %s\t%s\n" "-o" "(Optional) Output directory" 107 | printf " %s\t%s\n" "-u" "(Optional) Upload to FTP" 108 | printf "\n" 109 | } 110 | 111 | error() { 112 | printf "%s\n" "${1}, exiting script..." >&2; exit 1 113 | } 114 | 115 | check_upload_status() { 116 | if [[ $( /usr/bin/curl --connect-timeout 30 --retry 3 -l -u "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}" 2>&1 | grep -E ^${1}$ ) == ${1} ]]; then 117 | printf "%s" "exists" 118 | else 119 | printf "%s" "no" 120 | fi 121 | } 122 | 123 | upload_dmg() { 124 | curl_output=$( curl --connect-timeout 30 --retry 3 -S -T "${1}" -u "${ftp_user}:${ftp_pass}" "ftp://${ftp_server}/" 2>&1 ) 125 | if [[ ${?} -ne 0 ]]; then 126 | error "Upload of file ${1} to server ${ftp_server} failed with error: ${curl_output}" 127 | fi 128 | } 129 | 130 | #////////////////////////////////////////////////////////////////////////////////////////////////// 131 | ### 132 | ### MAIN SCRIPT 133 | ### 134 | #////////////////////////////////////////////////////////////////////////////////////////////////// 135 | 136 | # Stop globbing from printing itself if there are no matches 137 | shopt -s nullglob 138 | 139 | # Parse passed arguments 140 | parse_opts "${@}" 141 | 142 | printf "%s\n" "Found the following server applications:" 143 | printf "\t%s\n" "${applications[@]}" 144 | 145 | declare -a all_application_dmgs 146 | 147 | # Loop through all applications and create dmg in output directory 148 | for application in "${applications[@]}"; do 149 | 150 | printf "%s\n" "Checking ${application}..." 151 | 152 | # Get application name 153 | application_name=$( /usr/libexec/PlistBuddy -c "Print :CFBundleDisplayName" "${application}/Contents/Info.plist" 2>&1 ) 154 | if [[ ${application_name} =~ "Does Not Exist" ]]; then 155 | application_name=$( /usr/libexec/PlistBuddy -c "Print :CFBundleName" "${application}/Contents/Info.plist" 2>&1 ) 156 | fi 157 | 158 | # Get application version 159 | application_version=$( /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${application}/Contents/Info.plist" 2>&1 ) 160 | 161 | # Get application build version 162 | application_build_version="-$( /usr/libexec/PlistBuddy -c "Print :ProductBuildVersion" "${application}/Contents/ServerRoot/System/Library/CoreServices/ServerVersion.plist" 2>&1 )" 163 | if [[ ${application_build_version} =~ "Does Not Exist" ]]; then 164 | application_build_version="" 165 | fi 166 | 167 | # Assemble name for dmg file and volume 168 | name=$( sed 's/\ //g' <<< "${application_name}_${application_version}${application_build_version}" ) 169 | 170 | # Check if target dmg already exist in selected ouptut directory 171 | if [[ -f ${output_directory}/${name}.dmg ]]; then 172 | if [[ ${upload} == True ]]; then 173 | rm "${output_directory}/${name}.dmg" 174 | else 175 | printf "%s\n" "File: ${output_directory}/${name} already exist, skipping..." >&2 176 | continue 177 | fi 178 | fi 179 | 180 | if [[ ${upload} == True ]] && [[ $( check_upload_status "${name}.dmg" ) == exists ]]; then 181 | printf "%s\n" "File: ${name}.dmg already exist on the FTP, skipping..." >&2 182 | continue 183 | fi 184 | 185 | # Remove quarantine attribute if present 186 | xattr -d -r com.apple.quarantine "${application}" > /dev/null 2>&1 187 | 188 | # Create application dmg archive 189 | printf "%s\n" "Creating ${output_directory}/${name}.dmg..." 190 | if ! hdiutil create -srcfolder "${application}" -volname "${name}" "${output_directory}/${name}" 1> /dev/null; then 191 | error "Creating ${output_directory}/${name}.dmg failed" 192 | fi 193 | 194 | # Add path to dmg to all_application_dmgs 195 | all_application_dmgs+=( "${output_directory}/${name}.dmg" ) 196 | 197 | # Upload current dmg if 'upload' == True 198 | if [[ ${upload} == True ]]; then 199 | printf "%s\n" "Uploading ${output_directory}/${name}.dmg..." 200 | upload_dmg "${output_directory}/${name}.dmg" 201 | fi 202 | done 203 | 204 | # Remove all local dmgs if 'upload' == True 205 | if [[ ${upload} == True ]]; then 206 | for application_dmg in "${all_application_dmgs[@]}"; do 207 | if [[ ${application_dmg} =~ ^.*Server_.*\.dmg$ ]]; then 208 | rm "${application_dmg}" 209 | else 210 | printf "%s\n" "Unknown dmg in all_application_dmgs: ${application_dmg}" 211 | fi 212 | done 213 | fi 214 | 215 | # Restore globbing behaviour. 216 | shopt -u nullglob 217 | 218 | exit 0 -------------------------------------------------------------------------------- /tools/sharedLibraryDependencyChecker/README.md: -------------------------------------------------------------------------------- 1 | ## sharedLibraryDependencyChecker 2 | 3 | Example: 4 | 5 | 6 | `-t`: Show dependencies for the `Quartz.framework` binary. 7 | `-v`: Show dependencies missing from the system volume `/Volumes/OS X Base System` 8 | `-x`: Output the result as regexes 9 | `-r`: Show what binary is dependent on the missing dependency 10 | `-f`: Output full path to all dependencies 11 | 12 | ```bash 13 | sharedLibraryDependencyChecker -t "/System/Library/Frameworks/Quartz.framework/Versions/A/Quartz" -v "/Volumes/OS X Base System" -x -r -f 14 | ``` -------------------------------------------------------------------------------- /tools/sharedLibraryDependencyChecker/sharedLibraryDependencyChecker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### Version 1.0 4 | ### Created by Erik Berglund 5 | ### https://github.com/erikberglund 6 | 7 | #////////////////////////////////////////////////////////////////////////////////////////////////// 8 | ### 9 | ### DESCRIPTION 10 | ### 11 | #////////////////////////////////////////////////////////////////////////////////////////////////// 12 | 13 | # This script is designed to recursively check all shared library dependencies for the passed binary. 14 | 15 | #////////////////////////////////////////////////////////////////////////////////////////////////// 16 | ### 17 | ### USAGE 18 | ### 19 | #////////////////////////////////////////////////////////////////////////////////////////////////// 20 | 21 | # Usage: ./sharedLibraryDependencyChecker.bash [options] ... 22 | # 23 | # Options: 24 | # -t [Required] Path to application (.app) or binary. Multiple paths can be defined with additional -t args. 25 | # -v (Optional/Ignored if -a is used) Path to system volume root 26 | # -x (Optional) Format output as regex strings 27 | # -X (Optional) Format output as regex strings surrounded by xml string tags (regex) 28 | # -a (Optional) Output all dependencies for target(s) 29 | # -r (Optional) Output what file(s) depends on each output entry 30 | # -f (Optional) Output full paths for all files (Used to turn off the default behaviour of only outputting path to the .framework bundle for files contained within) 31 | # -e [regex] (Optional) Output full paths for all files matched by [regex] (Used to turn off the default behaviour for matching files of only outputting path to the .framework bundle for files contained within) 32 | # -i [regex] (Optional) Igore item(s) matching [regex] in output 33 | 34 | #////////////////////////////////////////////////////////////////////////////////////////////////// 35 | ### 36 | ### VARIABLES 37 | ### 38 | #////////////////////////////////////////////////////////////////////////////////////////////////// 39 | 40 | path_tmp_relational_plist="/tmp/$( uuidgen ).plist" 41 | 42 | declare -a target_executables 43 | declare -a external_dependencies 44 | declare -a bundled_dependencies 45 | declare -a missing_external_dependencies 46 | declare -a missing_bundled_dependencies 47 | 48 | #////////////////////////////////////////////////////////////////////////////////////////////////// 49 | ### 50 | ### FUNCTIONS 51 | ### 52 | #////////////////////////////////////////////////////////////////////////////////////////////////// 53 | 54 | resolve_dependencies_for_target() { 55 | 56 | # 1 - Path to the dependency to check 57 | local dependency_target="${1}" 58 | 59 | if [[ -f "${dependency_target}" ]]; then 60 | 61 | # Loop through all dependencies listed by 'otool -L ' 62 | while read dependency_path; do 63 | 64 | # Get absolute path to dependency 65 | local dependency_library_path=$( resolve_dependency_path "${dependency_path}" "${dependency_target%/*}" ) 66 | 67 | if [[ -L ${dependency_library_path} ]]; then 68 | # If dependency path is a symbolic link 69 | 70 | symlink_path="${dependency_library_path}" 71 | 72 | while [[ -L ${symlink_path} ]]; do 73 | readlink_path=$( readlink "${symlink_path}" ) 74 | 75 | if ! [[ ${readlink_path} =~ ^Versions ]]; then 76 | add_item_to_array external_dependencies "${symlink_path}" 77 | symlink_path=$( resolve_dependency_path "${readlink_path}" "${symlink_path%/*}" ) 78 | else 79 | break 80 | fi 81 | done 82 | 83 | dependency_path="${symlink_path}" 84 | dependency_library_path="${symlink_path}" 85 | elif [[ -n ${dependency_library_path} ]]; then 86 | # If dependency path is not empty 87 | 88 | if [[ ${dependency_library_path} =~ \.framework ]] && [[ ${outputAbsolutePath} != yes ]]; then 89 | 90 | # If item contains '.framework' then just add the path to the framework bundle 91 | dependency_library_path_key=$( sed -nE 's/^(.*.framework)\/.*$/\1/p' <<< ${dependency_library_path} ) 92 | else 93 | dependency_library_path_key=${dependency_library_path} 94 | fi 95 | current_key_value=$( /usr/libexec/PlistBuddy -c "Print ${dependency_library_path_key}" "${path_tmp_relational_plist}" 2>&1 ) 96 | if [[ ${current_key_value} =~ "Does Not Exist" ]]; then 97 | plist_buddy_output_add_array=$( /usr/libexec/PlistBuddy -c "Add '""${dependency_library_path_key}""' array" "${path_tmp_relational_plist}" 2>&1 ) 98 | fi 99 | /usr/libexec/PlistBuddy -c "Add '""${dependency_library_path_key}:0""' string ${dependency_target}" "${path_tmp_relational_plist}" 100 | else 101 | # If dependency_library_path is empty, continue 102 | continue 103 | fi 104 | 105 | if [[ ${dependency_path} =~ ^@ ]] && ! array_contains_item bundled_dependencies "${dependency_library_path}"; then 106 | 107 | # Add dependency to bundled_dependencies array if it's not already added 108 | add_item_to_array bundled_dependencies "${dependency_library_path}" 109 | 110 | # Resolve current dependency's dependencies as well 111 | resolve_dependencies_for_target "${dependency_library_path}" 112 | elif ! array_contains_item external_dependencies "${dependency_library_path}"; then 113 | 114 | # Add dependency to external_dependencies array if it's not already added 115 | add_item_to_array external_dependencies "${dependency_library_path}" 116 | 117 | # Resolve current dependency's dependencies as well 118 | resolve_dependencies_for_target "${dependency_library_path}" 119 | fi 120 | done < <( otool -L "${dependency_target}" | sed -nE "s/^[ $( printf '\t' )]+(.*)\(.*$/\1/p" 2>&1 ) 121 | elif [[ -d "${dependency_target}" ]] && ! array_contains_item external_dependencies "${dependency_target}"; then 122 | 123 | # Add dependency to external_dependencies array if it's not already added 124 | add_item_to_array external_dependencies "${dependency_target}" 125 | else 126 | printf "%s\n" "[ERROR] No such file or directory: ${dependency_target}" >&2 127 | fi 128 | } 129 | 130 | resolve_dependency_path() { 131 | 132 | # 1 - Path to the dependency to check 133 | local dependency_path="${1}" 134 | 135 | # 2 - Path to the linker's @executable_path for current dependency 136 | local linker_executable_path="${2}" 137 | 138 | if [[ ${dependency_path} =~ ^@ ]]; then 139 | 140 | # Replace the linker variable with an absolute path 141 | case "${dependency_path%%/*}" in 142 | '@executable_path') 143 | local base_path=$( sed -E 's/^\///g;s/\/$//g' <<< "${linker_executable_path}" ) 144 | ;; 145 | *) 146 | printf "%s\n" "[ERROR] ${dependency_path%%/*} - Unknown Linker Path!" >&2 147 | exit 1 148 | ;; 149 | esac 150 | 151 | # Remove the linker variable and any slash prefixes 152 | dependency_path=$( sed -E 's,^[^/]*/,,;s/\/$//g' <<< "${dependency_path}" ) 153 | fi 154 | 155 | # Check if the dependency_path contains any parent directory notations ( ../../ ) 156 | if [[ ${dependency_path} =~ \.\./ ]]; then 157 | 158 | # Read directory paths to arrays with each directory as one item 159 | IFS='/' read -a base_path_folders <<< "${base_path:-${2}}" 160 | IFS='/' read -a dependency_path_folders <<< "${dependency_path}" 161 | 162 | # Count number of parent directory steps to remove ( ../../ ) 163 | count=0 164 | for directory in ${dependency_path_folders[*]}; do 165 | if [[ ${directory} == .. ]]; then 166 | (( count++ )) 167 | fi 168 | done 169 | 170 | # Remove $count directories from both arrays and join the shortened version to one correct directory path 171 | IFS=/ eval 'dependency_path="/${base_path_folders[*]:0:$(( ${#base_path_folders[@]} - count ))}/${dependency_path_folders[*]:${count}}"' 172 | elif [[ ${dependency_path} == ${1##*/} ]]; then 173 | 174 | dependency_path="${linker_executable_path}/${dependency_path}" 175 | fi 176 | 177 | # Return path and remove extra '/' in path 178 | echo -n "${dependency_path}" | sed 's/\/\//\//g' 179 | } 180 | 181 | add_item_to_array () { 182 | 183 | # 1 - Array variable name 184 | local array="${1}" 185 | shift 1 186 | 187 | # Add passed item to the array 188 | eval "${array}+=( $( printf "'%s' " "${@}" ) )" 189 | } 190 | 191 | array_contains_item() { 192 | 193 | # 1 - Array variable name 194 | local array="${1}[@]" 195 | 196 | # 2 - Item to add to variable 197 | local item="${2}" 198 | 199 | # Return 0 if item already exist in array, else return 1 200 | for arrayItem in "${!array}"; do 201 | if [[ ${item} == ${arrayItem} ]]; then return 0; fi 202 | done 203 | return 1 204 | } 205 | 206 | clean_and_sort_array() { 207 | 208 | # 1 - Array variable name 209 | local array="${1}[@]" 210 | 211 | declare -a newArray 212 | for arrayItem in "${!array}"; do 213 | if [[ ${arrayItem} =~ \.framework && ( ${outputAbsolutePath} != yes && ! ${arrayItem} =~ ${outputAbsolutePathForRegex} ) ]]; then 214 | 215 | # If item contains '.framework' then just add the path to the framework bundle 216 | newArray+=( "$( sed -nE 's/^(.*.framework)\/.*$/\1/p' <<< ${arrayItem} )" ) 217 | else 218 | newArray+=( "${arrayItem}" ) 219 | fi 220 | done 221 | 222 | # Sort the new array 223 | IFS=$'\n' array=( $( sort <<< "${newArray[*]}" | uniq ) ) 224 | 225 | # Update passed array with the cleaned and sorted version 226 | eval "${1}=( $( printf "'%s' " "${array[@]}" ) )" 227 | } 228 | 229 | find_missing_dependencies_on_volume() { 230 | 231 | # 1 - Array variable name 232 | local array="${1}[@]" 233 | 234 | # 2 - Array variable name for new array 235 | # - 236 | 237 | declare -a newArray 238 | for arrayItem in "${!array}"; do 239 | 240 | # Create path to item om target volume 241 | itemPathOnTargetVolume=$( sed -E 's/\/+/\//g' <<< "${targetVolumePath}/${arrayItem}" ) 242 | 243 | # If item doesn't exist on target volume, add it to newArray 244 | if ! [[ -e ${itemPathOnTargetVolume} ]]; then newArray+=( "${arrayItem}" ); fi 245 | 246 | # Update passed array with missing shared libraries 247 | eval "${2}=( $( printf "'%s' " "${newArray[@]}" ) )" 248 | done 249 | } 250 | 251 | parse_command_line_options() { 252 | while getopts "ae:fi:rt:v:xX" opt; do 253 | case ${opt} in 254 | a) outputAll="yes" ;; 255 | e) outputAbsolutePathForRegex="${OPTARG}" ;; 256 | f) outputAbsolutePath="yes" ;; 257 | i) outputIgnoreRegex="${OPTARG}" ;; 258 | r) outputReferences="yes" ;; 259 | t) target_executables+=( "${OPTARG}" ) ;; 260 | v) targetVolumePath="${OPTARG}" ;; 261 | x) outputRegex="yes" ;; 262 | X) outputRegex="yes"; outputRegexXML="yes";; 263 | \?) print_usage; exit 1 ;; 264 | :) print_usage; exit 1 ;; 265 | esac 266 | done 267 | 268 | verfiy_command_line_options 269 | } 270 | 271 | verfiy_command_line_options() { 272 | for (( i=0; i<${#target_executables[@]}; i++)); do 273 | targetExecutable="${target_executables[i]}" 274 | if [[ -z ${targetExecutable} ]]; then 275 | printf "%s\n" "Input variable 1 targetExecutable=${targetExecutable} is not valid!"; 276 | print_usage 277 | exit 1 278 | elif [[ ${targetExecutable##*.} == app ]]; then 279 | targetExecutableName=$( /usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" "${targetExecutable}/Contents/Info.plist" 2>&1 ) 280 | if [[ -n ${targetExecutableName} ]]; then 281 | targetExecutable="${targetExecutable}/Contents/MacOS/${targetExecutableName}" 282 | if ! [[ -f ${targetExecutable} ]]; then 283 | printf "%s\n" "Could not find executable from App Bundle!" 284 | printf "%s\n" "Try passing the executable path directly." 285 | print_usage 286 | exit 1 287 | else 288 | target_executables[${i}]="${targetExecutable}" 289 | fi 290 | else 291 | printf "%s\n" "Could not get CFBundleExecutable from ${targetExecutable} from App Bundle!" 292 | printf "%s\n" "Try passing the executable path directly." 293 | print_usage 294 | exit 1 295 | fi 296 | fi 297 | done 298 | 299 | if [[ ${outputAll} != yes ]]; then 300 | if [[ -z ${targetVolumePath} ]] || ! [[ -d ${targetVolumePath} ]]; then 301 | printf "%s\n" "Input variable 2 targetVolumePath=${targetVolumePath} is not valid!"; 302 | print_usage 303 | exit 1 304 | fi 305 | fi 306 | 307 | if ! [[ -f /usr/bin/otool ]]; then 308 | printf "%s\n" "Could not find otool" 309 | exit 1 310 | fi 311 | } 312 | 313 | print_usage() { 314 | printf "\n%s\n\n" "Usage: ./${0##*/} [options] ..." 315 | printf "%s\n" "Options:" 316 | printf " %s\t\t%s\n" "-t" "[Required] Path to application (.app) or binary. Multiple paths can be defined with additional -t args." 317 | printf " %s\t\t%s\n" "-v" "(Optional/Ignored if -a is used) Path to system volume root" 318 | printf " %s\t\t%s\n" "-x" "(Optional) Format output as regex strings" 319 | printf " %s\t\t%s\n" "-X" "(Optional) Format output as regex strings surrounded by xml string tags (regex)" 320 | printf " %s\t\t%s\n" "-a" "(Optional) Output all dependencies for target(s)" 321 | printf " %s\t\t%s\n" "-r" "(Optional) Output what file(s) depends on each output entry" 322 | printf " %s\t\t%s\n" "-f" "(Optional) Output full paths for all files (Used to turn off the default behaviour of only outputting path to the .framework bundle for files contained within)" 323 | printf " %s\t%s\n" "-e [regex]" "(Optional) Output full paths for all files matched by [regex] (Used to turn off the default behaviour for matching files of only outputting path to the .framework bundle for files contained within)" 324 | printf " %s\t%s\n" "-i [regex]" "(Optional) Igore item(s) matching [regex] in output" 325 | printf "\n" 326 | } 327 | 328 | #////////////////////////////////////////////////////////////////////////////////////////////////// 329 | ### 330 | ### MAIN SCRIPT 331 | ### 332 | #////////////////////////////////////////////////////////////////////////////////////////////////// 333 | 334 | parse_command_line_options "${@}" 335 | for (( i=0; i<${#target_executables[@]}; i++)); do 336 | targetExecutable="${target_executables[i]}" 337 | resolve_dependencies_for_target "${targetExecutable}" 338 | done 339 | clean_and_sort_array external_dependencies 340 | clean_and_sort_array bundled_dependencies 341 | if [[ ${outputAll} != yes ]]; then 342 | find_missing_dependencies_on_volume external_dependencies missing_external_dependencies 343 | fi 344 | 345 | # Print result 346 | missing_external_dependencies_count=${#missing_external_dependencies[@]} 347 | 348 | if [[ ${outputRegex} != yes ]]; then 349 | if [[ ${outputAll} == yes ]]; then 350 | if [[ ${#external_dependencies[@]} -ne 0 ]]; then 351 | printf "\n%s\n" "[${targetExecutable} - All Dependencies]" 352 | for ((i=0; i<${#external_dependencies[@]}; i++)); do 353 | if [[ -n ${outputIgnoreRegex} && ${external_dependencies[i]} =~ ${outputIgnoreRegex} ]]; then 354 | continue 355 | fi 356 | printf "\t%s\n" "$((${i}+1)) ${external_dependencies[i]}" 357 | if [[ ${outputReferences} == yes ]]; then 358 | printf "\n\t\t%s\n" "## Referenced by the following sources ##" 359 | oldIFS=${IFS}; IFS=$'\n' 360 | current_key_value=( $( /usr/libexec/PlistBuddy -c "Print '""${external_dependencies[i]}""'" "${path_tmp_relational_plist}" | grep -Ev [{}] | sed -E 's/^[ $( printf '\t' )]*//' 2>&1 ) ) 361 | IFS=${oldIFS} 362 | for ((j=0; j<${#current_key_value[@]}; j++)); do 363 | printf "\t\t%s\n" "${current_key_value[j]}" 364 | done 365 | printf "\n" 366 | fi 367 | done 368 | else 369 | printf "\n%s\n" "[${1##*/} - No Dependencies]" 370 | fi 371 | else 372 | if [[ ${missing_external_dependencies_count} -ne 0 ]]; then 373 | printf "\n%s\n" "[${targetExecutable} - Missing Dependencies]" 374 | for ((i=0; i&1 ) ) 383 | IFS=${oldIFS} 384 | for ((j=0; j<${#current_key_value[@]}; j++)); do 385 | printf "\t\t%s\n" "${current_key_value[j]}" 386 | done 387 | printf "\n" 388 | fi 389 | done 390 | else 391 | printf "\n%s\n" "[${1##*/} - All Dependencies Exist]" 392 | fi 393 | fi 394 | else 395 | if [[ ${outputRegexXML} == yes ]]; then 396 | outputPrefix="" 397 | outputSuffix="" 398 | fi 399 | if [[ ${outputAll} == yes ]]; then 400 | if [[ ${#external_dependencies[@]} -ne 0 ]]; then 401 | for ((i=0; i<${#external_dependencies[@]}; i++)); do 402 | if [[ -n ${outputIgnoreRegex} && ${external_dependencies[i]} =~ ${outputIgnoreRegex} ]]; then 403 | continue 404 | fi 405 | dependency_folder=${external_dependencies[i]%/*} 406 | dependency_item=$( sed 's/[+]/\\&/g' <<< "${external_dependencies[i]##*/}" ) 407 | if [[ ( ${outputAbsolutePath} == yes || ${dependency_folder} =~ ${outputAbsolutePathForRegex} ) && ${dependency_folder} =~ .framework ]]; then 408 | printf "%s\n" "${outputPrefix}.*/$( sed -nE 's/^.*\/(.*.framework(\/.*$|$))/\1/p' <<< ${dependency_folder} )/${dependency_item}.*${outputSuffix}" 409 | else 410 | printf "%s\n" "${outputPrefix}.*/${dependency_folder##*/}/${dependency_item}.*${outputSuffix}" 411 | fi 412 | done 413 | fi 414 | else 415 | if [[ ${missing_external_dependencies_count} -ne 0 ]]; then 416 | for ((i=0; i