Created
September 16, 2020 15:14
-
-
Save patgmac/cad85674efc503cb0dbb3133dfe33ce8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script Name: jamfMigrator.sh | |
# By: Patrick Gallagher | |
# Updated: 06/11/2019 | |
version=1.2.7 | |
oldJSS="https://oldjss.company.com:8443" | |
newJSS="https://newjss.company.com" | |
ComputerName=$(/usr/sbin/scutil --get ComputerName) | |
jamf1="apiaccount" | |
jamf2=$(/usr/bin/security find-generic-password -ga keychain_item_name -w /Library/Keychains/System.keychain) # look at https://grahamrpugh.com/2018/08/14/api-passwords-in-keychain.html | |
#jamfURL="${oldJSS}/JSSResource/computers/udid" | |
jamfBinary="/usr/local/bin/jamf" | |
mySerial=$( system_profiler SPHardwareDataType | grep Serial | awk '{print $NF}' ) | |
udid=$(system_profiler SPHardwareDataType | grep UUID | awk '{print $3}') | |
#getUUID=$(/usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice | /usr/bin/awk '/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }') | |
launchDaemonLabel="com.company.jamfMigrator" | |
launchDaemonLocation="/Library/LaunchDaemons/${launchDaemonLabel}.plist" | |
logLocation="/var/sandbox/jamf_cloud_migration.log" | |
osMinorVersion=$( /usr/bin/sw_vers -productVersion | /usr/bin/cut -d. -f2 ) | |
timestamp=$( /bin/date '+%Y-%m-%d-%H-%M-%S' ) | |
loggedInUser=$( python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");' ) | |
# text display variables | |
windowType="utility" # [hud | utility | fs] | |
jhTitle="Jamf Cloud Migration" | |
icon="/private/var/sandbox/logo.png" # path | |
iconSize="128" # pixels | |
alignDescription="left" #[right | left | center | justified | natural] | |
alignHeading="center" # [right | left | center | justified | natural] | |
defaultButton=1 | |
################################################## | |
# Setup Functions | |
function checkJSSConnection { | |
if [[ -e $jamfBinary ]]; then | |
checkAvailablity=$(${jamfBinary} checkJSSConnection) | |
exitStatus $? "${1} is unavailable at this time. Suspending until next interval..." | |
if [[ $checkAvailablity == *"${1}"* ]]; then | |
# If the check contains the JSS we're expecting... | |
if [[ $checkAvailablity != *"The JSS is available"* ]]; then | |
# If the JSS is unavailable, suspend further processing... | |
/usr/bin/logger -s "${1}""} is unavailable at this time. Suspending until next interval..." 2>> $logLocation | |
promptReboot | |
else | |
# If the JSS is available, then continue... | |
/usr/bin/logger -s "${1} is available, continuing..." 2>> $logLocation | |
fi | |
elif [[ $checkAvailablity == *"${newJSS}"* ]]; then | |
/usr/bin/logger -s "Already migrated, tearing down" 2>> $logLocation | |
tearDown | |
fi | |
else | |
/usr/bin/logger -s "Unable to run \`jamf checkJSSConnection\`" 2>> $logLocation | |
/usr/bin/logger -s "Assuming Jamf Framework has been removed..." 2>> $logLocation | |
fi | |
} | |
function promptError() { | |
jhDescription="There was an error in the migration process. Please try again. | |
If the problem continues, please visit the WorkBench" | |
button1="Ok" | |
/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \ | |
-windowType $windowType -title "$jhTitle" -alignHeading "$alignHeading" -alignDescription "$alignDescription" -description "$jhDescription" \ | |
-button1 "$button1" -defaultButton "$defaultButton" -icon "$icon" -iconSize "$iconSize" | |
exit 50 | |
} | |
function promptReboot() { | |
/usr/bin/logger -s "Starting Reboot" 2>> $logLocation | |
jhDescription="Your computer needs to be rebooted before migration can continue. Please close any open applications" | |
button1="Reboot" | |
button2="Cancel" | |
cancelButton=2 # Button 1 or 2 | |
button=$(/Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper \ | |
-windowType $windowType -title "$jhTitle" -alignHeading "$alignHeading" -alignDescription "$alignDescription" -description "$jhDescription" \ | |
-button1 "$button1" -button2 "$button2" -defaultButton "$defaultButton" -cancelButton "$cancelButton" -icon "$icon" -iconSize "$iconSize") | |
if [ "$button" -eq 0 ]; then | |
/usr/local/bin/jamf displayMessage -message "Your computer will now reboot" | |
/usr/bin/logger -s "Jamf Migration: User chose to reboot" 2>> $logLocation | |
# Prevent applications from re-opening. Doing this so the UMAD screen isn't hidden after reboot | |
/bin/rm /Users/$loggedInUser/Library/Preferences/ByHost/com.apple.loginwindow.* | |
/usr/local/bin/jamf reboot -immediately | |
elif [ "$button" -eq 2 ]; then | |
/usr/local/bin/jamf displayMessage -message "Please reboot at your earliest convenience" | |
/bin/rm /Users/$loggedInUser/Library/Preferences/ByHost/com.apple.loginwindow.* | |
/usr/bin/logger -s "Jamf Migration: User cancelled reboot" 2>> $logLocation | |
exit 1 | |
fi | |
} | |
function exitStatus { | |
if [[ $1 != "0" ]]; then | |
/usr/bin/logger -s "Failed" 2>> $logLocation | |
if [[ -e $2 ]]; then | |
/usr/bin/logger -s "Error: ${2}" 2>> $logLocation | |
fi | |
exit 0 | |
else | |
/usr/bin/logger -s "Success!" 2>> $logLocation | |
fi | |
} | |
function migrateNetwork () { | |
wirelessInterface=$(/usr/sbin/networksetup -listallhardwareports | grep -E -A 2 "(AirPort|Wi-Fi)" | grep Device | awk '{print $2}') | |
if [[ $(/usr/bin/profiles -P | egrep 735a0ab0-0610-0136-409e-7a005c4ab000) ]]; then | |
/usr/bin/logger -s "Jamf Migration: Removing local network profile" 2>> $logLocation | |
/usr/bin/profiles -R -p 735a0ab0-0610-0136-409e-7a005c4ab000 | |
fi | |
if [[ $(/usr/bin/profiles -P | egrep D8CD0947-B02F-4A4F-B5A1-CA718575014E-mod) ]]; then | |
/usr/bin/logger -s "Jamf Migration: Removing old local network profile" 2>> $logLocation | |
/usr/bin/profiles -R -p D8CD0947-B02F-4A4F-B5A1-CA718575014E-mod | |
fi | |
# Put device on PublicWiFi | |
if [[ $currentSSID != "PublicWiFi" ]]; then | |
/usr/sbin/networksetup -removepreferredwirelessnetwork "$wirelessInterface" PublicWiFi | |
/usr/sbin/networksetup -addpreferredwirelessnetworkatindex "$wirelessInterface" PublicWiFi 0 OPEN | |
enablePubWifi=$(/usr/sbin/networksetup -setairportnetwork "$wirelessInterface" PublicWiFi) | |
if [[ $enablePubWifi == "" ]]; then | |
currentSSID=$(/usr/sbin/networksetup -getairportnetwork "$wirelessInterface" | sed 's/Current AirPort Network: //g' | awk '{print $4}') | |
/usr/bin/logger -s "Jamf Migration: Currently on the network: $currentSSID" 2>> $logLocation | |
/usr/bin/logger -s "Jamf Migration: Successfully joined PublicWiFi." 2>> $logLocation | |
else | |
/usr/bin/logger -s "Jamf Migration: Joining PublicWiFi Failed, might be remote or might be wired" 2>> $logLocation | |
/usr/bin/logger -s "Jamf Migration: Currently on the network: $currentSSID" 2>> $logLocation | |
fi | |
fi | |
} | |
function checkMDMProfileInstalled() { | |
enrolled=$(/usr/bin/profiles -C | /usr/bin/grep "00000000-0000-0000-A000-4A414D460003") | |
if [ "$enrolled" != "" ]; then | |
/usr/bin/logger -s "MDM Profile Present..." 2>> $logLocation | |
mdmPresent=1 | |
else | |
/usr/bin/logger -s "MDM Profile Successfully Removed..." 2>> $logLocation | |
mdmPresent=0 | |
fi | |
} | |
# Mark the device as Migrated" | |
function setMigrationStatus() { | |
/usr/bin/logger -s "Jamf Migration: Sending command to set migration status in old JSS" 2>> "$logLocation" | |
curl -sfku "${jamf1}:${jamf2}" -X "PUT" "${oldJSS}/JSSResource/computers/udid/$udid/subset/extension_attributes" \ | |
-H "Content-Type: application/xml" \ | |
-H "Accept: application/xml" \ | |
-d "<computer><extension_attributes><extension_attribute><id>149</id><name>Migrated to Cloud</name><type>String</type><value>Yes</value></extension_attribute></extension_attributes></computer>" \ | |
> /dev/null 2>&1 | |
if [ "$?" == "0" ]; then | |
/usr/bin/logger -s "Jamf Migration: Marked as migrated in Old JSS" 2>> "$logLocation" | |
else | |
/usr/bin/logger -s "Jamf Migration: Failed to Mark as migrated in Old JSS" 2>> "$logLocation" | |
fi | |
} | |
function jamfUnmanageDeviceAPI() { | |
/usr/bin/logger -s "Jamf Migration: Sending API Payload to Unmanage Computer" 2>> $logLocation | |
#/usr/bin/curl --silent --show-error --fail --user "${jamf1}:${jamf2}" "${jamfURL}/${getUUID}" --header "Content-Type: text/xml" --upload-file $unmanagePayload --request PUT | |
sleep 10 | |
checkMDMProfileInstalled | |
counter=0 | |
until [ "$mdmPresent" -eq "0" ] || [ "$counter" -gt "9" ]; do | |
((counter++)) | |
/usr/bin/logger -s "Check ${counter}/10; MDM Profile Present; waiting 20 seconds to re-check..." 2>> $logLocation | |
/usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${jamf1}:${jamf2} ${oldJSS}/JSSResource/computercommands/command/UnmanageDevice/id/${jamfProCompID} | |
if [[ "$?" == "0" ]]; then | |
/usr/bin/logger -s "Jamf Migration: Sent Remove MDM API Payload successfully" 2>> $logLocation | |
else | |
/usr/bin/logger -s "Jamf Migration: Problem Unmanaging Computer" 2>> $logLocation | |
fi | |
sleep 20 | |
checkMDMProfileInstalled | |
done | |
} | |
function tearDown { | |
# Remove keychain item | |
/usr/bin/security delete-generic-password -a keychain_item_name /Library/Keychains/System.keychain | |
# Remove LaunchDaemon | |
/usr/bin/logger -s "Jamf Migration: Deleting LaunchDaemon" 2>> $logLocation | |
/bin/rm -f "$launchDaemonLocation" | |
exitStatus $? | |
# Delete Self | |
/usr/bin/logger -s "Jamf Migration: Deleting Script" 2>> $logLocation | |
/bin/rm -f "$0" | |
exitStatus $? | |
promptReboot | |
/usr/bin/logger -s "Jamf Migration: ***** On-Prem removal process: COMPLETE *****" 2>> $logLocation | |
/usr/bin/logger -s "Jamf Migration: ***** Enrollment occurs after reboot" 2>> $logLocation | |
# Unload LaunchDaemon | |
/usr/bin/logger -s "Jamf Migration: Unloading LaunchDaemon" 2>> $logLocation | |
/bin/launchctl remove $launchDaemonLabel | |
exit 0 | |
} | |
#### End of function setup | |
## Start of script actions | |
/usr/bin/touch $logLocation | |
/usr/bin/logger -f $logLocation | |
/usr/bin/logger -s "Jamf Migration: ***** Jamf Migration process for $ComputerName: START *****" 2>> $logLocation | |
/usr/bin/logger -s "Jamf Migration: Script version $version" 2>> $logLocation | |
if [[ $jamf2 == "" ]]; then | |
logger -s "Jamf Migration: Failed to get API..." 2>> $logLocation | |
promptError | |
else | |
/usr/bin/killall "Self Service" | |
# Enable MDM Debug logging | |
rm -rf /Library/Logs/ManagedClient/* | |
/usr/bin/logger -s "Jamf Migration: Enabling MDM Debug Logging" 2>> $logLocation | |
/usr/bin/defaults write /Library/Preferences/com.apple.MCXDebug debugOutput -2 | |
/usr/bin/defaults write /Library/Preferences/com.apple.MCXDebug collateLogs 1 | |
/usr/bin/touch /var/db/MDM_EnableDebug | |
# Retrive JPS record for computer based on serial number | |
jamfProCompID=$(/usr/bin/curl -s -u ${jamf1}:${jamf2} -H "Accept: text/xml" ${oldJSS}/JSSResource/computers/serialnumber/${mySerial}/subset/general | /usr/bin/xpath "//computer/general/id/text()") | |
if [[ $jamfProCompID == "" ]]; then | |
logger -s "Jamf Migration: Failed to retrive record from JPS..." 2>> $logLocation | |
promptError | |
else | |
/usr/bin/logger -s "Jamf Migration: Machine device ID is ${jamfProCompID}" 2>> $logLocation | |
fi | |
fi | |
/usr/bin/logger -s "Jamf Migration: Checking if the current JSS instance is available..." 2>> $logLocation | |
# Function checkJSSConnection | |
checkJSSConnection $oldJSS | |
## Move to a non-MDM controlled network | |
migrateNetwork | |
## Remove Configuration Profiles | |
logger -s "Jamf Migration: Removing MDM Profiles ..." 2>> $logLocation | |
if [ "${osMinorVersion}" -ge 13 ]; then | |
logger -s "Jamf Migration: macOS $(/usr/bin/sw_vers -productVersion); attempting removal via jamf binary..." 2>> $logLocation | |
/usr/local/bin/jamf removeMdmProfile -verbose | |
sleep 3 | |
checkMDMProfileInstalled | |
if [ "$mdmPresent" == "0" ]; then | |
logger -s "Jamf Migration: Successfully Removed MDM Profile..." 2>> $logLocation | |
else | |
logger -s "Jamf Migration: MDM Profile Present; attempting removal via API..." 2>> $logLocation | |
jamfUnmanageDeviceAPI | |
if [ "$mdmPresent" != "0" ]; then | |
logger -s "Jamf Migration: Unable to remove MDM Profile; exiting..." 2>> $logLocation | |
promptError | |
fi | |
fi | |
else | |
logger -s "Jamf Migration: macOS $(/usr/bin/sw_vers -productVersion); attempting removal via jamf binary..." 2>> $logLocation | |
/usr/local/bin/jamf removeMdmProfile -verbose | |
sleep 3 | |
checkMDMProfileInstalled | |
if [ "$mdmPresent" == "0" ]; then | |
logger -s "Jamf Migration: Successfully Removed MDM Profile..." 2>> $logLocation | |
else | |
logger -s "Jamf Migration: MDM Profile Present; attempting removal via API..." 2>> $logLocation | |
jamfUnmanageDeviceAPI | |
if [ "$mdmPresent" == "0" ]; then | |
logger -s "Jamf Migration: Successfully Removed MDM Profile..." 2>> $logLocation | |
else | |
logger -s "Jamf Migration: macOS $(/usr/bin/sw_vers -productVersion); attempting force removal..." 2>> $logLocation | |
/bin/mv -v /var/db/ConfigurationProfiles/ "/var/db/ConfigurationProfiles-$timestamp" | |
checkMDMProfileInstalled | |
if [ "$mdmPresent" != "0" ]; then | |
logger -s "Jamf Migration: Unable to remove MDM Profile; exiting..." 2>> $logLocation | |
exit 0 | |
fi | |
fi | |
fi | |
fi | |
# Check if outset is installed, if not, install it. | |
if [[ -f $jamfBinary ]]; then | |
if [[ ! -e /usr/local/outset/outset ]]; then | |
/usr/bin/logger -s "Jamf Migration: Outset not present, installing..." 2>> $logLocation | |
$jamfBinary policy -event outset -randomdelayseconds 0 | |
fi | |
else | |
/usr/bin/logger -s "Jamf Migration: Jamf binary not present" 2>> $logLocation | |
fi | |
# Adding a script to outset which will be run on the next boot to start the enrollment | |
cat > /usr/local/outset/boot-once/remove_casper_framework.sh << "EOF" | |
#!/bin/bash | |
logged_in_user=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");'` | |
logged_in_user_uid=`id -u "$logged_in_user"` | |
logLocation="/var/sandbox/jamf_cloud_migration.log" | |
/usr/bin/logger -f $logLocation | |
/usr/bin/logger -s "Jamf Migration: Removing Framework" 2>> $logLocation | |
/usr/local/bin/jamf removeFramework | |
/usr/bin/logger -s "Jamf Migration: Opening Migration Instructions PDF" | |
/bin/launchctl asuser "$logged_in_user_uid" /usr/bin/open /var/sandbox/migration_instructions.pdf | |
/usr/bin/logger -s "Jamf Migration: Installing umad" 2>> $logLocation | |
/usr/sbin/installer -pkg /var/sandbox/umad-1.0.pkg -target / | |
EOF | |
chmod 755 /usr/local/outset/boot-once/remove_casper_framework.sh | |
# Remove previous ouset things if present. | |
if [[ -e /usr/local/outset/boot-once/provision_boot-once.sh ]]; then | |
rm /usr/local/outset/boot-once/provision_boot-once.sh | |
fi | |
if [[ -e /usr/local/outset/boot-every/repair_bandsaw.sh ]]; then | |
rm /usr/local/outset/boot-every/repair_bandsaw.sh | |
fi | |
if [[ -e /usr/local/outset/boot-every/provision_boot-every.sh ]]; then | |
rm /usr/local/outset/boot-every/provision_boot-every.sh | |
fi | |
setMigrationStatus | |
tearDown |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment