Shell scripts and custom attributes are how Intune does on a Mac what configuration profiles can't. When they don't run, the report often tells you very little: no status, a bare Failed, or an empty result. In this post I'll explain how the Intune management agent delivers scripts, list the requirements that silently stop them, and show where to look on the Mac and how to prove a fix.
Errors this guide fixes
bad interpreterTerminal (manual test run)command not foundTerminal (manual test run)Operation not permittedTerminal (manual test run)2016214831 The provided log file path must exist.Collect logs (macOS script)2016214828 The number of log files exceeded the allowed limit of 25 files.Collect logs (macOS script)2016214834 Log file size cannot exceed 60 MB.Collect logs (macOS script)
Symptoms#
- The script's Device status or User status stays empty for a Mac, or shows
Failed. - A custom attribute's Result column is empty, out of date or shows an error.
- The script works when you paste it into Terminal, but not from Intune; or a test run prints a
bad interpretererror,command not foundorOperation not permitted. - Collect logs fails with one of these:
2016214831 The provided log file path must exist.
2016214828 The number of log files exceeded the allowed limit of 25 files.
2016214834 Log file size cannot exceed 60 MB.Match these on the decimal code and the message: Microsoft's table gives the same hex code, 0x87D300D1, for both 2016214831 and 2016214834.
Why it happens#
Scripts travel through the agent, not MDM#
Intune silently installs the Microsoft Intune management agent at /Library/Intune/Microsoft Intune Agent.app when a Mac gets its first shell script; it shows as IntuneMdmAgent in Activity Monitor. The agent checks for new or changed scripts about every 8 hours, independently of the MDM check-in, and Sync in the admin center starts only an MDM check-in. A script you assigned ten minutes ago may simply not have arrived yet.
Requirements that stop scripts#
| Requirement (Microsoft Learn) | What you see when it's missed |
|---|---|
| macOS 12.0 or later, managed by Intune | No agent, no status |
| Direct internet connection; a proxy isn't supported | Agent can't check in; nothing arrives |
Script starts with a valid shebang such as #!/bin/sh or #!/usr/bin/env zsh | Failed (malformed script) |
| Script file smaller than 1 MB | Upload rejected |
| Run script as signed-in user = Yes needs someone signed in; it then runs for every signed-in user. No (default) runs as root | No run until a user signs in; permission errors in user context |
| Exit code 0 means success | Failed for any non-zero exit code; no rerun unless Max number of times to retry if script fails is set |
| Run time under 60 minutes | Stopped and reported as failed |
Scripts also run in parallel as separate processes, so never rely on one script finishing before another. A script with Script frequency left at Not configured runs once; scheduled scripts also run after a restart, and Microsoft notes they can run more often than scheduled in conditions such as a full disk or a deleted local cache.
How run status is reported#
Run status is sent only when it changes from the last report; if it doesn't change, Intune refreshes the timestamp every 7 days. So Last updated is not "last ran". If a Mac goes offline after receiving a script but before reporting, it never reports that run at all, which Microsoft lists as a known issue.
How to fix it#
- Confirm the agent and force a check-in. If the agent folder is missing, check the assignment: scripts assigned to user groups apply to any user who signs in to the Mac. An unhealthy agent tries to recover for 24 hours, then removes itself and reinstalls while scripts are still assigned.
The user can do the same from Company Portal: select the Mac, then Check status.Bash
ls -d "/Library/Intune/Microsoft Intune Agent.app" pgrep -l IntuneMdmAgent sudo killall IntuneMdmAgent # the agent restarts and checks in immediately - Read the agent logs. The system-level log is
/Library/Logs/Microsoft/Intune/IntuneMDMDaemon date--time.logand the per-user log is~/Library/Logs/Microsoft/Intune/IntuneMDMAgent date--time.log. Search both for the script's name; a broad first pass looks like this:Bashgrep -i "script" /Library/Logs/Microsoft/Intune/IntuneMDMDaemon*.log | tail -n 40 grep -i "script" ~/Library/Logs/Microsoft/Intune/IntuneMDMAgent*.log | tail -n 40 - Reproduce the context. Run the script as an executable so its shebang is used:
chmod +x script.sh, thensudo ./script.sh; echo "exit: $?"for a root script, or./script.shas the user for a user script. Then check the usual suspects:- A
bad interpretererror (under sudo, an "unable to execute" error): a wrong shebang path or Windows line endings.file script.shreports "with CRLF line terminators"; fix it withtr -d '\r' < script.sh > fixed.sh. command not found: don't rely on your Terminal's PATH; call tools by full path (/usr/bin/defaults, notdefaults) and don't assume Homebrew exists.Operation not permitted: even root can't touch privacy-protected locations without consent. Grant access with a Privacy Preferences Policy Control profile or avoid those paths.- An unexpected
Failed: the last command decides the exit code, so a finalgrepwith no match fails the whole script. End with an explicit exit code.
- A
- Make scripts report on themselves. Intune shows only success or failure, so log to your own file (this example runs as root):
Bash
#!/bin/zsh LOG="/Library/Logs/Contoso/rename-check.log" /bin/mkdir -p "${LOG:h}" exec >> "$LOG" 2>&1 echo "$(/bin/date -u +"%Y-%m-%dT%H:%M:%SZ") start" name=$(/usr/sbin/scutil --get ComputerName) || { echo "cannot read ComputerName"; exit 1; } echo "ComputerName is $name" exit 0 - Fix custom attributes. They live under Devices › By platform › macOS › Organize devices › Custom attributes for macOS and run every 8 hours. The script must echo one value matching the data type you chose (String, Integer or Date), the output must be 20 KB or less, and dates must be ISO-8601:
Bash
#!/bin/zsh # Integer: free space on the startup volume in GB /bin/df -g / | /usr/bin/awk 'NR==2 {print $4}' - Collect logs remotely when you can't reach the Mac: Devices › Manage devices › Scripts and remediations › Platform scripts, select the script, then a device in Device status or User status, and Collect logs. Use full absolute paths separated only by semicolons (
/Library/Logs/Contoso/a.log;/Users/Shared/b.zip), stay within 60 MB compressed or 25 files, and use allowed extensions (.log, .zip, .gz, .tar, .txt, .xml, .crash, .rtf). The upload happens at the next agent check-in, the agent logs are added automatically, and any missing file is listed inLogCollectionInfo.txt.
Verify the fix#
- After a forced agent check-in, Device status shows Success (exit code 0) for the Mac.
- Your script's own log shows the run with a timestamp, and the agent log shows no retry for it.
- For custom attributes, the Result column shows the echoed value after the next 8-hour run.
Prevent it next time#
- Test as root and as a standard user, save with LF line endings, use full paths and finish with an explicit exit code.
- Set retries for scripts that can fail transiently, and a frequency only for idempotent scripts.
- Keep run time far below 60 minutes, and plan around the 8-hour agent cycle rather than the Sync button.
- The same agent installs DMG and unmanaged PKG apps; see macOS PKG and DMG apps failing in Intune. For Windows, see Intune PowerShell scripts not running.

