• Stars
    star
    204
  • Rank 192,063 (Top 4 %)
  • Language
    Python
  • License
    MIT License
  • Created over 10 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Automate building and integrating OS X installer packages to install Configuration Profiles.

Make Profile Pkg

Given a Configuration Profile as an argument, this script:

  • builds a flat package that installs the profile to a configurable path
  • creates a postinstall script to install the profile:
    • (optionally removing the .mobileconfig file after installation)
  • saves an uninstall script for the profile alongside the package
  • optionally imports the pkg into a Munki repo (see the -m option)
    • note: see the 'Munki-specific use' section below regarding Munki's native support for handling configuration profiles

Run with -h to see the full help.

If the package isn't installed to the boot volume (when using AutoDMG, for example), the profile will be also copied to /private/var/db/ConfigurationProfiles/Setup so it will be instead be installed when the volume is next booted.

Rationale

OS X has a mechanism (the profiles utility) to install profiles given a Configuration Profile on disk. It can also remove a profile given either the path to the file, or the profile's identifier.

Coupled with the fact that we can package these data and instructions and version the package, we can use built-in mechanisms to install the profile and/or check whether this profile has been installed.

Read even more backstory here.

Munki-specific use

Note: As of Munki 2.2, Munki can natively import configuration profiles. I would recommend that if you are only planning to deploy a profile using Munki to use its native support rather than this tool. This tool is still useful for building installer packages for use in different scenarios. See Armin Briegel's blog post for a good example of how this works (specifically towards the bottom, "Importing the Profile into Munki.")

The packages are built to be just as useful without Munki, but if you do import them into Munki, the following additional keys will be set appropriately:

  • description, display_name (taken from the profile's PayloadDisplayName and PayloadDescription keys)
  • installcheck_script (see below)
  • minimum_os_version (Profiles require Lion or newer)
  • uninstall_method and uninstall_script

Additionally, the Munki pkginfo will use the installcheck_script mechanism to check whether the profile is actually installed on the machine, rather than only checking for an installer package receipt. This allows Munki to ensure that the profile is installed even if a user should later remove it after the initial installation. The script is borrowed from Graham Gilbert's sample script from a session at MacTech 2014.

Examples

No options are required:

➜ ./make_profile_pkg.py suppress_ml_icloud_asst.mobileconfig

pkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmpaiPyN5
pkgbuild: Adding top-level postinstall script
pkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/suppress_ml_icloud_asst-2014.04.17.pkg

But, there are several you can set:

➜ ./make_profile_pkg.py \
    --format-name "Profile_%filename%" \
    --installed-path /Library/MyGreatOrg/Profiles \
    --version 10.8 \
    --pkg-prefix org.my.great \
    --delete-after-install \
    --munki-repo-destination "defaults/profiles" \
    --munki-import \
    suppress_ml_icloud_asst.mobileconfig

pkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmp_LwP92
pkgbuild: Adding top-level postinstall script
pkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/Profile_suppress_ml_icloud_asst-10.8.pkg
Copying Profile_suppress_ml_icloud_asst-10.8.pkg to /Volumes/munki_repo/pkgs/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg...
Saving pkginfo to /Volumes/munki_repo/pkgsinfo/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.plist...

In the latter case, here's what the package's postinstall script looks like:

#!/bin/sh
if [ "$3" = "/" ] ; then
    /usr/bin/profiles -I -F /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig
else
    /bin/mkdir -p "$3/private/var/db/ConfigurationProfiles/Setup"
    /bin/cp "$3"/Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig "$3"/private/var/db/ConfigurationProfiles/Setup/suppress_ml_icloud_asst.mobileconfig
    /bin/rm -f "$3/private/var/db/ConfigurationProfiles/Setup/.profileSetupDone"
fi

/bin/rm -f /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig

... and the generated pkginfo:

<?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>autoremove</key>
    <false/>
    <key>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>description</key>
    <string>Custom: com.apple.SetupAssistant</string>
    <key>display_name</key>
    <string>MCXToProfile: com.apple.SetupAssistant</string>
    <key>installcheck_script</key>
    <string>#!/bin/bash

# The version of the package
PKG_VERSION="10.8"

# The identifier of the package
PKG_ID="org.my.great.Profile_suppress_ml_icloud_asst"

# The identifier of the profile
PROFILE_ID="suppress_ml_icloud_asst"

# The version installed from pkgutil
VERSION_INSTALLED=`/usr/sbin/pkgutil --pkg-info "$PKG_ID" | grep version | sed 's/^[^:]*: //'`

if ( /usr/bin/profiles -P | /usr/bin/grep -q $PROFILE_ID ); then
    # Profile is present, check the version
    if [ "$VERSION_INSTALLED" = "$PKG_VERSION" ]; then
        # Correct version, all good
        exit 1
    else
        exit 0
    fi
else
    # Profile isn't there, need to install
    exit 0
fi
</string>
    <key>installed_size</key>
    <integer>4</integer>
    <key>installer_item_hash</key>
    <string>b968f5dd9fed506e6592cb26887034c1346339a4dc3e4312e292f40f094e9cb7</string>
    <key>installer_item_location</key>
    <string>defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg</string>
    <key>installer_item_size</key>
    <integer>4</integer>
    <key>minimum_os_version</key>
    <string>10.7</string>
    <key>name</key>
    <string>Profile_suppress_ml_icloud_asst</string>
    <key>receipts</key>
    <array>
        <dict>
            <key>installed_size</key>
            <integer>4</integer>
            <key>packageid</key>
            <string>org.my.great.Profile_suppress_ml_icloud_asst</string>
            <key>version</key>
            <string>10.8</string>
        </dict>
    </array>
    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh

/usr/bin/profiles -R -p suppress_ml_icloud_asst
/bin/rm -f /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig
/usr/sbin/pkgutil --forget org.my.great.Profile_suppress_ml_icloud_asst
</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>10.8</string>
</dict>
</plist>

Signing Packages

Output packages can be optionally signed using the --sign option. A valid identity must be provided. To find valid identities that can be used for signing: /usr/bin/security find-identity -p basic -v

Note that if you use Apple developer certificates, you must use an Installer type certificate to sign packages using pkgbuild. Note also that if you use a certificate that is untrusted on client machines, your package will not install.

Use the common name of a valid identity to pass to the --sign argument:

 ./make_profile_pkg.py \
    --format-name "Profile_%filename%" \
    --installed-path /Library/MyGreatOrg/Profiles \
    --version 10.8 \
    --pkg-prefix org.my.great \
    --delete-after-install \
    --munki-repo-destination "defaults/profiles" \
    --munki-import \
    --sign "3rd Party Mac Developer Installer" \
    suppress_ml_icloud_asst.mobileconfig

pkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmp_LwP92
pkgbuild: Adding top-level postinstall script
pkgbuild: Signing package with identity "3rd Party Mac Developer Installer" from keychain /Users/tsutton/Library/Keychains/login.keychain
pkgbuild: Adding certificate "Apple Worldwide Developer Relations Certification Authority"
pkgbuild: Adding certificate "Apple Root CA"
pkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/Profile_suppress_ml_icloud_asst-10.8.pkg
Copying Profile_suppress_ml_icloud_asst-10.8.pkg to /Volumes/munki_repo/pkgs/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg...
Saving pkginfo to /Volumes/munki_repo/pkgsinfo/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.plist...

You may be prompted to approve the use of your identity by pkgbuild and security. These settings can be changed in Keychain Access by selecting your private key associated with the certificate and choosing File -> Get Info -> Access Control.

More Repositories

1

brigadier

Fetch and install Boot Camp ESDs with ease.
Python
2,017
star
2

osx-vm-templates

macOS templates for Packer and VeeWee.
Shell
1,120
star
3

mcxToProfile

Convert macOS property lists, defaults and MCX into Configuration Profiles with Custom Settings payloads
Python
533
star
4

python-macadmin-tools

List of open-source Python-based Mac sysadmin tools
Python
371
star
5

brew-pkg

Build OS X installer packages directly from Homebrew formulae
Ruby
196
star
6

speedwagon

Download iOS/tvOS/watchOS/xrOS simulators without Xcode or macOS
Go
120
star
7

aamporter

Utility to batch download Adobe Creative Suite/Cloud updates and optionally import them into a Munki repository.
Python
86
star
8

make-adobe-cc-license-pkg

Tool for building macOS installer packages and Munki pkginfos for Adobe Creative Cloud license files.
Python
75
star
9

customdisplayprofiles

A command-line utility for setting ColorSync profiles for connected displays on OS X.
Python
66
star
10

scripts

Miscellaneous scripts.
Python
34
star
11

winclone-image-builder

Using Packer and Vagrant to build Windows images automatically
Python
31
star
12

python-macadmins-2015

Python for Mac Admins 2015 talk (MacDevOps, MacDeploy) resources
Python
28
star
13

munki-conditions

Admin-provided conditions for Munki
Python
22
star
14

brewbus

Very simple Omnibus-style OS X installer packages from Homebrew.
Shell
18
star
15

XProtectPackager

Tool to rapidly package and import Apple's XProtect definitions for distribution to clients
Python
16
star
16

brew-stew

Monolithic homebrew packages for dev environment deployment
Python
14
star
17

autopkg-ci

Public AutoPkg CI with Jenkins.
Python
14
star
18

presentation-tools

Tools for doing presentations
Shell
13
star
19

localprofilemanager

Client-side tool for managing OS X Configuration Profiles
Python
12
star
20

packer-startosinstall

Shell
8
star
21

vagrant-bsdpy

A basic Vagrant lab for testing/hacking BSDPy, a Python NetBoot server
Shell
8
star
22

macops.ca

Source for https://macops.ca
HTML
6
star
23

docker-xip

Docker image for unpacking .xip files
Dockerfile
6
star
24

homebrew-formulae

Homebrew formulae.
Ruby
5
star
25

docker-psscriptanalyzer

Shell
5
star
26

jss-vagrant

Simple Vagrant environment for bootstrapping a Casper JSS.
Shell
5
star
27

adobe-ccp-automation

Experimenting with automating CCP
Python
5
star
28

docker-download-xcode

Tools and docker image to automate downloading Xcode
Ruby
4
star
29

pyvideo-urlgrabber

Script to print out video URLs from http://pyvideo.org
Python
4
star
30

uptime

A polyglot `uptime` example to learn some Bazel
Starlark
3
star
31

korsakow-editor

Java
2
star
32

munkibuilds.org

Configuration for munkibuilds.org.
HTML
1
star
33

mas-fetch

Testing fetching OS X installers using argon/mas
Python
1
star
34

datadog-agent-apple-silicon-build

Building the Datadog Agent on Apple Silicon
Shell
1
star
35

Do_not_update-pref_files

1
star