Initial Commit

This commit is contained in:
macnotes
2024-05-20 20:35:15 -04:00
commit faad5d358a
11 changed files with 1431 additions and 0 deletions

159
ChangeLog.md Normal file
View File

@@ -0,0 +1,159 @@
# Setup Manager - Change Log
## v1.0RC
(2024-03-11)
- various minor fixes to localization, documentation, and small UI tweaks
- better error handling and display for some edge cases
- added ReadMe and License to installer pkg
## v0.9.1
(2023-11-20)
- Norwegian and Swedish localizations, thanks to Sam Wennerlund
- refactored process launching code, this should help with some stalling issues
- shutdown button should not stall anymore
- Setup Manager now caches the defaults at launch. This makes it more resilient to its configuration profile "disappearing" because the computer is not scope. (We still recommend scoping the Setup Manager Configuration profile as well as adding it to the Prestage.) This also addresses the custom UI "flickering" while it runs. (#21)
## v0.9
(2023-10-26)
- Help button
- new key `help` shows a help button (circled question mark) in the lower right corner. The "Continue" and/or "Shutdown" buttons will replace the "Help" when the appear
- see [Configuration Profile documentation](ConfigurationProfile.md#help) for more detail
- "About this Mac" info window
- now shows network connection status. With the option key, the info window shows the interface name and IP address
- to keep the info window clean, some (more) items are now only shown when opening the info window while holding option keys (Jamf Pro and Setup Manager version)
- updated Installomator to v10.5
- added new defaults key `overrideSerialNumber` to display a preset serial number, this is useful for creating screenshots or recordings
- main window is not resizable (#26)
- user entry with options menu would be empty unless manually set (#23)
- item progress indicators are now more distinct (#25)
- added "Powered by Jamf" and icon in button bar
- Setup Manager rearranges windows properly when a screen is attached or removed
- app and pkg are now signed and notarized with Jamf Developer certificates
- many more bug fixes and improvements
## v0.8.2
(2023-09-19)
- local files are now shown correctly with `icon`
- download speed is shown in macOS Sonoma
- fixed a strange race condition that led to large installomator installations stalling with Jamf School
- 'Shutdown' button is now hidden by default, since it breaks some of the workflows. You can unhide it by setting the `finalAction` key to `shutdown` (this will hide the continue button) or setting the `showBothButtons` key to `true` which will show both buttons.
## v0.8
(2023-09-05)
- Italian and Spanish localizations (Thanks to Nicola Lecchi, Andre Vilja and Javier Tetuan)
- fixed crashing bug when `background` is set
- 'Save Button' in User Entry now enables properly
- UI layout improvements
- main `icon` now properly displays wide aspect images
- watchPath actions time faster in DEBUG mode
- unloads Jamf Pro background check-in during workflow
- About this Mac…
- downloand speed (measured with `networkQuality`) and esitmated download time
- Jamf Pro version
- new preference keys (see [config profile documentation for details](ConfigurationProfile.md))
- `accentColor`
- `totalDownloadBytes`
- `userEntry.showForUserIDs`
## v0.7.1
(2023-06-29)
- flag file is now created _before_ last recon, so Jamf can pick it up with an extension attribute
- fixed some UI bugs in action tiles
- added documentation for single touch workflow with Jamf Connect
## v0.7
(2023-06-27)
- added macOS Sonoma to list of known macOS releases
- added documentation for Jamf School
- added changelog and some more updates to documentation
- computer name can now be generated wihtout UI from a template
- added slight scale animation and edge fade to action list
- user entry fields can now be validated with a regular expression and localized message
- battery widget now display correctly on Macs without a battery
## v0.6
(2023-06-05)
- launchd plist is now removed when app launches and flag file is present. This will prevent further accidental restarts after the app has been re-installed
- improved logging when parsing an action fails
- added Pendo integration to track app launches
- hitting cmd-L multiple times would open multiple log windows
- log window now auto-scrolls to latest entry
- command-W no longer closes main window
- added French localization
- fixed some typos in Dutch localization
- Warning screen appears when battery drops below 20% and disappears when charger is connected
- you can show/hide battery status with cmd-B
- updated built-in Installomator to v10.4
- fixed some logic errors in the Jamf Pro workflow that were introduced when adding Jamf School support
## v0.5
(2023-05-09)
- should now support Jamf School, this required major changes throughout the code, please test everything, also on Jamf Pro
- added installomator as an option for actions (mostly for Jamf School, but this also works with Jamf Pro)
- changed packaging script so that Jamf School can parse the pkg
- while rebuilding everything found a few edge cases that weren't handled very well
- holding the option key when clicking "About this Mac…" will now show some extra info (want to add more data there going forward)
- added SwiftLint to the project
## v0.4
(2023-04-05)
- disk size is shown in "About this Mac…"
- display and Mac will not sleep during installations
- Setup Manager will ignore non-managed enrollmentActions when not in Debug mode
- Setup Manager shows when Debug mode is enabled
- command-Q no longer quits the app (you can use shift-control-command-E) instead
## v0.3
(2023-03-10)
- localization (English, German, Dutch)
- DEBUG mode now does something
- added flag requiresRoot to shell action
- Prerequisites now wait for Jamf keychain
- About this Mac info should work for Intel Macs
- Connected Shutdown button
- Setup Manager creates a flag file at /private/var/db/.JamfSetupEnrollmentDone when it finishes
- when this file exists when Setup Manager launches, the app will terminate immediately and do nothing.
- new defaults key finalCountdown which automatically continues (or shuts down) after a timer
- new defaults key finalAction which can set 'shut down' as the action when the timer runs out
- started out with localization
- background window and log window work over Setup Assistant
- show Jamf Computer ID in Info Window and re-worked Info View
- user input configurable in profile
- added department, building and room as options for input
## v0.2
- app should now work with macOS Monterey
- window not movable
- main window centered correctly
- menu bar hidden
- removed coverflow effect from main action list
known issues:
- log window and background image window don't open when run over login window
- user input not yet optional
- shutdown button does not work yet

698
ConfigurationProfile.md Normal file
View File

@@ -0,0 +1,698 @@
# Configuration Profile format
The project includes a [custom profile plist](sample-com.jamf.setupmanager.plist) for Jamf Pro and [an example configuration profile](sample-jamfschool.mobileconfig) for Jamf School.
## Top-level keys
#### `DEBUG`
(Boolean, default: `false`)
When this is set to `true` any steps that actually change software on the disk will not be performed.
These behaviors change in debug mode:
- checks for the existence of the Jamf binary and keychain are skipped
- Jamf Setup manager will accept enrollmentActions from a non-managed preference file
- `policy`, `recon`, and `shell` actions that require root are replaced with a 10 second delay (and will always complete successfully)
- watchPath and wait actions timeout and fail after 10 seconds
When in debug mode, you have to set the `simulateMDM` preference key to `Jamf Pro` or `Jamf School`. This allows you to do test runs on un-enrolled Macs.
#### `title`
(String, default: `Welcome to Setup Manager`, localized)
The main title over the window.
Example:
```
<key>title</key>
<string>Welcome to your new Mac!</string>
```
#### `icon`
(String, default: `name:AppIcon`, localized)
The icon shown at the top center of the window. There are many options to define icons, described in the [Icon Sources](#icon-sources) section later.
#### `message`
(String, default: `Setup Manager is configuring your Mac…`, localized)
The message shown below the title.
Example:
```
<key>message</key>
<string>Please wait a few moments while we install essential software…</string>
```
#### `background`
(String, optional, localized)
When this key is set, Setup Manager treats it as an image/[icon source](#icon-source) and displays the image in a screen covering background.
#### `enrollmentActions`
(Array of Dicts, required)
This array contains a list of `Dict`s which describe the individual actions to be performed in order. Actions are described in detail in the [Actions](#actions) section.
#### `userEntry`
(Dict of Dicts, optional)
When this key exists, Setup Manager will prompt for user data while the enrollment actions are running. The individual keys are described in [User Entry](#user-entry).
#### `help`
(Dict of Strings, optional)
When this key exists, Setup Manager will show a "Help" button (a circled question mark) in the lower right corner while it is running. You can add subkeys with content for the help, which are described in [Help](#help). When Setup Manager has completed, the "Help" button will be replaced with the "Continue" and/or "Shutdown" button.
#### `accentColor`
(String, optional, default: system blue)
When present sets the accent color for buttons, progress bar and other UI elements. You can use this to match branding. Color is encoded as a six digit hex code, i.e. `#FF0088`.
#### `finalCountdown`
(Number/integer, optional, default: `60`)
This key changes the duration (in seconds) of the "final countdown" before the app automatically quits. Set to `-1` (or any negative number) to disable automated continue.
Examples:
```
<key>finalCountdown</key>
<integer>30</integer>
```
```
<key>finalCountdown</key>
<integer>-1</integer>
```
#### `finalAction`
(String, optional, default: `continue`)
This key sets the action and label for the button shown when Setup Manger has completed. When this key is set to `shutdown` (no space!) it will shutdown the computer, other wise it will just quit Setup Manager ("continue"). This is also the action that is performed when the `finalCountdown` timer runs out.
Example:
```
<key>finalAction</key>
<string>shutdown</string>
```
#### `showBothButtons`
(Bool, optional default: `false`)
This key determines whether both the 'Shutdown' and 'Continue' are shown or just the button set in the `finalAction` key.
Example:
```
<key>showBothButtons</key>
<true/>
```
#### `totalDownloadBytes` : (Integer, opitonal, default: 1000000000 or 1GB, v0.8)
Use this value to provide an estimate for the total size of all items that will be downloaded. Setup Manager will display and estimated download time for this sum in the "About this Mac..." popup window.
Example:
```
<key>totalDownloadBytes</key>
<integer>4500000000</integer>
```
#### `jssID`
(String, Jamf Pro only)
Set this to `$JSSID` in the configuration profile and Setup Manager will be aware of its computer's id in Jamf Pro. It will be display in the 'About this Mac…' popup.
Example:
```
<key>jssID</key>
<string>$JSSID</string>
```
#### `userID`
(String, Jamf Pro only)
Set this to `$EMAIL` in the configuration profile. This communicates the user who logged in to customized enrollment to Setup Manager. This can be used together with the `userEntry.showForUserIDs` key to control which users see the user entry UI.
Example:
```
<key>userID</key>
<string>$EMAIL</string>
```
#### `computerNameTemplate`
(String, Jamf Pro only)
When this key is set, Setup Manager will generate the computer name from this template and set it. When this key is present, a `computerName` dict or string in `userEntry` will be ignored.
The template uses tokens, which begin and end with `%` character. The tokens will be replaced with data from the device or from user entry. For example, in the template `Mac-%serial%` the `%serial%` token will be replaced with the computer's serial number. (A double `%%` will be substituted with a single `%`, in case you need to represent this symbol in the computer name.)
The following tokens are available:
- `serial`: the computer's serial number
- `udid`: the computer's provisioning udid
- `model`: the computer's model name, e.g. `MacBook Air` or `Mac mini`
- `model-short`: the first word of `model` (no spaces), i.e. `MacBook`, `Mac` or `iMac`
- these values from user entry: `email`, `assetTag`, `building`, `department`, `room`
If the value for a token cannot be retrieved or is empty, it will be substituted with `%%%` (three percentage signs).
You can add a `:n` (where `n` is an integer number) to a token. This will substitute only the first `n` characters of the string. For example `%serial:5%` will be substituted with the first 5 characters of the serial number. When `n` is negative, it will substitute the _last_ `n` characters. For example, `%udid:-8%` will substitute the last eight characters of the udid.
Example:
```
<key>computerNameTemplate</key>
<string>Mac-%serial:-6%</string>
```
This will set the computer name to `Mac-ABC123` where `ABC123` is the last six characters of the serial number
#### `overrideSerialNumber`
(String, optional)
When set, the "About this Mac" info window will show this value instead of the real serial number. This is useful when making screen shots or recordings for documentation or presentations where you do not want to expose real serial numbers.
## Actions
All actions should have these keys:
#### `label`
(String, required, localized)
The label is used as the name of the action in display.
#### `icon`
(String, optional, localized)
The icon source string used for the display of the label. Different types of actions will have different default icons, which is used when no `icon` key is present.
There are several different types of actions, and these are defined by additional keys. These keys will be on the same level as the keys above.
### Shell Command
#### `shell`
(String)
The path to the command or script that should be run for this action. You need to provide the absolute full path to the command, e.g. `/usr/bin/say`.
#### `arguments`
(Array of Strings, optional)
When the command given in `shell` requires arguments they are listed here, one item per argument. Do _not_ escape or quote spaces or other special characters.
#### `requiresRoot`
(Bool, default: `false`, optional)
When this key is set to `true` Setup Manager will only run this when itself is running as root. Otherwise it will fail the action. When `DEBUG` is enabled, it will replace the action with a delay instead.
Example:
```
<dict>
<key>label</key>
<string>Set Time Zone</string>
<key>icon</key>
<string>symbol:clock</string>
<key>shell</key>
<string>/usr/sbin/systemsetup</string>
<key>arguments</key>
<array>
<string>-setTimeZone</string>
<string>Europe/Amsterdam</string>
</array>
<key>requiresRoot</key>
<true/>
</dict>
```
### Jamf Policy Trigger
#### `policy`
(String)
(Jamf Pro only)
This will run the jamf policy or polices with the given trigger name. This is the equivalent of running `jamf policy -event <triggername>`
Example:
```
<dict>
<key>label</key>
<string>BBEdit</string>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_abcdefghj</string>
<key>policy</key>
<string>install_bbedit</string>
</dict>
```
### Watch Path
#### `watchPath`
(String)
This action will wait until a file at the given path exists (`wait` is `untilExists`, default) or is removed (`wait` is `whileExists`).
#### `wait`
(String, default: `untilExists`)
Determines if the action waits until the file exists (`untilExists`) or until the file is removed (`whileExists`).
#### `timeout`
(Number/integer, in seconds, default: `600`)
The action will fail after this timeout.
Example:
```
<dict>
<key>label</key>
<string>Jamf Protect</string>
<key>icon</key>
<string>symbol:app.badge</string>
<key>watchPath</key>
<string>/Applications/JamfProtect.app</string>
<key>wait</key>
<integer>300</integer>
</dict>
```
Note: This is intended to check if app are installed from the Mac App Store or Jamf App Installers. In my experience, these methods are very unreliable, hence the timeout. Since you cannot anticipate the order in which these apps may be installed, it is best to put the `watchPath` actions at the end. For large installations (Xcode) you want to have a large timeout.
### Wait
#### `wait`
(Number/integer, in seconds)
Wait for a given time. Use this to let the system catch up with previous installations.
Example:
```
<dict>
<key>label</key>
<string>Waiting…</string>
<key>wait</key>
<integer>20</integer>
</dict>
```
### Jamf Inventory Update (recon)
#### `recon`
(String, value is ignored, Jamf Pro only)
This will run a Jamf Inventory update.
You should usually not need to add a recon step. By default Setup Manager will automatically run an inventory update before and after running the enrollment actions.
Example:
```
<dict>
<key>recon</key>
<string/>
</dict>
```
### Installomator
This will run Installomator to install a given label.
Note: by default, Setup manager will add `NOTIFY=silent` to the arguments to suppress notfications. You can override this in the `arguments`.
#### `installomator`
(String)
The installomator label to run.
#### `arguments`
(Array of Strings, optional)
List of additional arguments passed into Installomator.
Example:
```
<dict>
<key>label</key>
<string>Google Chrome</string>
<key>icon</key>
<string>symbol:gearshape.2</string>
<key>installomator</key>
<string>googlechromepkg</string>
</dict>
```
## Icon Sources
Icons can be defined in several ways in Setup Manager. These different approaches for the top-level `icon` and `background` key, as well as the `icon` key in an action.
### From the web
When the icon source string starts with `http` or `https`, Setup Manager will attempt to download a file from that URL and interpret it as an image file. It will show a spinning progress view while downloading.
```
<key>icon</key>
<string>https://example.com/path/to/icon.png</string>
```
### Local file
When the icon source is an absolute file path, Setup Manager will attempt to read that file as an image file and display it.
```
<key>icon</key>
<string>/Library/Organization/image.png</string>
```
### Application:
When the icon source is an absolute file path that ends in `.app`, Setup Manager will get the icon from that app.
```
<key>icon</key>
<string>/System/Applications/App Store.app</string>
```
### Name:
When the icon source starts with `name:`, Setup Manager will get the icon with that name. Two names are useful: `AppIcon` gets Setup Manager's app icon and `NSComputer` will get an icon representing the current hardware.
```
<key>icon</key>
<string>name:AppIcon</string>
```
### SF Symbols:
When the icon source starts with `symbol:`, Setup Manager will create the icon using that symbols name. You can look up symbol names using the [SF Symbols app](https://developer.apple.com/sf-symbols/).
Note that the availability of SF Symbols will vary with the OS version and that some SF Symbols may look different in different localizations.
```
<key>icon</key>
<string>symbol:clock</string>
```
## User Entry
You can enable user entry for the following keys:
- `userID`
- `department`
- `building`
- `room`
- `assetTag`
- `computerName`
Any of the fields will only be shown when its key exists. If you were to create an empty `userEntry` dict, you get an empty user input screen with a 'Save' button - not a good user experience.
#### `default`
(String, localized)
You provide a default value in two ways:
Example:
```
<key>computerName</key>
<string>Mac-12345</string>
```
Use this simple `string` form, when all you need is the field with a default value filled in. Leave the `string` value empty if you don't even want a default value.
When you want to configure other options of the field, you need to use the `dict` form:
Example:
```
<key>computerName</key>
<dict>
<key>default</key>
<string>ABC12345</string>
</dict>
```
With the second, longer form you can have different default values per [localization](#localization).
```
<key>computerName</key>
<dict>
<key>default</key>
<string>Device-12345</string>
<key>default.de</key>
<string>Gerät-12345</string>
</dict>
```
#### `placeholder`
(String, localized)
This will show the string value given as a greyed out placeholder in the empty text field.
```
<key>assetTag</key>
<dict>
<key>placeholder</key>
<string>ABC12345</string>
</dict>
```
Note: a `default` value will prevent the placeholder from appearing, unless the user actively deletes the contents of a field.
#### `options`
(Array of Strings, optional)
This will show a popup list of preset options:
```
<key>department</key>
<dict>
<key>options</key>
<array>
<string>IT</string>
<string>Sales</string>
<string>R&amp;D</string>
</array>
</dict>
```
The first option is the default selection.
Note: since we want to avoid having to provide Jamf Pro API credentials to Setup Manager, JSM does _not_ read the list of buildings or departments from Jamf and you will have to transcribe them into the profile. Annoying, but the lesser of two evils, here.
#### `validation`
(String, optional)
The value of this key is a regular expression string. When the expression matches the entire string entered, it validates. For example, a `validation` of `[A-Z]{3}\d{5}` will match three uppercase letters (`[A-Z]{3}`) and then five numbers (`\d{5}`).
Some useful regular expressions:
- `.+`: at least one character (i.e. not empty)
- `[a-z]{7}`: exactly seven lowercase letters
- `\d{3,5}`: three to five digits (numbers)
- `\S+\@(example\.com|example.org)`: email ending with `example.com` or `example.org`
Detailed description of the regular expression syntax: [NSRegularExpression](https://developer.apple.com/documentation/foundation/nsregularexpression)
Example:
```
<key>userID</key>
<dict>
<key>placeholder</key>
<string>first.last@example.com</string>
<key>validation</key>
<string>\S+\.\S+\@example\.com</string>
</dict>
```
#### `validationMessage`
(String, optional, localized)
The default validation message will show the regular expression the value is not matching. This is suitable for debugging but not at all user friendly. You really should provide a localized message explaining how the value can conform.
```
<key>assetTag</key>
<dict>
<key>placeholder</key>
<string>ABC12345</string>
<key>validation</key>
<string>[A-Z]{3}\d{5}</string>
<key>validationMessage</key>
<string>Asset Tag needs to be of format 'ABC12345'</string>
<key>validationMessage.de</key>
<string>Etikett Nummer muss im Format 'ABC12345' sein</string>
<key>validationMessage.fr</key>
<string>L'étiquette d'actif doit être au format 'ABC12345'</string>
<key>validationMessage.nl</key>
<string>Asset Tag moet het formaat 'ABC12345' hebben</string>
</dict>
```
### Conditionally show the user entry for certain users
You can configure Setup Manager to only show the user entry section when specified users have authentication in enrollment customization. This enables workflows, where certain users (techs and admins) gets the option to re-assign the device to another user, but other users don't see the option.
For this, you need to setup the top-level `userID` to receive the `$EMAIL` variable. This will communicate the user who logged in with customized enrollment back into Setup Manager. Then you add key `showForUserIDs` with an array of user emails to the `userEntry` dict. When both `userID` and `userEntry.showForUserIDs` are set, the user entry UI will only show for the listed users.
#### `showForUserIDs`
(Array of Strings, optional)
Example:
```
<key>userEntry</key>
<dict>
<key>showForUserIDs</key>
<array>
<string>a.b@example.com</string>
<string>m.b@example.com</string>
<string>r.p@example.com</string>
</array>
<key>userID</key>
<dict>
<key>placeholder</key>
<string>first.last@example.com</string>
<key>validation</key>
<string>\S+\.\S+@example.com</string>
</dict>
</dict>
<key>userID</key>
<string>$EMAIL</string>
```
## Help
When you provide a top-level `help` key with a dictionary a help button (with a circled question mark) will be shown in the lower right corner. When you click on the help button a window with information will be shown. You can set the information with the following keys in the `help` dictionary.
#### `title`
(String, optional, localized)
#### `message`
(String, optional, localized)
#### `url`:
(String, optional, localized)
The contents of the `url` key will be translated into a QR code and displayed next to the help message. This allows for end users to follow a link to more information on their devices while the Mac is performing installations.
Example:
```
<key>help</key>
<dict>
<key>message</key>
<string>This is some help message content.</string>
<key>title</key>
<string>Help Content</string>
<key>url</key>
<string>https://jamf.com</string>
</dict>
```
## Localization
The app will pick up the user choice of the UI language for the interface elements. Right now it supports English, French, German, Italian, Spanish, and Dutch. The app will fall back to English for other language choices.
You can provide localizations for the texts given in the configuration profile. You can do so by adding the two-letter language abbreviation (e.g. `de`, `fr`, or `nl`) to the key, separated with a `.` (dot or period character). The value of the key without a "language extension" is used for English and as a fallback value for other languages.
Example:
```
<key>title</key>
<string>Welcome!</string>
<key>title.de</key>
<string>Willkommen!</string>
<key>title.fr</key>
<string>Bienvenu!</string>
<key>title.nl</key>
<string>Welkom!</string>
```
If you do not provide or have deleted a `title.de` key and value, the app will choose the value of the `title` key even when in the German setting.
The following keys can be localized:
### Top-level keys
- `title`
- `message`
- `icon`
- `background`
### Action keys
- `label`
- `icon`
### User Entry keys
- `default`
- `placeholder`
- `validationMessage`
Use these two-letter codes for these languages:
| Language | two-letter code |
|--------------------|-----------------|
| Dutch (Nederlands) | nl |
| English | en (default) |
| French | fr |
| German | de |
| Italian | it |
| Norwegian | nb |
| Spanish | es |
| Swedish | sv |

BIN
Images/SetupManager250.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -0,0 +1,108 @@
# Single Touch workflow with Jamf Pro and Jamf Connect
## What is Single Touch?
In a single touch workflow a tech performs or monitors the initial setup of a device to the point just before the user creates their account. While Setup Manager can run zero-touch workflows, it was built specifically with single-touch workflows in mind.
A single touch workflow can be as easy the tech unpacking the Mac (erasing it with an MDM command or restoring it with Apple Configurator when necessary), connecting it to network, stepping through the initial Setup dialogs, optionally entering the asset tag or other data, monitoring Setup Manager's process until it is finished and then handing over or sending the Mac to the designated end user who continues the setup and creates their account in Setup Assistant.
You can use a combination of Jamf Pro, Setup Manager and Jamf Connector, to get a tighter deployment, user assignment and account creation process. This requires a bit more setup and configuration. This workflow allows the tech to monitor the Setup Manager workflow, enter device specific data such as an asset tag and assign _and lock_ the device to a different user, without requiring the end user's login credentials.
## What you need:
- Jamf Pro
- Setup Manager
- Jamf Connect Login configured with SSO
Customized Enrollment with SSO is not _required_ for this workflow. The assignment to the final user is set from the email entered in Setup Manager. Nevertheless, customized enrollment with SSO is useful in this context since restricts Mac enrollment to a group of authorized accounts.
You should have Jamf Pro and Jamf Connect configured with the required SSO integrations and thoroughly tested before configuring this workflow.
## Configure Setup Manager
Add the Setup Manager pkg to the Prestage. Also create a configuration profile for Setup Manager with the workflow to install and configure the software you want to be installed at this stage.
You need to leave least one panel of Setup Assistant _enabled_. Otherwise Setup Manager might not launch.
Setup Manager profile will require a `userEntry` field for `userID` to know which user to assign the Mac to. This will show a field prompting for "User Email." You can of course add other fields to `userEntry` at this time, though they are not required.
Example:
```
<key>userID</key>
<dict>
<key>placeholder</key>
<string>first.last@example.com</string>
<key>validation</key>
<string>\S+\.\S+\@example\.com</string>
<key>validationMessage</key>
<string>Email needs to be for example.com!</string>
<key>validationMessage.de</key>
<string>Email muss für example.com sein!</string>
</dict>
```
## Deploy Jamf Connect
You also need to make sure that Jamf Connect (Login) is deployed is installed and configured. There are different approaches to do this.
- add Jamf Connect pkg to prestage
- install Jamf Connect with a pkg policy triggered from Setup Manager workflow
- install Jamf Connect with Installomator action in Setup Manager workflow
- install Jamf Connect with Jamf App Installers
When you upload the Jamf Connect pkg to Jamf Pro and add it to either the Prestage or a policy, you retain control over which version of Jamf Connect gets deployed. With Installomator or Jamf App Installer you will always get the latest available version.
When you use Jamf App Installers you have no direct control over when the installation actually occurs. You should add a `watchPath` action at the end of your `enrollmentActions` array in the Setup Manager profile to ensure that Jamf Connect is installed before proceeding:
```
<dict>
<key>label</key>
<string>Jamf Connect</string>
<key>icon</key>
<string>symbol:app.badge</string>
<key>watchPath</key>
<string>/Applications/Jamf Connect.app</string>
<key>wait</key>
<integer>900</integer>
</dict>
```
## Create Extension Attribute
The email entered for userID will be submitted to Jamf Pro at the end of the Setup Manager workflow. When the Setup Manager workflow is done a flag file will be created at `/private/var/db/.JamfSetupEnrollmentDone`. We can use this to scope profiles and policies to Macs that have finished the Setup Manager workflow.
Create an Extension attribute named "Setup Manager Done" with the script code:
```
if [ -f "/private/var/db/.JamfSetupEnrollmentDone" ]; then
echo "<result>done</result>"
else
echo "<result>incomplete</result>"
fi
```
Then create a Smart Group named "Setup Manager Done" with the criteria `"Setup Manager Done" is "done"`.
## Pre-set user for Jamf Connect
Jamf Connect Login allows pre-configuring the user. Create a configuration profile named "Jamf Connect Enrollment User" to the preference domain `com.jamf.connect.login` with the following property list:
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnrollmentRealName</key>
<string>$REALNAME</string>
<key>EnrollmentUserName</key>
<string>$EMAIL</string>
</dict>
</plist>
```
Scope this configuration profile the "Setup Manager Done" smart group you created earlier.
With this setup, the configuration profile that presets the user in Jamf Connect Login will be pushed out after Setup Manager finishes its final recon, which sets the user information to the Mac in Jamf Pro.

90
README.md Normal file
View File

@@ -0,0 +1,90 @@
![Setup Manager Icon](Images/SetupManager250.png)
# Setup Manager
_"Every Assistant has a Manager"_
![Setup Manager Logo](https://img.shields.io/badge/macOS-12%2B-success)
Please report issues, feature requests [as an issue.](https://github.com/setup-manager/setup-manager/issues)
We have opened the [discussions](https://github.com/setup-manager/setup-manager/discussions) area for questions and more generic feedback.
Updates will be published in the '[Releases](https://github.com/setup-manager/setup-manager/releases)' section of the repo. There you can also [download the latest pkg installer](https://github.com/setup-manager/setup-manager/releases/latest). You can subscribe to notifications for the repo using the 'Watch' button above.
## What it does
There are many enrollment progress tools available for Mac admins, each with their own strengths. Jamf Setup Manager approaches the problem from the perspective of an IT service provider.
Setup Manager offers many of the same features of these utilities but is especially useful for the case where an IT department or provisioning depot wants to ensure that a new Mac is properly configured and assigned before sending the device to its new user. It runs over Setup Assistant before a user is created so it won't interfere with MDM-capable user or the secure token flow for FileVault. You can control which policies and installations Setup Manager runs with a configuration profile.
Setup Manager provides:
- a nice modern UI
- configuration with a configuration profile, no need to modify shell scripts or json
- works with different deployment workflows
- zero-touch (user-driven)
- single-touch (tech-driven)
- user initiated enrollment
- customized branding
- localized interface and custom text
- support for Jamf Pro and Jamf School
![setup manager progress dialog](Images/setup-manager-progress-screenshot.png)
## Installation and Configuration
### Jamf Pro
1. Upload the Setup Manager installer pkg file to Jamf Pro
2. Create a custom configuration profile with the preference domain `com.jamf.setupmanager`. See documentation for the profile contents [here](ConfigurationProfile.md).
3. Scope the configuration profile to the computers
4. Add the pkg and the configuration profile to the Prestage
Setup Manager can be used for various zero-touch and tech-driven single-touch deployments with Jamf Pro and (optionally) Jamf Connect. One single-touch workflow with Jamf Connect where the tech can re-assign the Mac to a different end user [is described here](JamfProConnect-SingleTouch.md).
### Jamf School
[Setup with Jamf School](Setup-JamfSchool.md)
## Configuration Profile
The structure of the configuration profile [is documented here](ConfigurationProfile.md).
## Notes
### Requirements
Setup Manager requires macOS 12.0.0 or higher. It will work only with Jamf Pro or Jamf School.
### Known Issues
- Setup Manager will **_not_** launch with Auto-Advance enabled
- Setup Manager may **_not_** launch when you disable _all_ Setup Assistant screens
### Quit
The command-Q keyboard short cut to quit the app is disabled. You can use shift-control-command-E instead. This should only be used when debugging as it may leave the client in an undetermined state when installations are aborted.
### Logging
Setup Manager logs to `/Library/Logs/Setup Manager.log`.
While it is running you can open a log window with command-L.
### Flag file
Setup Manager creates a flag file at `/private/var/db/.JamfSetupEnrollmentDone` when it finishes. If this file exists when Setup Manager launches, the app will terminate immediately and withour taking any action. You can use this flag file in an extension attribute in Jamf to determine whether the enrollment steps were performed. (Setup Manager does not care if the actions were performed successfully.)
When DEBUG is set to YES in the defaults/configuration profile, the flag file is ignored at launch, but still created when done.
### Final action and shutdown
When the app is not running as root (for testing or from Xcode) or when the `DEBUG` preference is set, shutdown will merely quit.
### "About This Mac…" window
When you hold the option key when clicking on "About This Mac…" you will see more information.
Please report issues, feature requests, and feedback (positive and negative) [as an issue.](https://github.com/setup-manager/setup-manager/issues)

71
Setup-JamfSchool.md Normal file
View File

@@ -0,0 +1,71 @@
# Setup with Jamf School
## Setting Jamf Setup Manager Workflow in Jamf School
In order to configure the workflow in Jamf School you will need
- A Jamf Setup Manager Configuration Profile (configured for your deployment, example profile below) uploaded to Jamf School
- Jamf Setup Manager PKG (available from GitHub) uploaded to Jamf School
- An Automated Device Enrolment Profile with at least one setup assistant pane configured, “Wait for the configuration to be applied before continuing the Setup Assistant” box checked and an admin account configured as required and “skipped user creation” pane
- Other ADE profile setting should be set as required but Do Not select Auto Advance (see below)
### Step 1
- Create a Payloadless Profile for Smart Group Targeting
- Navigate to profiles and create a new macOS Profile.
- Name it “Jamf Setup Manager Installed”
- Do not scope the profile and do not configure any payloads. Simply save the profile
### Step 2
- Create a Smart Group to target your required Macs
- Navigate to Devices → Device Groups and create a new group. Ensure you select “Smart Group”
- Name the Group “Jamf Setup Manager Profile” skip all other panes until members
- In members select “Operating System” “equals” “Any” and then leave the min and max OS blank. This will target any and all macOS devices in my environment
- If you only want to select a subset of macOS devices, for example Lab Mac devices and not 1:1 devices, configure this group to target the desired devices in your environment
- Save Scope
### Step 3
- Create a Smart Group to target devices with Jamf Setup Manager Profile Installed to deploy JSM pkg
- Navigate to Devices → Device Groups and create a new group. Ensure you select “Smart Group”
- Name the Group “Install Jamf Setup Manager”, skip all other panes until members
- In members select “Managed Profile (Installed)” “equals” and then select the Jamf Setup Manager Configuration Profile that you uploaded to Jamf School
- Save Scope
- Next in the Apps tab add the Jamf Setup Manager pkg and in the Profiles tab select the “Jamf Setup Manager Installed” profile you created in Step 1
- If you named your profile in step 1 something different, be sure to select that profile in this step
### Step 4
- Create a Smart Group to target devices with the “JSM Installed” profile installed and deploy the rest of the profile and apps
- Navigate to Devices → Device Groups and create a new group. Ensure you select “Smart Group”
- Name the group “macOS Management & Apps”, skip all other panes until members
- In members select ““Managed Profile (Installed)” “equals” and then select “Jamf Setup Manager Installed” profile that you created in Step 1
- If you named your profile in step 1 something different, be sure to select that profile in this step
- Next in the Apps tab add any apps or packages that will not be installed via Installomator as part of the Jamf Setup Workflow and in the Profiles tab any any and all config needed to manage your Macs
- If you install packages or App Store apps through Jamf School, if you want to report on them as part of the Jamf Setup Manager workflow be sure to add Watchpaths for the apps / content into the Jamf Setup Manager Configuration Profile before uploading to Jamf School
These chained Smart group actions then perform the following flow
- Scope the Jamf Setup Manager Config profiles to all macOS devices
- Once the Profile is reported as installed by Jamf School, it will then install the Jamf Setup Manager pkg (since we 100% know the config profile is on the device before the pkg, when know itll be configured in the correct manner) and the “Jamf Setup Manager Installed” profile
- Only when the device reports back that it has “Jamf Setup Manager Installed” profile will it move into the next smart group where it will receive the commands to install further apps / packages and the rest of the configuration profiles
With this flow we are controlling the best we can that the first thing the device does it install Jamf Setup Manager and the required config rather than having Jamf Setup Manager queued rather down a list of apps that are installing.
This activity log shows the order in which Jamf School issues and the device receives the commands. We can see that theres not a huge amount of time between all the actions but long enough that we can be sure that the device gets the Enterprise Install command to install Jamf Setup Manager before anything other apps
## Workflow Warnings
Since the Jamf Setup Manager workflow is very “specific” for Jamf School it shouldnt be a surprise that there are some warnings, or gotchas. All mainly around the way that weve chained together the smart groups based on installed profiles, although it gives us the flow that we need it's also a little fragile.
For example if you were to accidentally unscope the “Jamf Setup Manager Installed” profile from a device it would then fall out of scope of the “macOS Management & Apps” group, which is where all of the management and App Store apps are scoped.
…and of course that means the device has the profiles removed and App Store apps removed AKA disaster 💥💥💥
The second smart group we create also is looking for a profile that is installed. Youre likely not going to unscope by accident this profile (although if you did is would mean the device has profiles removed and App Store app removed AKA disaster 💥💥💥) what is more likely to happen is that you UPDATE or REPLACE the “Jamf Setup Manager Configuration Profile”
Let's say you upload your JSM configure Profile and call its “JSM Setup V1” and this is the profile that you select in the smart group in Step 1 above. You then edit the config profile and call it JSM Setup V1.1, maybe even delete the JSM Setup V1 from Jamf School.
The smart group is still looking for a profile called “JSM Setup V1”.
Depending on your setup and how youve managed your profiles in Jamf School your deployed devices might not longer have JSM Setup V1 installed, which means it falls out of the “Install Jamf Setup Manager” group which in turn will fall out of the “macOS Management & Apps” group….which is where all of the management and App Store apps are scoped.
Again, of course that means the device has the profiles removed and App Store apps removed AKA disaster 💥💥💥
Also newly deployed devices might not run through the workflow correctly as they are now have JSM Setup V1.1 installed and the smart group is looking for JSM Setup V1.
Bottom line here is be mindful about the name of your Jamf Setup Manager Profile and if you amend the config and upload a new version, scope that FIRST, then EDIT the smart group, wait for it to deploy and then remove the old profile.
Although targeting the profile is what makes this workflow successful in Jamf School, its also a house of cards

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>userEntry</key>
<dict>
<key>department</key>
<dict>
<key>options</key>
<array>
<string>Sales</string>
<string>R&amp;D</string>
<string>IT</string>
</array>
</dict>
<key>computerName</key>
<string>Mac-12345</string>
<key>userID</key>
<dict>
<key>placeholder</key>
<string>first.last@example.com</string>
<key>placeholder.de</key>
<string>vorname.nachname@example.com</string>
<key>placeholder.nl</key>
<string>voornaam.achternaam@example.com</string>
</dict>
<key>assetTag</key>
<dict>
<key>placeholder</key>
<string>ABC12345</string>
</dict>
</dict>
<key>enrollmentActions</key>
<array>
<dict>
<key>arguments</key>
<array>
<string>-setTimeZone</string>
<string>Europe/Amsterdam</string>
</array>
<key>icon</key>
<string>symbol:clock</string>
<key>label</key>
<string>Set Time Zone</string>
<key>label.es</key>
<string>Establecer zona horaria</string>
<key>label.fr</key>
<string>Définir le fuseau horaire</string>
<key>label.it</key>
<string>Imposta il fuso orario</string>
<key>label.de</key>
<string>Zeitzone setzen</string>
<key>label.nl</key>
<string>Tijdzone instellen</string>
<key>requiresRoot</key>
<true/>
<key>shell</key>
<string>/usr/sbin/systemsetup</string>
</dict>
<dict>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_bb4e9c7d19adf8360ff28d666b01e66c35ae3e8d190660ac496d5a8abf4276a8</string>
<key>label</key>
<string>Microsoft 365</string>
<key>policy</key>
<string>install_microsoft365</string>
</dict>
<dict>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_87d2224fa990a47de96f63fb2f84aa3b7304c20a3ff29412f5a7a484745fd2c9</string>
<key>label</key>
<string>Google Chrome</string>
<key>policy</key>
<string>install_chrome</string>
</dict>
<dict>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_d72c39716b456bb647a1cfe01942656bd25dfcdd0faaa147dcce337589b75a8a</string>
<key>label</key>
<string>BBEdit</string>
<key>policy</key>
<string>install_bbedit</string>
</dict>
<dict>
<key>icon</key>
<string>symbol:app.badge</string>
<key>label</key>
<string>Jamf Protect</string>
<key>timeout</key>
<integer>600</integer>
<key>watchPath</key>
<string>/Applications/JamfProtect.app</string>
</dict>
</array>
<key>icon</key>
<string>name:AppIcon</string>
<key>finalCountdown</key>
<integer>30</integer>
<key>message</key>
<string>Please be patient while Setup Manager configures your new Mac.</string>
<key>message.es</key>
<string>Por favor espere mientras Setup Manager configura tu nuevo Mac.</string>
<key>message.it</key>
<string>Sii paziente mentre Setup Manager configura il tuo nuovo Mac.</string>
<key>message.fr</key>
<string>Veuillez être patient pendant que Setup Manager configure votre nouveau Mac.</string>
<key>message.de</key>
<string>Bitte etwas Geduld während Setup Manager deinen neuen Mac konfiguriert.</string>
<key>message.nl</key>
<string>Even geduld terwijl Setup Manager je nieuwe Mac configureert.</string>
<key>title</key>
<string>Welcome!</string>
<key>title.es</key>
<string>¡Bienvenido!</string>
<key>title.it</key>
<string>Benvenuto!</string>
<key>title.fr</key>
<string>Bienvenu!</string>
<key>title.de</key>
<string>Willkommen!</string>
<key>title.nl</key>
<string>Welcom!</string>
<key>jssID</key>
<string>$JSSID</string>
</dict>
</plist>

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadContent</key>
<dict>
<key>com.jamf.setupmanager</key>
<dict>
<key>Forced</key>
<array>
<dict>
<key>mcx_preference_settings</key>
<dict>
<key>enrollmentActions</key>
<array>
<dict>
<key>arguments</key>
<array>
<string>-setTimeZone</string>
<string>Europe/Amsterdam</string>
</array>
<key>icon</key>
<string>symbol:clock</string>
<key>label</key>
<string>Set Time Zone</string>
<key>label.de</key>
<string>Zeitzone setzen</string>
<key>label.fr</key>
<string>Définir le fuseau horaire</string>
<key>label.nl</key>
<string>Tijdzone instellen</string>
<key>requiresRoot</key>
<true/>
<key>shell</key>
<string>/usr/sbin/systemsetup</string>
</dict>
<dict>
<key>arguments</key>
<array>
<string>--install-rosetta</string>
<string>--agree-to-license</string>
</array>
<key>icon</key>
<string>symbol:cpu</string>
<key>label</key>
<string>Install Rosetta</string>
<key>label.de</key>
<string>Rosetta installieren</string>
<key>label.fr</key>
<string>Installer Rosetta</string>
<key>label.nl</key>
<string>Rosetta installeren</string>
<key>requiresRoot</key>
<true/>
<key>shell</key>
<string>/usr/sbin/softwareupdate</string>
</dict>
<dict>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_d72c39716b456bb647a1cfe01942656bd25dfcdd0faaa147dcce337589b75a8a</string>
<key>installomator</key>
<string>bbedit</string>
<key>label</key>
<string>BBEdit</string>
</dict>
<dict>
<key>icon</key>
<string>https://ics.services.jamfcloud.com/icon/hash_87d2224fa990a47de96f63fb2f84aa3b7304c20a3ff29412f5a7a484745fd2c9</string>
<key>installomator</key>
<string>googlechromepkg</string>
<key>label</key>
<string>Google Chrome</string>
</dict>
</array>
<key>icon</key>
<string>name:AppIcon</string>
<key>message</key>
<string>Setup Manager is configuring your Mac…</string>
<key>message.de</key>
<string>Setup Manager konfiguriert deinen Mac…</string>
<key>message.fr</key>
<string>Setup Manager configure votre Mac…</string>
<key>message.nl</key>
<string>Setup Manager configureert je Mac…</string>
<key>title</key>
<string>Welcome!</string>
<key>title.de</key>
<string>Willkommen!</string>
<key>title.fr</key>
<string>Bienvenu!</string>
<key>title.nl</key>
<string>Welkom!</string>
</dict>
</dict>
</array>
</dict>
</dict>
<key>PayloadDisplayName</key>
<string>Custom Settings</string>
<key>PayloadIdentifier</key>
<string>4FA5FEAD-6868-450F-A00B-09A7628F9420</string>
<key>PayloadOrganization</key>
<string>Jamf Setup Manager</string>
<key>PayloadType</key>
<string>com.apple.ManagedClient.preferences</string>
<key>PayloadUUID</key>
<string>4FA5FEAD-6868-450F-A00B-09A7628F9420</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string></string>
<key>PayloadDisplayName</key>
<string>Setup Manager</string>
<key>PayloadEnabled</key>
<true/>
<key>PayloadIdentifier</key>
<string>316D8E1F-7D42-49F9-A28B-4625D46469E7</string>
<key>PayloadOrganization</key>
<string>Armin Briegel</string>
<key>PayloadRemovalDisallowed</key>
<true/>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>316D8E1F-7D42-49F9-A28B-4625D46469E7</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>

43
uninstall.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/sh
# uninstall.sh
# removes Setup Manager app and all related files
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
# Note:
# Setup Manager creates a flag file at
#
# /private/var/db/.JamfSetupEnrollmentDone
#
# when it completes successfully. This uninstall script
# does NOT remove this file. When you re-install Setup
# Manager after running this script, the flag file's
# existence will suppress the launch of Setup Manager.
#
# Depending on your workflow needs, you may want to
# uncomment the last line which removes the flag file.
appName="Setup Manager"
bundleID="com.jamf.setupmanager"
appPath="/Applications/Utilities/${appName}.app"
if [ $(whoami) != "root" ]; then
echo "needs to run as root!"
exit 1
fi
if launchctl list | grep -q "$bundleID" ; then
echo "unloading launch daemon"
launchctl unload /Library/LaunchDaemons/"$bundleID".plist
fi
echo "removing files"
rm -rfv /Applications/Utilities/"$appName".app
rm -v /Library/LaunchDaemons/"$bundleID".plist
pkgutil --forget "$bundleID"
# rm -v /private/var/db/.JamfSetupEnrollmentDone