MDM Rollout
Every MDM rollout has the same three steps:
- Install the binary — push
install-mdm-template.sh(macOS + Linux) orinstall-mdm-template-win.ps1(Windows) via your MDM tool. Get it from the PointFive app or your PointFive contact. - Drop the enrollment manifest — at the system path so every user on the machine inherits the binding. Generate the manifest in the PointFive app.
- Verify —
tokenshift doctorreports back.
Paths used below:
- macOS / Linux system manifest:
/etc/tokenshift/enrollment.json - Windows system manifest:
%PROGRAMDATA%\tokenshift\enrollment.json
See Enrollment for what’s in the manifest and why the per-user path takes precedence when both exist.
Two policies, scoped to the same smart group:
- Install — push
install-mdm-template.shas a script payload (get it from the PointFive app or your PointFive contact). Paste your API key into the marked block before uploading. - Configure — push the enrollment manifest as a file to
/etc/tokenshift/enrollment.json(mode 0644, owned by root).
Run tokenshift doctor as a self-service “verify” policy so users (and
your support team) can confirm the binding without admin help.
JumpCloud
Section titled “JumpCloud”JumpCloud Commands work well for both steps:
-
Push a shell command that installs the binary user-owned — get
install-mdm-template.sh(macOS + Linux) from the PointFive app (or your PointFive contact) and setTENANT_IDat the top to your tenant UUID before pushing (the script aborts while theYOUR-TENANT-UUID-HEREplaceholder is unedited). Paste your API key into the marked block at the top of the same script, replacingPASTE-YOUR-API-KEY-HEREand keeping the quotes:Terminal window ######## PASTE YOUR API KEY FROM THE TOKENSHIFT CONSOLE HERE ########export TOKENSHIFT_BEARER_TOKEN="${TOKENSHIFT_BEARER_TOKEN:-PASTE-YOUR-API-KEY-HERE}"#####################################################################Tenant UUID and API key are then both in the Command body, and that body is the only thing to keep current. The script aborts at exit
30if either placeholder is left unedited, or if the key is not a well-formed tenant API key (at least 82 characters,p5ts_prefix, letters, digits and underscores only).It installs every eligible user on the machine, each into their own
~/.tokenshift/binas that user, and wires PATH via~/.tokenshift/env— nothing under/usr/local/bin. A plaincurl | tar -C /usr/local/binleaves a root-owned binary that can’t self-update.Note what pasting costs on JumpCloud specifically: the key sits in cleartext in the saved Command, readable by anyone with console access to it, and it has to be re-edited in every Command carrying the script whenever the key rotates. JumpCloud can hold it as a Custom Variable with the Secret Variable toggle instead — encrypted at rest, substituted at runtime — and the installer honours an environment-supplied key ahead of the pasted one, so
export TOKENSHIFT_BEARER_TOKEN={{tokenshift_bearer_token}}above the script still works. If your console has broad read access or you rotate keys often, that is the safer option. -
Push the manifest contents via a second Command that writes
/etc/tokenshift/enrollment.jsonwithtee.
Verify with a third Command that runs tokenshift doctor and captures
output.
Intune
Section titled “Intune”macOS-side: push install-mdm-template.sh as a shell script assigned to a
device group. Intune for Mac runs scripts as root, so writing
/etc/tokenshift/enrollment.json is straightforward — either inline in the
same script or via a separate configuration profile.
Windows-side: push install-mdm-template-win.ps1 as a platform script
(Devices → Scripts), assigned in user context — the installer is
per-user and needs no admin. Run it in the 64-bit PowerShell host; the
script relaunches itself 64-bit if Intune starts it under 32-bit, so either
setting works. Set TOKENSHIFT_TENANT_ID and TOKENSHIFT_BEARER_TOKEN in
the environment, or paste the key into the marked block before uploading.
The enrollment manifest goes to %PROGRAMDATA%\tokenshift\enrollment.json
via a separate device-context script or a configuration profile.
Ansible
Section titled “Ansible”A playbook does the same steps natively — no install-mdm-template.sh
invocation needed: create the user-owned ~/.tokenshift/bin store, download
and unpack the tarball into it, wire PATH via a /etc/profile.d drop-in,
drop the enrollment manifest to /etc/tokenshift/enrollment.json, then run
tokenshift doctor to verify. A ready-to-adapt playbook is available via
the PointFive app or your PointFive contact.
Who gets installed
Section titled “Who gets installed”A root-triggered run of install-mdm-template.sh (MDM push, Ansible, or sudo) installs
every eligible user on the machine, each into their own ~/.tokenshift and each
enrolled as themselves. There is no “primary user” to resolve. An account is eligible when
all of these hold, and is skipped with a logged reason otherwise:
- the account resolves, and its UID is in the human range —
/etc/login.defsUID_MIN/UID_MAXon Linux (default 1000–60000), ≥501 on macOS - it has a real login shell (not
nologin/false) - its home directory, read from the account record, exists and is owned by it
Exclude accounts with a space- or comma-separated denylist. Each entry is a shell glob
matched against the username — svc-* excludes every service account, a literal name
excludes just that one:
sudo TOKENSHIFT_EXCLUDE_USERS="svc-*,contractor" bash ./install-mdm-template.shA single run installs at most 10 users, overridable with TOKENSHIFT_MAX_USERS. Beyond the
cap the first 10 still install and the run exits non-zero: an endpoint with that many
eligible accounts is a shared machine rather than the single-owner workstation this flow is
built for, and it should surface for a human decision instead of installing silently.
The run exits non-zero if no user was eligible, if the cap was exceeded, or if an
installed user hit a fatal step (binary placement, telemetry, enroll). A skipped account is
not a failure, and hook-wiring or doctor warnings never fail the run.
Windows works the other way round. install-mdm-template-win.ps1 installs the account that
runs it and nothing else — no eligibility scan, no TOKENSHIFT_EXCLUDE_USERS, no
TOKENSHIFT_MAX_USERS, and no root step to reclaim. Cover a shared machine by assigning the
script in user context so each user’s own session runs it. Service SIDs (S-1-5-18/-19/-20)
are refused.
Which agents get wired
Section titled “Which agents get wired”- The installer wires every supported and detected agent on the machine.
- Detection is per user: an agent is detected once its own config directory exists.
- An agent that is not installed yet is never wired — there is no way to wire ahead.
- Wiring is additive and idempotent. Re-running
tokenshift installpicks up an agent that appeared since the last run and leaves the already-wired ones untouched. - So there is nothing to wire “per agent” — when a developer adopts a new agent, re-run the same install.
When nothing is detected, install prints the per-agent detection status and still exits 0, so a fleet push is never aborted by a machine that has no agent yet.
Reporting
Section titled “Reporting”The run result is the exit code and stdout — Jamf policy logs, Intune script output and Ansible all capture both, so nothing extra is needed to see whether an install succeeded.
| code | meaning |
|---|---|
0 | every gated-in user installed |
10 / 30 / 40 / 45 | preflight / config / download / verify |
20 | no eligible user on the device |
25 | more eligible users than the cap; the first N installed |
60 | a leftover /usr/local/bin/tokenshift survived removal |
125 | at least one installed user hit a fatal step |
Windows shares 10 / 30 / 40 / 45 for preflight / config / download / verify, and adds
50 for binary placement, 80 for telemetry, 90 for enroll, and 115 for the closing
self-update round-trip. The multi-user codes (20, 25, 60, 125) never appear — one run
installs one user, so a per-user step failure is the run’s own exit code rather than rolling
up into 125 the way the sh arm does.
For inventory — asking a device days later whether it is installed, outside a run — each
installed user carries the complete run log at ~/.tokenshift/install-<stamp>.log and a
single-line verdict at ~/.tokenshift/install-status. There is deliberately no device-wide
file: an inventory script already runs as root and can read any home, and a shared path in a
world-writable directory could be pre-created by a local user to report a device as compliant
when nothing was installed.
On Windows the same pair lands in %USERPROFILE%\.tokenshift.
A Jamf extension attribute, Intune custom attribute, or Workspace ONE sensor reads them with:
#!/bin/sh# newest per-user verdict on this device; absent means not installedv=$(for h in /Users/*/ /home/*/; do cat "$h/.tokenshift/install-status" 2>/dev/null; done \ | grep . | tail -1)echo "<result>${v:-not-installed}</result>"The Windows equivalent, for an Intune custom attribute script:
$v = Get-ChildItem $env:SystemDrive\Users -Directory -ErrorAction SilentlyContinue | ForEach-Object { Get-Content "$($_.FullName)\.tokenshift\install-status" -ErrorAction SilentlyContinue } | Select-Object -Last 1if ($v) { $v } else { 'not-installed' }Each verdict ends with sig=verified|skipped|rejected|unchecked, on every OS — so the same
query also reports whether the artifact’s signature was checked on that endpoint. See
Installation & distribution → Verification at install time.
Updating the manifest
Section titled “Updating the manifest”The manifest is read once at session start and cached for the lifetime of
the process. Pushing a new manifest takes effect on the next agent
session (or the next tokenshift invocation). No restart required for
already-running shells beyond the agent itself.
Removing
Section titled “Removing”# remove the binary store and PATH wiring (run as the user)rm -rf "$HOME/.tokenshift/bin"rm -f "$HOME/.tokenshift/env" /usr/local/bin/tokenshiftsudo rm -f /etc/profile.d/tokenshift.sh # if the Ansible playbook was used
# remove the system manifestrm /etc/tokenshift/enrollment.jsonOn Windows, run it as the user:
tokenshift uninstall --purgetokenshift uninstall --purge removes hooks and per-user state but
never touches the system-deployed manifest — /etc/tokenshift/enrollment.json or
%PROGRAMDATA%\tokenshift\enrollment.json stays your MDM’s responsibility.
- Quickstart — the three-step install flow.
- Installation & distribution — the full security model: pinning, transport, threat surface.