Skip to content

Instantly share code, notes, and snippets.

@patgmac
Created September 16, 2020 15:14
Show Gist options
  • Save patgmac/cad85674efc503cb0dbb3133dfe33ce8 to your computer and use it in GitHub Desktop.
Save patgmac/cad85674efc503cb0dbb3133dfe33ce8 to your computer and use it in GitHub Desktop.
#!/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