├── jamfMigrator.png
├── FV2 Reissue Script.png
├── Create FV_enabled User.png
├── com.github.mlbz521.jamfMigrator.plist
├── LICENSE
├── postinstall.sh
├── README.md
└── jamfMigrator.sh
/jamfMigrator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLBZ521/jamfMigrator/HEAD/jamfMigrator.png
--------------------------------------------------------------------------------
/FV2 Reissue Script.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLBZ521/jamfMigrator/HEAD/FV2 Reissue Script.png
--------------------------------------------------------------------------------
/Create FV_enabled User.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLBZ521/jamfMigrator/HEAD/Create FV_enabled User.png
--------------------------------------------------------------------------------
/com.github.mlbz521.jamfMigrator.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Label
6 | com.github.mlbz521.jamfMigrator
7 | ProgramArguments
8 |
9 | /bin/bash
10 | -c
11 | (/private/var/tmp/jamfMigrator.sh)
12 |
13 | RunAtLoad
14 |
15 | StartInterval
16 | 600
17 | AbandonProcessGroup
18 |
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Zack T
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/postinstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ###################################################################################################
4 | # Script Name: postinstall.sh
5 | # By: Zack Thompson / Created: 11/20/2017
6 | # Version: 1.0 / Updated: 11/21/2017 / By: ZT
7 | #
8 | # Description: This script stages files and loads a LaunchDaemon.
9 | #
10 | ###################################################################################################
11 |
12 | # Define the Variables
13 | pkgDir=$(/usr/bin/dirname $0)
14 | launchDaemonLabel="com.github.mlbz521.jamfMigrator"
15 | osVersion=$(sw_vers -productVersion | /usr/bin/awk -F '.' '{print $2}')
16 | launchDaemonLocation="/Library/LaunchDaemons/${launchDaemonLabel}.plist"
17 |
18 | # Stages the bits
19 | cp "${pkgDir}/${launchDaemonLabel}.plist" $launchDaemonLocation
20 | cp -R "${pkgDir}/jamfMigrator.sh" /private/var/tmp/
21 | cp -R "${pkgDir}/QuickAdd.pkg" /private/var/tmp/
22 |
23 | # Determine proper launchctl syntax based on OS Version
24 | if [[ ${osVersion} -ge 11 ]]; then
25 | /bin/launchctl bootstrap system $launchDaemonLocation
26 | /bin/launchctl enable system/$launchDaemonLabel
27 | elif [[ ${osVersion} -le 10 ]]; then
28 | /bin/launchctl load $launchDaemonLocation
29 | fi
30 |
31 | exit 0
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jamfMigrator
2 | This project assists with migrating from one JSS to another JSS. I will describe the setup process and logic of the script below.
3 |
4 | I've added an additional workflow to this project to include some kind of option for 'migrating' FileVault keys to the new JSS.
5 |
6 | The overall scope of this project is to:
7 | * Mark the computer in the old Jamf environment as “unmanaged” – so you can easily track what has, and has not, migrated
8 | * Remove the old Jamf Framework – which removes the main MDM Profile and all traces of Jamf related Config Profiles, MDM certs, etc
9 | * Join computer to the new Jamf environment in a clean state
10 | * Reissue a new FileVault Personal Recovery Key (requires a known FileVault Unlock Key)
11 |
12 | In my testing, the overall process took, from policy execution to the script completing, roughly one minute and fifteen seconds.
13 |
14 | **Inspired by several discussions on JamfNation:**
15 | * https://www.jamf.com/jamf-nation/discussions/10866/un-manage-and-keep-in-inventory
16 | * https://www.jamf.com/jamf-nation/discussions/10456/remove-framework-after-imaging
17 | * And several other threads I've read regarding Jamf managed state recovery methods (See: rtrouton's CasperCheck)
18 |
19 | #### WorkFlow ####
20 |
21 | 
22 |
23 | ## Setup ##
24 |
25 | Edit the `jamfMigrator.sh` script and modify the following values:
26 | * `newJSS`
27 | * `oldJSS`
28 | * `jamfAPIUser`
29 | * `jamfAPIPassword`
30 | * If you change the LaunchDaemon file and Label names, you'll need to update those in all files as well
31 | * If your JSS has a self signed cert, you may need to add `-k` (`--insecure`) to the `curl` command to disable SSL verification
32 |
33 | API Permissions I needed were:
34 | * JSS Objects > Update >
35 | * Computers
36 | * Users
37 |
38 | Create a payload-free package with all three files and a QuickAdd package created for the new JSS instance
39 | * If using `munkipkg`, add all files into the scripts folder
40 | * If using Packages, add the `postinstall.sh` script as the Post-installation script and all other files into Scripts > Additional Resources
41 |
42 | Grab the `reissue_FileVaultPRK.sh` script [here](https://github.com/MLBZ521/macOS.JAMF/blob/master/Scripts/reissue_FileVaultPRK.sh)
43 |
44 | Upload these items:
45 | * `jamfMigrator.pkg` to the old JSS
46 | * `reissue_FileVaultPRK.sh` to the new JSS
47 |
48 | Create the following Policies:
49 | * In the Old JSS
50 | * *(If needed)* Policy to Create a FileVault Enabled User. [Example](https://github.com/MLBZ521/jamfMigrator/blob/master/Create%20FV_enabled%20User.png)
51 | * Policy to deploy the `jamfMigrator.pkg` Package
52 | * In the New JSS
53 | * Policy with the `reissue_FileVaultPRK.sh` with a known FileVault Unlock Key. [Example](https://github.com/MLBZ521/jamfMigrator/blob/master/FV2%20Reissue%20Script.png)
54 |
55 |
56 | ## Logic ##
57 |
58 | #### jamfMigrator.sh ####
59 |
60 | This script does the heavy lifting.
61 |
62 | * Checks if it can contact the old JSS (uses `jamf checkJSSConnection`)
63 | * If successful, continues
64 | * If an unsuccessful attempt to connect to the old JSS, quit and try again on the next interval
65 | * Sends a generated xml file to the old JSS, via the API, to mark the machine as unmanaged
66 | * The UUID is grabbed from the machine to associate it to its' Jamf Record
67 | * Jamf Framework is removed
68 | * QuickAdd package for the new JSS is installed
69 | * Checks if it can contact the new JSS (uses `jamf checkJSSConnection`)
70 | * If successful, continues
71 | * If unsuccessful
72 | * If still attempting to connect to the old JSS, quit and try again on the next interval
73 | * If it attempts to connect to the new JSS, but fails, quit and try again on the next interval
74 | * Begins 'tearDown' -- cleans up all staged bits
75 |
76 | After virtually every action, the Exit Code (`$?`) is checked to see if it was successful; if it isn't, the script exists and will be launched again at the next interval.
77 |
78 | Logs each process step to `system.log`
79 |
80 |
81 | #### com.github.mlbz521.jamfMigrator.plist ####
82 |
83 | This is the LaunchDaemon that staged and loaded by the `postinstall.sh` script.
84 |
85 | * On load, the LaunchDaemon will execute the `jamfMigrator.sh script` as a child process
86 | * If the script fails, the LaunchDaemon will launch again in ten minutes
87 |
88 |
89 | #### postinstall.sh ####
90 |
91 | This script stages the bits to do the work. You can use it with any payload-free pkg creation method (munkipkg, Packages, etc).
92 |
93 | * On install of the payload-free package, it will stage the bits:
94 | * `cp com.github.mlbz521.jamfMigrator.plist /Library/LaunchDaemons/`
95 | * `cp jamfMigrator.sh /private/var/tmp/`
96 | * `cp QuickAdd.pkg /private/var/tmp/`
97 |
98 | * And then load the LaunchDaemon based on the OS Version
99 | * if >= 10.11
100 | * `/bin/launchctl bootstrap system $launchDaemonLocation`
101 | * `/bin/launchctl enable system/$launchDaemonLabel`
102 | * if <= 10.10
103 | * `/bin/launchctl load $launchDaemonLocation`
104 |
105 |
106 | #### reissue_FileVaultPRK.sh ####
107 |
108 | This script issues a new FileVault Personal Recovery Key. It will require a known FileVault Unlock Key, which can be one of the following:
109 | * A FileVault Enable Account with a known password
110 | * Current FileVault Personal Recovery Key
111 |
112 | Obviously, the easiest and most 'scopable' way to do this to have a FileVault Enabled Account. If you do not have a known FileVault Enable Account with a known password, then on ≤10.12, you can easily create one via Jamf before migrating to the new JSS. (Jamf cannot create a FV_Enabled account on 10.13+ machines currently.)
113 |
114 | Add the script to a Policy in the new JSS and enter the known Unlock Key in the Script Parameter.
115 |
116 | After migrating and after this policy successfully runs (i.e. the new JSS has a **valid** FileVault Recovery Key) the account can be FV disabled or deleted.
117 |
--------------------------------------------------------------------------------
/jamfMigrator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ###################################################################################################
4 | # Script Name: jamfMigrator.sh
5 | # By: Zack Thompson / Created: 11/17/2017
6 | # Version: 1.0 / Updated: 11/21/2017 / By: ZT
7 | #
8 | # Description: This script uses the Jamf API to mark the device as unmanaged, remove the current Jamf Framework, then install a new QuickAdd package, and finally cleanup after itself.
9 | #
10 | # Inspired by several discussions on JamfNation:
11 | # https://www.jamf.com/jamf-nation/discussions/10866/un-manage-and-keep-in-inventory
12 | # https://www.jamf.com/jamf-nation/discussions/10456/remove-framework-after-imaging
13 | # And several other threads I've read regarding Jamf managed state recovery methods (See: rtrouton's CasperCheck)
14 | #
15 | ###################################################################################################
16 |
17 | /usr/bin/logger -s "***** jamfMigrator process: START *****"
18 |
19 | ##################################################
20 | # Define Variables
21 | newJSS="https://newjss.company.com:8443"
22 | oldJSS="https://oldjss.company.com.edu:8443"
23 | jamfAPIUser="APIUsername"
24 | jamfAPIPassword="APIPassword"
25 | jamfURL="${oldJSS}/JSSResource/computers/udid"
26 | jamfBinary="/usr/local/bin/jamf"
27 | getUUID=$(/usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice | /usr/bin/awk '/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }')
28 | osVersion=$(sw_vers -productVersion | /usr/bin/awk -F '.' '{print $2}')
29 | unmanagePayload="/private/tmp/unmanage_UUID.xml"
30 | launchDaemonLabel="com.github.mlbz521.jamfMigrator"
31 | launchDaemonLocation="/Library/LaunchDaemons/${launchDaemonLabel}.plist"
32 | enrollPkg="/private/var/tmp/QuickAdd.pkg"
33 |
34 | # Stage the "unmanage" PUT payload
35 | /bin/echo "
36 |
37 |
38 |
39 | false
40 |
41 |
42 | " > $unmanagePayload
43 |
44 | ##################################################
45 | # Setup Functions
46 |
47 | function checkJSSConnection {
48 | if [[ -e $jamfBinary ]]; then
49 | checkAvailablity=$(${jamfBinary} checkJSSConnection)
50 | # Function exitStatus
51 | exitStatus $? "${1} is unavailable at this time. Suspending until next interval..."
52 |
53 | if [[ $checkAvailablity == *"${1}"* ]]; then
54 | # If the check contains the JSS we're expecting...
55 | if [[ $checkAvailablity != *"The JSS is available"* ]]; then
56 | # If the JSS is unavailable, suspend further processing...
57 | /usr/bin/logger -s "${1} is unavailable at this time. Suspending until next interval..."
58 | exit 1
59 | else
60 | # If the JSS is available, then continue...
61 | /usr/bin/logger -s "${1} is available, continuing..."
62 | fi
63 | elif [[ $checkAvailablity == *"${oldJSS}"* ]]; then
64 | # If the check is the oldJSS when we're expecting the newJSS, something went wrong, suspend further processing...
65 | /usr/bin/logger -s "Failed -- still pointing to the old JSS Server... Suspending until next interval..."
66 | exit 1
67 | elif [[ $checkAvailablity == *"${newJSS}"* ]]; then
68 | # This elif is for, if somehow on the first checkJSSConnection run, it's connected to the new JSS, then we're good to go.
69 | /usr/bin/logger -s "Connected to the new JSS instance!"
70 | /usr/bin/logger -s "***** jamfMigrator process: COMPLETE *****"
71 | exit 0
72 | fi
73 | else
74 | /usr/bin/logger -s "Unable to run \`jamf checkJSSConnection\`"
75 | /usr/bin/logger -s "Assuming Jamf Framework has been removed..."
76 | # Function enrollMachine
77 | enrollMachine
78 | fi
79 | }
80 |
81 | function enrollMachine {
82 | # Enroll machine
83 | /usr/bin/logger -s "Installing QuickAdd package"
84 | /usr/sbin/installer -dumplog -verbose -pkg $enrollPkg -allowUntrusted -target /
85 | # Function exitStatus
86 | exitStatus $?
87 | }
88 |
89 | function tearDown {
90 | # Unload LaunchDaemon
91 | /usr/bin/logger -s "Unloading LaunchDaemon"
92 | # Determine proper launchctl syntax
93 | if [[ ${osVersion} -ge 11 ]]; then
94 | /bin/launchctl bootout system $launchDaemonLocation
95 | elif [[ ${osVersion} -le 10 ]]; then
96 | /bin/launchctl unload $launchDaemonLocation
97 | fi
98 | # Function exitStatus
99 | exitStatus $?
100 |
101 | # Remove LaunchDaemon
102 | /usr/bin/logger -s "Deleting LaunchDaemon"
103 | /bin/rm -f $launchDaemonLocation
104 | # Function exitStatus
105 | exitStatus $?
106 |
107 | # Delete QuickAdd Package
108 | /usr/bin/logger -s "Deleting QuickAdd Package"
109 | /bin/rm -f $enrollPkg
110 | # Function exitStatus
111 | exitStatus $?
112 |
113 | # Delete Self
114 | /usr/bin/logger -s "Deleting Script"
115 | /bin/rm -f "$0"
116 | # Function exitStatus
117 | exitStatus $?
118 | }
119 |
120 | function exitStatus {
121 | if [[ $1 != "0" ]]; then
122 | /usr/bin/logger -s " -> Failed"
123 | if [[ -e $2 ]]; then
124 | /usr/bin/logger -s "Error: ${2}"
125 | fi
126 | exit 1
127 | else
128 | /usr/bin/logger -s " -> Success!"
129 | fi
130 | }
131 |
132 | ##################################################
133 | # Now that we have our work setup...
134 |
135 | /usr/bin/logger -s "Checking if the current JSS instance is available..."
136 | # Function checkJSSConnection
137 | checkJSSConnection $oldJSS
138 |
139 | # Submit unamange payload to the JSS (add -k, --insecure to disabled SSL verification)
140 | /usr/bin/logger -s "Sending API Payload to Unmanage Computer"
141 | /usr/bin/curl --silent --show-error --fail --user "${jamfAPIUser}:${jamfAPIPassword}" "${jamfURL}/${getUUID}" --header "Content-Type: text/xml" --upload-file $unmanagePayload --request PUT
142 | # Function exitStatus
143 | exitStatus $?
144 |
145 | # Remove JAMF Binary
146 | /usr/bin/logger -s "Removing Framework"
147 | $jamfBinary removeFramework
148 | # Function exitStatus
149 | exitStatus $?
150 |
151 | # Function enrollMachine
152 | enrollMachine
153 |
154 | /usr/bin/logger -s "Checking if new JSS instance is available..."
155 | # Function checkJSSConnection
156 | checkJSSConnection $newJSS
157 |
158 | # Function tearDown
159 | tearDown
160 |
161 | /usr/bin/logger -s "***** jamfMigrator process: COMPLETE *****"
162 |
163 | exit 0
164 |
--------------------------------------------------------------------------------