{"id":19639019,"url":"https://github.com/timsutton/make-profile-pkg","last_synced_at":"2025-06-10T15:34:57.756Z","repository":{"id":15262424,"uuid":"17991552","full_name":"timsutton/make-profile-pkg","owner":"timsutton","description":"Automate building and integrating OS X installer packages to install Configuration Profiles.","archived":false,"fork":false,"pushed_at":"2018-10-12T18:45:09.000Z","size":43,"stargazers_count":205,"open_issues_count":5,"forks_count":25,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-06-05T12:13:45.737Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timsutton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-21T19:25:27.000Z","updated_at":"2025-02-06T21:14:53.000Z","dependencies_parsed_at":"2022-09-05T02:50:52.085Z","dependency_job_id":null,"html_url":"https://github.com/timsutton/make-profile-pkg","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timsutton%2Fmake-profile-pkg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timsutton%2Fmake-profile-pkg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timsutton%2Fmake-profile-pkg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timsutton%2Fmake-profile-pkg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timsutton","download_url":"https://codeload.github.com/timsutton/make-profile-pkg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timsutton%2Fmake-profile-pkg/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259102465,"owners_count":22805475,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T12:43:47.699Z","updated_at":"2025-06-10T15:34:57.727Z","avatar_url":"https://github.com/timsutton.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Make Profile Pkg\n\nGiven a Configuration Profile as an argument, this script:\n- builds a flat package that installs the profile to a configurable path\n- creates a postinstall script to install the profile:\n  - (optionally removing the .mobileconfig file after installation)\n- saves an uninstall script for the profile alongside the package\n- optionally imports the pkg into a Munki repo (see the `-m` option)\n  - *note*: see the 'Munki-specific use' section below regarding Munki's native support for handling configuration profiles\n\nRun with `-h` to see the full help.\n\nIf the package isn't installed to the boot volume (when using [AutoDMG](https://github.com/MagerValp/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.\n\n\n### Rationale\n\nOS 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.\n\nCoupled 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.\n\nRead even more backstory [here](http://macops.ca/how-to-package-profiles).\n\n\n### Munki-specific use\n\n*Note*: As of [Munki 2.2](https://github.com/munki/munki/releases/tag/v2.2.0.2399), 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](http://scriptingosx.com/2015/01/push-settings-with-munkis-new-profile-support) for a good example of how this works (specifically towards the bottom, \"Importing the Profile into Munki.\")\n\nThe 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:\n- `description`, `display_name` (taken from the profile's `PayloadDisplayName` and `PayloadDescription` keys)\n- `installcheck_script` (see below)\n- `minimum_os_version` (Profiles require Lion or newer)\n- `uninstall_method` and `uninstall_script`\n\nAdditionally, 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](https://github.com/grahamgilbert/mactech_2014/blob/effbfbfad4f1dfa9328287127c40a9051dcd4cb2/Profile/installcheck_script_v2.sh) from a session at MacTech 2014.\n\n\n### Examples\n\nNo options are required:\n\n```bash\n➜ ./make_profile_pkg.py suppress_ml_icloud_asst.mobileconfig\n\npkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmpaiPyN5\npkgbuild: Adding top-level postinstall script\npkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/suppress_ml_icloud_asst-2014.04.17.pkg\n```\n\nBut, there are several you can set:\n\n```bash\n➜ ./make_profile_pkg.py \\\n    --format-name \"Profile_%filename%\" \\\n    --installed-path /Library/MyGreatOrg/Profiles \\\n    --version 10.8 \\\n    --pkg-prefix org.my.great \\\n    --delete-after-install \\\n    --munki-repo-destination \"defaults/profiles\" \\\n    --munki-import \\\n    suppress_ml_icloud_asst.mobileconfig\n\npkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmp_LwP92\npkgbuild: Adding top-level postinstall script\npkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/Profile_suppress_ml_icloud_asst-10.8.pkg\nCopying Profile_suppress_ml_icloud_asst-10.8.pkg to /Volumes/munki_repo/pkgs/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg...\nSaving pkginfo to /Volumes/munki_repo/pkgsinfo/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.plist...\n```\n\nIn the latter case, here's what the package's postinstall script looks like:\n\n```bash\n#!/bin/sh\nif [ \"$3\" = \"/\" ] ; then\n    /usr/bin/profiles -I -F /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig\nelse\n    /bin/mkdir -p \"$3/private/var/db/ConfigurationProfiles/Setup\"\n    /bin/cp \"$3\"/Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig \"$3\"/private/var/db/ConfigurationProfiles/Setup/suppress_ml_icloud_asst.mobileconfig\n    /bin/rm -f \"$3/private/var/db/ConfigurationProfiles/Setup/.profileSetupDone\"\nfi\n\n/bin/rm -f /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig\n```\n\n\n... and the generated pkginfo:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n\u003cdict\u003e\n    \u003ckey\u003eautoremove\u003c/key\u003e\n    \u003cfalse/\u003e\n    \u003ckey\u003ecatalogs\u003c/key\u003e\n    \u003carray\u003e\n        \u003cstring\u003etesting\u003c/string\u003e\n    \u003c/array\u003e\n    \u003ckey\u003edescription\u003c/key\u003e\n    \u003cstring\u003eCustom: com.apple.SetupAssistant\u003c/string\u003e\n    \u003ckey\u003edisplay_name\u003c/key\u003e\n    \u003cstring\u003eMCXToProfile: com.apple.SetupAssistant\u003c/string\u003e\n    \u003ckey\u003einstallcheck_script\u003c/key\u003e\n    \u003cstring\u003e#!/bin/bash\n\n# The version of the package\nPKG_VERSION=\"10.8\"\n\n# The identifier of the package\nPKG_ID=\"org.my.great.Profile_suppress_ml_icloud_asst\"\n\n# The identifier of the profile\nPROFILE_ID=\"suppress_ml_icloud_asst\"\n\n# The version installed from pkgutil\nVERSION_INSTALLED=`/usr/sbin/pkgutil --pkg-info \"$PKG_ID\" | grep version | sed 's/^[^:]*: //'`\n\nif ( /usr/bin/profiles -P | /usr/bin/grep -q $PROFILE_ID ); then\n    # Profile is present, check the version\n    if [ \"$VERSION_INSTALLED\" = \"$PKG_VERSION\" ]; then\n        # Correct version, all good\n        exit 1\n    else\n        exit 0\n    fi\nelse\n    # Profile isn't there, need to install\n    exit 0\nfi\n\u003c/string\u003e\n    \u003ckey\u003einstalled_size\u003c/key\u003e\n    \u003cinteger\u003e4\u003c/integer\u003e\n    \u003ckey\u003einstaller_item_hash\u003c/key\u003e\n    \u003cstring\u003eb968f5dd9fed506e6592cb26887034c1346339a4dc3e4312e292f40f094e9cb7\u003c/string\u003e\n    \u003ckey\u003einstaller_item_location\u003c/key\u003e\n    \u003cstring\u003edefaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg\u003c/string\u003e\n    \u003ckey\u003einstaller_item_size\u003c/key\u003e\n    \u003cinteger\u003e4\u003c/integer\u003e\n    \u003ckey\u003eminimum_os_version\u003c/key\u003e\n    \u003cstring\u003e10.7\u003c/string\u003e\n    \u003ckey\u003ename\u003c/key\u003e\n    \u003cstring\u003eProfile_suppress_ml_icloud_asst\u003c/string\u003e\n    \u003ckey\u003ereceipts\u003c/key\u003e\n    \u003carray\u003e\n        \u003cdict\u003e\n            \u003ckey\u003einstalled_size\u003c/key\u003e\n            \u003cinteger\u003e4\u003c/integer\u003e\n            \u003ckey\u003epackageid\u003c/key\u003e\n            \u003cstring\u003eorg.my.great.Profile_suppress_ml_icloud_asst\u003c/string\u003e\n            \u003ckey\u003eversion\u003c/key\u003e\n            \u003cstring\u003e10.8\u003c/string\u003e\n        \u003c/dict\u003e\n    \u003c/array\u003e\n    \u003ckey\u003euninstall_method\u003c/key\u003e\n    \u003cstring\u003euninstall_script\u003c/string\u003e\n    \u003ckey\u003euninstall_script\u003c/key\u003e\n    \u003cstring\u003e#!/bin/sh\n\n/usr/bin/profiles -R -p suppress_ml_icloud_asst\n/bin/rm -f /Library/MyGreatOrg/Profiles/suppress_ml_icloud_asst.mobileconfig\n/usr/sbin/pkgutil --forget org.my.great.Profile_suppress_ml_icloud_asst\n\u003c/string\u003e\n    \u003ckey\u003euninstallable\u003c/key\u003e\n    \u003ctrue/\u003e\n    \u003ckey\u003eversion\u003c/key\u003e\n    \u003cstring\u003e10.8\u003c/string\u003e\n\u003c/dict\u003e\n\u003c/plist\u003e\n```\n\n### Signing Packages\n\nOutput 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:\n`/usr/bin/security find-identity -p basic -v`\n\nNote 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.\n\nUse the common name of a valid identity to pass to the `--sign` argument:\n```bash\n ./make_profile_pkg.py \\\n    --format-name \"Profile_%filename%\" \\\n    --installed-path /Library/MyGreatOrg/Profiles \\\n    --version 10.8 \\\n    --pkg-prefix org.my.great \\\n    --delete-after-install \\\n    --munki-repo-destination \"defaults/profiles\" \\\n    --munki-import \\\n    --sign \"3rd Party Mac Developer Installer\" \\\n    suppress_ml_icloud_asst.mobileconfig\n\npkgbuild: Inferring bundle components from contents of /var/folders/8t/5trmslfj2cnd5gxkbmkbn5fj38qb2l/T/tmp_LwP92\npkgbuild: Adding top-level postinstall script\npkgbuild: Signing package with identity \"3rd Party Mac Developer Installer\" from keychain /Users/tsutton/Library/Keychains/login.keychain\npkgbuild: Adding certificate \"Apple Worldwide Developer Relations Certification Authority\"\npkgbuild: Adding certificate \"Apple Root CA\"\npkgbuild: Wrote package to /Users/tsutton/git/github/make-profile-pkg/Profile_suppress_ml_icloud_asst-10.8.pkg\nCopying Profile_suppress_ml_icloud_asst-10.8.pkg to /Volumes/munki_repo/pkgs/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.pkg...\nSaving pkginfo to /Volumes/munki_repo/pkgsinfo/defaults/profiles/Profile_suppress_ml_icloud_asst-10.8.plist...\n```\n\nYou 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 -\u003e Get Info -\u003e Access Control.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimsutton%2Fmake-profile-pkg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimsutton%2Fmake-profile-pkg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimsutton%2Fmake-profile-pkg/lists"}