├── .gitignore
├── tools
├── uninstallAST
│ ├── README.md
│ └── uninstallAST
├── osxImageModifier
│ ├── README.md
│ ├── osxImageModifierScript.bash
│ └── osxImageModifier
├── privilegedHelperToolReset
│ ├── README.md
│ └── privilegedHelperToolReset
├── osxInstallerArchiver
│ ├── README.md
│ └── osxInstallerArchiver
├── privilegedHelperToolStatus
│ ├── README.md
│ └── privilegedHelperToolStatus
├── jekyllServe
│ ├── README.md
│ └── jekyllServe
├── sharedLibraryDependencyChecker
│ ├── README.md
│ └── sharedLibraryDependencyChecker
├── resetVMWare
│ └── resetVMWare.bash
├── letsEncryptJSS
│ ├── README.md
│ └── letsEncryptJSS
├── README.md
├── serverAppArchiver
│ ├── README.md
│ └── serverAppArchiver
└── modelUTIInfo
│ ├── README.md
│ └── modelUTIInfo.py
├── random
├── dmgLoopDSCore
│ ├── README.md
│ └── dmgLoopDSCore
├── dmgLoopServerApp
│ ├── README.md
│ └── dmgLoopServerApp
├── printDHCPOptions
│ ├── README.md
│ └── printDHCPOptions
├── reconnectWiFiNetwork
│ ├── README.md
│ ├── com.github.erikberglund.reconnectWiFiNetwork.plist
│ └── reconnectWiFiNetwork
├── modifyAuthorizationDB
│ ├── README.md
│ └── modifyAuthorizationDB
├── saveUserPictureToFile
│ ├── README.md
│ └── saveUserPictureToFile
├── modifyNetworkServiceIPv6
│ ├── README.md
│ └── modifyNetworkServiceIPv6
├── printUserWithMostLoggedInTime
│ ├── README.md
│ └── printUserWithMostLoggedInTime
├── createWeblocWithCustomIcon
│ ├── README.md
│ └── createWeblocWithCustomIcon
├── modifyNetworkServiceDelete
│ ├── README.md
│ └── modifyNetworkServiceDelete
├── modifyNetworkServiceOrder
│ ├── README.md
│ └── modifyNetworkServiceOrder
├── modifyNetworkServiceEnabled
│ ├── README.md
│ └── modifyNetworkServiceEnabled
├── printSIPStatus
│ ├── README.md
│ └── printSIPStatus
└── README.md
├── functions
├── Bash
│ ├── variables_script
│ │ ├── README.md
│ │ └── variables_script.sh
│ ├── variables_xattr-com-apple-FinderInfo
│ │ ├── README.md
│ │ └── variables_xattr-com-apple-FinderInfo.sh
│ ├── create_folder
│ │ ├── README.md
│ │ └── create_folder.sh
│ ├── move_file_ftp
│ │ ├── README.md
│ │ └── move_file_ftp.sh
│ ├── variables_sgr-escape-sequence
│ │ ├── README.md
│ │ └── variables_sgr-escape-sequence.sh
│ ├── README.md
│ └── folder_hierachy_from_date
│ │ ├── README.md
│ │ └── folder_hierachy_from_date.sh
└── README.md
├── installer
├── installerCreateUser
│ └── README.md
├── installerCurrentUserEnvVarTMPDIR
│ ├── README.md
│ └── installerCurrentUserEnvVarTMPDIR
└── README.md
├── README.md
└── snippets
├── README.md
├── macos_finder.md
├── macos_certificates.md
├── macos_os.md
├── macos_network.md
├── macos_netboot.md
├── macos_hardware.md
└── macos_diskimages.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/tools/uninstallAST/README.md:
--------------------------------------------------------------------------------
1 | ## uninstallAST
--------------------------------------------------------------------------------
/random/dmgLoopDSCore/README.md:
--------------------------------------------------------------------------------
1 | ## dmgLoopDSCore
2 |
3 |
--------------------------------------------------------------------------------
/random/dmgLoopServerApp/README.md:
--------------------------------------------------------------------------------
1 | ## dmgLoopServerApp
2 |
3 |
--------------------------------------------------------------------------------
/random/printDHCPOptions/README.md:
--------------------------------------------------------------------------------
1 | ## printDHCPOptions
2 |
3 |
--------------------------------------------------------------------------------
/tools/osxImageModifier/README.md:
--------------------------------------------------------------------------------
1 | ## osxImageModifier
2 |
3 |
--------------------------------------------------------------------------------
/random/reconnectWiFiNetwork/README.md:
--------------------------------------------------------------------------------
1 | # reconnectWiFiNetwork
2 |
--------------------------------------------------------------------------------
/tools/privilegedHelperToolReset/README.md:
--------------------------------------------------------------------------------
1 | ## resetHelper
2 |
3 |
--------------------------------------------------------------------------------
/random/modifyAuthorizationDB/README.md:
--------------------------------------------------------------------------------
1 | ## modifyAuthorizationDB
2 |
3 |
--------------------------------------------------------------------------------
/random/saveUserPictureToFile/README.md:
--------------------------------------------------------------------------------
1 | ## saveUserPictureToFile
2 |
3 |
--------------------------------------------------------------------------------
/tools/osxInstallerArchiver/README.md:
--------------------------------------------------------------------------------
1 | ## osxInstallerArchiver
2 |
3 |
--------------------------------------------------------------------------------
/random/modifyNetworkServiceIPv6/README.md:
--------------------------------------------------------------------------------
1 | ## modifyNetworkServiceIPv6
2 |
3 |
--------------------------------------------------------------------------------
/random/printUserWithMostLoggedInTime/README.md:
--------------------------------------------------------------------------------
1 | ## printUserWithMostLoggedInTime
--------------------------------------------------------------------------------
/random/createWeblocWithCustomIcon/README.md:
--------------------------------------------------------------------------------
1 | ## createWeblocWithCustomIcon
2 |
3 |
--------------------------------------------------------------------------------
/random/modifyNetworkServiceDelete/README.md:
--------------------------------------------------------------------------------
1 | ## modifyNetworkServiceDelete
2 |
3 |
--------------------------------------------------------------------------------
/random/modifyNetworkServiceOrder/README.md:
--------------------------------------------------------------------------------
1 | ## modifyNetworkServiceOrder
2 |
3 |
--------------------------------------------------------------------------------
/tools/privilegedHelperToolStatus/README.md:
--------------------------------------------------------------------------------
1 | ## privilegedHelperToolStatus
2 |
3 |
--------------------------------------------------------------------------------
/random/modifyNetworkServiceEnabled/README.md:
--------------------------------------------------------------------------------
1 | ## modifyNetworkServiceEnabled
2 |
3 |
--------------------------------------------------------------------------------
/functions/Bash/variables_script/README.md:
--------------------------------------------------------------------------------
1 | # variables_script
2 |
3 | Variables I often use in scripts.
--------------------------------------------------------------------------------
/installer/installerCreateUser/README.md:
--------------------------------------------------------------------------------
1 | ## installerCreateUser
2 |
3 | Create local user account with multiple options.
4 |
--------------------------------------------------------------------------------
/tools/jekyllServe/README.md:
--------------------------------------------------------------------------------
1 | ## jekyllServe
2 |
3 | Small convenience script to start serving a jekyll site (and open it in a browser).
--------------------------------------------------------------------------------
/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/installerCurrentUserEnvVarTMPDIR/README.md:
--------------------------------------------------------------------------------
1 | ## installerCurrentUserEnvVarTMPDIR
2 |
3 | Get user environment variable(s) that aren't passed when run in installer.
4 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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)
--------------------------------------------------------------------------------
/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 | ```
--------------------------------------------------------------------------------
/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 | ```
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tools/uninstallAST/uninstallAST:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # LaunchDaemons created by Gateway Manager/AST installer
4 | gw_launch_daemons=( "com.apple.gw_controld.plist"\
5 | "com.apple.gw_datad.plist"\
6 | "com.apple.gw_logd.plist" )
7 |
8 | # Single files created by Gateway Manager/AST installer
9 | gw_files=( "/Library/Keychains/AppleServiceToolkit.keychain"\
10 | "/Library/Preferences/com.apple.gateway.plist"\
11 | "com.apple.GatewayManager.plist"
12 | "/usr/local/libexec/gw_controld"\
13 | "/usr/local/libexec/gw_datad"\
14 | "/usr/local/libexec/gw_logd" )
15 |
16 | # Folders created by Gateway Manager/AST installer
17 | gw_folders=( "/var/adg"\
18 | "/var/log/adg"
19 | "/Applications/Gateway Manager.app" )
20 |
21 | # NBIs created by Gateway Manager/AST installer
22 | nbis=( "AppleServiceToolkit.nbi" )
23 |
24 |
25 | # Quit Gateway Manager
26 | # Unload all services
27 | # Remove files and folders
28 | # Pkg forget and remove
29 |
30 | exit 0
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | ```
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 | ```
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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/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/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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