Skip to content
Bart Reardon edited this page Aug 4, 2025 · 4 revisions

Outset 4.2.0 contains a feature for deploying scripts as MDM payloads. overrides and run-once are recorded as per usual

Setup

encode your script as a base64 string: base64 -i /path/to/script.sh -w80

construct a payload in the following format:

<?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>script_payloads</key>
        <dict>
                <key>ACTION_TYPE</key>
                <dict>
                        <key>SCRIPT_NAME</key>
                        <data>
                        BASE64_ENCODED_DATA
                        </data>
                </dict>
        </dict>
</dict>
</plist>

ACTION_TYPE

can be one of the standard outset folder names, e.g. login-every, login-once etc. You can include multiple action types with additional <key><string> pairs per action.

SCRIPT_NAME

Can be any unique string. Set the users desktop picture is a valid script name. You can include multiple scripts per action type with additional <key><string> pairs per script.

BASE64_ENCODED_DATA

This is your base64 encoded script

Deploying multiple payloads

When deploying profiles on macOS you need to be aware that the behaviour of deploying more than one profile to the same preference domain that contain identical parent keys is undefined. In practice macOS will likely load one of them but not both.

Example:

The following configuration will not work. One of Payload 1 or Payload 2 will not be available if both are deployed to the same device as they have the same <key>script_payloads</key> parent key present.

Payload 1

<?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>script_payloads</key>
        <dict>
                <key>login-every</key>
                <dict>
                        <key>Login Script for Everyone</key>
                        <data>
                        BASE64_ENCODED_DATA
                        </data>
                </dict>
        </dict>
</dict>
</plist>

Payload 2

<?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>script_payloads</key>
        <dict>
                <key>login-every</key>
                <dict>
                        <key>Login Script for VIP's</key>
                        <data>
                        BASE64_ENCODED_DATA
                        </data>
                </dict>
        </dict>
</dict>
</plist>

script_payloads Identifier

To acheive the requirement of unique parent keys, Outset supports the addition of an identifier to the parent key, which is in the form of any valid text appended to the end of the script_payloads keyword.

Example:

<?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>script_payloads_VIP</key>
        <dict>
                <key>login-every</key>
                <dict>
                        <key>Login Script for VIP's</key>
                        <data>
                        BASE64_ENCODED_DATA
                        </data>
                </dict>
        </dict>
</dict>
</plist>

The addition of _VIP makes <key>script_payloads_VIP</key> unique and you can now deploy this in addition to any other script payloads.

Behaviour

By default, Outset will only process managed payload scripts if present (i.e. delivered via MDM). For testing with local profiles in /Library/Preferences/, run outset with the --debug flag

If a payload for a givin type is present as a payload, scripts located on device in the /usr/local/outset/ processing folders will be ignored. For instance a login-every payload will cause outset to ignore all scripts in /usr/local/outset/login-every

To create an override for a payload delivered script run /usr/local/outset/outset --add-override payload="Script Name" where Script Name is the key name present in the payload.

Example:

For the given payload

<key>script_payloads</key>
    <dict>
        <key>login-once</key>
        <dict>
            <key>Set the users desktop picture</key>
            <data>
            BASE64_ENCODED_DATA
            </data>
    </dict>
</dict>

use the following override

/usr/local/outset/outset --add-override payload="Set the users desktop picture"

Because payloads are delivered by MDM and are immutable, script hashing is not performed and hash verification is not required.

Generating payloads with outset-payload

Outset 4.2.0 includes a helper script /usr/local/outset/Outset.app/Contents/Resources/outset-payload that can be used to generate payload plists ready for uploading to your MDM.

outset-payload can operate on individual files or a prepared folder structure

Generate from one or more files

Run outset-payload on one or more files using the following syntax:

outset-payload --file /path/to/file1.sh [--file /path/to/file2.sh] --target <type>
  • --file can be specified multiple times.
  • <type> specifies one of the outset processing types. Default is login-once

Generate from a directory

To create an empty directory structure run:

outset-payload --create-payload-dirs <dirname>

where <dirname> is the path to a root directory structure. If this path doesn't existing it will be created. This will populate the named directory with the standard outset processing folders.

With a folder structure populated with your desired script payloads run:

outset-payload --directory <dirname>

Additional Options

The following additional options are recommended:

  • --identifier <name>: Sets a unique payload identifier (required if deploying more than one payload in seperate plists)
  • --output <filename>: Outputs the results to the named file. Default is outset-payload.plist in the current directory.

Run with --help to see all available options.

Example plist

<?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>script_payloads</key>
	<dict>
		<key>boot-every</key>
		<dict>
			<key>Boot every Script</key>
			<data>
				SGVsbG8gZnJvbSBib290IGV2ZXJ5IFNjcmlwdAo=
            </data>
		</dict>
		<key>boot-once</key>
		<dict>
			<key>Boot once Script</key>
			<data>
                ZWNobyAnSGVsbG8sIFdvcmxkISc=
            </data>
		</dict>
		<key>login-every</key>
		<dict>
			<key>Login every Script</key>
			<data>
				b3BlbiAiaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUSIK
            </data>
		</dict>
		<key>login-once</key>
		<dict>
			<key>Login once Script</key>
			<data>
                SGVsbG8gZnJvbSBsb2dpbiBvbmNlIFNjcmlwdAo=
            </data>
		</dict>
	</dict>
	<key>script_payloads_special</key>
	<dict>
		<key>login-every</key>
		<dict>
			<key>Special login every Script</key>
			<data>
                SGVsbG8gZnJvbSBTcGVjaWFsIGxvZ2luIGV2ZXJ5IFNjcmlwdAo=
            </data>
		</dict>
	</dict>
</dict>
</plist>
Clone this wiki locally