Munki.wiki.git

Repo URL: https://github.com/munki/munki.wiki.git
Edited by:
Cover image: Cover image
Share this using: email, Google+, Twitter, Facebook.
Exports: EPUB | MOBI

0.0.0.1 Introduction

The purpose of this list is so that when installing Adobe CS5 products using munki, one can determine which updates are needed to bring a fresh install fully up to date. This list is ordered by Product and also by Update. This allows for easier creation of update_for keys in your pkginfo files.

See https://blogs.adobe.com/csupdates/ for the latest news on Creative Suite Updates.

0.0.0.2 By Product

0.0.0.2.1 Photoshop CS5
  • Adobe Player for Embedding 3.1
  • Adobe Bridge 4.0.4
  • Adobe Device Central 3
  • Adobe Extend Script Toolkit 3.5.0
  • Adobe Extension Manager 5.0.1
  • Adobe Photoshop 12.0.2
  • Adobe XMP Panels
  • Camera Raw 6.4
  • CSXS Infrastructure (CS Live Services Update for CS)
0.0.0.2.2 Dreamweaver CS5
  • Adobe Device Central 3
  • Adobe Player for Embedding 3.1
  • CSXS Infrastructure (CS Live Services Update for CS)
  • Dreamweaver CS5 11.0.3 Update
  • Adobe Extension Manager 5.0.1
0.0.0.2.3 Flash Pro CS5
  • Adobe Bridge 4.0.4
  • Adobe Player for Embedding 3.1
  • Adobe XMP Panels
  • Adobe Extend Script Toolkit 3.5.0
  • Adobe Device Central 3
  • Adobe Extension Manager 5.0.1
  • Adobe Pixel Bender Toolkit 2.5 Update (Repackage with AAMEE)
  • CSXS Infrastructure (CS Live Services Update for CS)
  • Flash Professional CS5 11.0.2
  • Adobe Media Encoder CS5 5.0.1
  • Camera Raw 6.4
0.0.0.2.4 Illustrator CS5
  • Adobe Bridge 4.0.4
  • Adobe Player for Embedding 3.1
  • Adobe XMP Panels
  • Adobe Extend Script Toolkit 3.5.1
  • Adobe Device Central 3
  • Adobe Extension Manager 5.0.1
  • Adobe Illustrator 15.0.2 Update
  • CSXS Infrastructure (CS Live Services Update for CS)
  • Camera Raw 6.4
0.0.0.2.5 InDesign CS5
  • Adobe Bridge 4.0.4
  • Adobe Player for Embedding 3.1
  • Adobe XMP Panels
  • Adobe Extend Script Toolkit 3.5.1
  • Adobe Extension Manager 5.0.1
  • Adobe InDesign CS5 7.0.4 Update
  • CSXS Infrastructure (CS Live Services Update for CS)
  • Adobe Extend Script Toolkit 3.5.1
  • Adobe Media Encoder CS5 5.0.1
  • Camera Raw 6.4

0.0.0.3 By Update

0.0.0.3.1 Adobe Bridge 4.0.4
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.2 Adobe Player for Embedding 3.1
  • Dreamweaver CS5
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.3 Adobe Device Central 3
  • Dreamweaver CS5
  • Flash Professional CS5
  • Illustrator CS5
  • Photoshop CS5
0.0.0.3.4 Adobe Extend Script Toolkit 3.5.0
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.5 Adobe Extension Manager 5.0.1
  • Dreamweaver CS5
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.6 Adobe XMP Panels
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.7 Camera Raw 6.4
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.8 CSXS Infrastructure (CS Live Services Update for CS)
  • Dreamweaver CS5
  • Flash Professional CS5
  • Illustrator CS5
  • InDesign CS5
  • Photoshop CS5
0.0.0.3.9 Adobe Media Encoder CS5 5.0.1
  • Flash Professional CS5
  • InDesign CS5
0.0.0.3.10 Adobe Pixel Bender Toolkit 2.5 Update (Repackage with AAMEE)
  • Flash Professional CS5
0.0.0.3.11 Adobe Photoshop 12.0.2
  • Photoshop CS5
0.0.0.3.12 Dreamweaver CS5 11.0.3 Update
  • Dreamweaver CS5
0.0.0.3.13 Flash Professional CS5 11.0.2
  • Flash Professional CS5
0.0.0.3.14 Adobe Illustrator 15.0.2 Update
  • Illustrator CS5
0.0.0.3.15 Adobe InDesign CS5 7.0.4 Update
  • InDesign CS5

    0.0.0.3.15 Adobe CS6 products

1 Introduction

Info on installing and removing Adobe CS6 products with Munki.

2 Details

Early testing seems to indicate that Munki can treat Adobe CS6 deployment packages generated with AAMEE 3 exactly the same as CS5/5.5 deployment packages.

See Adobe CS5 for details.

This page will be updated as more information becomes known.

2.0.1 Introduction

Due to an issue with the Adobe Reader X/XI installer packages, installation will fail at the loginwindow. Here’s how to fix it without repackaging.

2.0.2 Current Recommendation

Use AutoPkg.

The AdobeReader.munki recipe finds the latest version of Adobe Reader X/XI, downloads it, imports it into your Munki repo, and adds the appropriate preinstall_script to the package info.

2.0.3 Details for those who wish to inflict more pain upon themselves

See this discussion: Adobe Reader X 10.1 preinstall script fail

To avoid the issue, add a preinstall_script to the package info:

    <key>preinstall_script</key>
    <string>#!/bin/sh
if [ -e "/Applications/Adobe Reader.app" ]; then
    rm -r "/Applications/Adobe Reader.app"
fi
exit 0
    </string>

This has been tested up through the 11.0.07 update and is still required.

2.0.4 Current Recommendation

Use AutoPkg.

The AdobeFlashPlayer.munki recipe finds the latest Flash Player installer, downloads it, extracts the embedded package, and imports it into your Munki repo.

2.0.5 Details for those who like extra work

Starting with release 10.1 of Adobe Flash Player, and at least through the current 10.3 releases, the item at the root of the disk image is NOT an Apple package, but rather a wrapper application.

To use this with munki, open the “Install Adobe Flash Player” application bundle (control-click on the application and choose “Show Package Contents”), navigate to the Resources folder and extract the “Adobe Flash Player.pkg” from this folder. Wrap it in a disk image to use with munki.

Even better, let munkiimport do the hard work for you. Mount the disk image, then:

/usr/local/munki/munkiimport /Volumes/Flash\ Player/Install\ Adobe\ Flash\ Player.app/Contents/Resources/Adobe\ Flash\ Player.pkg

(You might have to alter the path if the disk image mounts under another name.)

Later releases of Flash Player made this trickier, as the promoted download was often an app that did not have an embedded package. If you signed up for a “Flash Player Distribution Agreement” with Adobe, you’d be given a URL that pointed to a download that did contain the embedded package.
Allowing the installation of packages signed with untrusted or expired certificates

2.0.6 Introduction

Munki 3 supports optionally allowing the installation of packages signed with untrusted or expired certificates.

2.0.7 Background

Apple installer packages can be (and often are) signed by their creator, to ensure that the contents have not been tampered with. Apple’s installer by default will refuse to install packages with invalid or untrusted signatures. A package that was signed without the use of a trusted timestamp will also refuse to validate if any of the certificates in the signing chain have expired. This can mean that a package Munki would happily install this week will now fail to install because a cert has expired.

A managedsoftwareupdate session with such an expired package might look like this:

$ sudo managedsoftwareupdate --installonly
Managed Software Update Tool
Copyright 2010-2017 The Munki Project
https://github.com/munki/munki

Starting...
Installing Adobe Photoshop Lightroom (1 of 2)...
    Mounting disk image Lightroom_5_LS11_mac_5_7-5.7-0.0.dmg...
    Install of Adobe Photoshop Lightroom 5.pkg failed with return code 1...
ERROR: ------------------------------------------------------------------------------
ERROR: installer: Package name is Adobe Photoshop Lightroom 5.7
ERROR: installer: Certificate used to sign package is not trusted. Use -allowUntrusted to override.
ERROR: ------------------------------------------------------------------------------

We can examine the package signature:

$ pkgutil --check-signature /Volumes/Lightroom\ 5.7/Adobe\ Photoshop\ Lightroom\ 5.pkg 
Package "Adobe Photoshop Lightroom 5.pkg":
   Status: signed by a certificate that has since expired
   Certificate Chain:
    1. Developer ID Installer: Adobe Systems, Inc.
       SHA1 fingerprint: 9D 75 C9 20 01 4A 65 04 94 A7 63 95 E3 91 93 47 04 E8 57 DF
       -----------------------------------------------------------------------------
    2. Developer ID Certification Authority
       SHA1 fingerprint: 3B 16 6C 3B 7D C4 B7 51 C9 FE 2A FA B9 13 56 41 E3 88 E1 86
       -----------------------------------------------------------------------------
    3. Apple Root CA
       SHA1 fingerprint: 61 1E 5B 66 2C 59 3A 08 FF 58 D1 4A E2 24 52 D1 98 DF 6C 60

And as expected, we see “Status: signed by a certificate that has since expired”.

Traditionally, the Munki admin had two options when this situation occurred: get an updated package from the vendor, or when that was not possible, strip the signature from the expired package. (Apple’s installer will happily install unsigned packages.) This latter approach can be a lot of work.

2.0.8 Another solution

Munki 3 will support an optional key added to the pkginfo for Apple package installer items.

<key>allow_untrusted</key>
<true/>

Adding allow_untrusted = True to a pkginfo for an Apple package installer item will cause Munki to add the -allowUntrusted option when using /usr/sbin/installer to install a package. From man installer:

-allowUntrusted
       Allow install of a package signed by an untrusted (or expired) certificate.

With this new feature, and with the proper key and value added to the pkginfo for Lightroom 5.7, the managedsoftwareupdate session now looks like this:

$ sudo managedsoftwareupdate --installonly
Managed Software Update Tool
Copyright 2010-2017 The Munki Project
https://github.com/munki/munki

Starting...
Installing Adobe Photoshop Lightroom (1 of 1)...
    Mounting disk image Lightroom_5_LS11_mac_5_7-5.7-0.0.dmg...
    Preparing for installation…
    Preparing the disk…
    Preparing Adobe Photoshop Lightroom 5.7…
<snip>
    97.2625 percent complete...
    Registering updated applications…
    97.75 percent complete...
    Running installer actions…
    Finishing the Installation…
    100.0 percent complete...
    The software was successfully installed.

Munki has successfully installed a package with an expired signature.
The appdmg install type is now deprecated, having been superseded by copy_from_dmg.

copy_from_dmg was released with the 0.6.2 munkitools, and can do everything appdmg can, plus more. makepkginfo now creates pkginfo items with copy_from_dmg install methods instead of appdmg for “drag-and-drop” disk images. See https://github.com/munki/munki/wiki/CopyFromDMG for more information.

The rest of this document is historical in nature.

3 Introduction

As of the 0.4.4 release, you can use disk images that contain a single application as a type of munki package. These are usually “drag-and-drop” disk images, where the user is expected to drag the app to the /Applications folder (or actually anywhere on the local disk).
munki will copy a single application to the /Applications folder on the startup disk.

munki’s internal name for this type of installer item is “appdmg”.

4 Details

This feature is meant as a convenience for systems administrators. Instead of having to repackage a drag-and-drop disk image as an Apple installer, admins can simply use the original disk image.

Using this format directly instead of repackaging is not recommended if you need to make changes to the app bundle itself before deployment (Firefox customizations come to mind), or the app offers to install additional items that require admin authorization on first launch (examples include TextMate, TextWrangler, and BBEdit, which offer to install command-line tools on first launch).

This won’t work with disk images that require the user to agree to a Software License Agreement when the disk image is double-clicked in the Finder – hidutil cannot mount these images without user intervention. You’ll either have to create a new disk image minus the Software License Agreement, or just package the app into an Apple package.

If removal is requested, munki uses the path to the app as specified in the “installs” key to do a simple rm -rf of the application bundle.

Sample output from makepkginfo /path/to/Firefox 3.5.3.dmg:

<?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>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>installer_item_location</key>
    <string>apps/Firefox 3.5.3.dmg</string>
    <key>installer_item_size</key>
    <integer>18002</integer>
    <key>installer_type</key>
    <string>appdmg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>org.mozilla.firefox</string>
            <key>CFBundleName</key>
            <string>Firefox</string>
            <key>CFBundleShortVersionString</key>
            <string>3.5.3</string>
            <key>path</key>
            <string>/Applications/Firefox.app</string>
            <key>type</key>
            <string>application</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>Firefox</string>
    <key>uninstall_method</key>
    <string>remove_app</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>3.5.3.0.0</string>
</dict>
</plist>

4.0.1 Introduction

An overview of deploying Mac App Store applications using Munki.

4.0.2 Details

This is technical advice, not legal advice. Make sure you are complying with vendor agreements and have purchased the appropriate number of licenses for the software you wish to deploy.

Basic steps:

  1. Purchase one or more licenses for an application from the App Store under an institutional AppleID.
  2. Download the application (using the institutional AppleID) on a Mac with the Munki admin tools installed.
  3. Import the application into your Munki repo using munkiimport /Applications/Foo.app, where “/Applications/Foo.app” is the path to the downloaded/purchased application.
  4. Deploy the application using Munki the same way as any other application.

When there are updates for the application, repeat steps 2-4 above.

This technique will work for applications that do not do App Store receipt validation. For applications that do App Store receipt validation, you’ll need to use something other than Munki to distribute these applications.

Related links:

https://support.apple.com/kb/HT5061<br>
https://support.apple.com/kb/ht4781<br>
https://support.apple.com/kb/HT4831

VPP and Managed Distribution:

https://www.apple.com/business/vpp/<br>
https://www.apple.com/education/it/vpp/

Q: How do I know if an application does App Store receipt validation?<br>
A: I don’t know how to tell in advance. You’ll know when you try to deploy it and it asks for authorization and refuses to run on deployed machines!

4.0.3 Introduction

Munki can be configured to install available Apple Software Updates, with the benefit that users don’t need to be administrators to install updates.

4.0.4 Details

To install Apple Software Updates with Munki, set InstallAppleSoftwareUpdates to True in [[Munki’s preferences|Preferences]]:

<key>InstallAppleSoftwareUpdates</key>
<true/>

Or using defaults:

defaults write /Library/Preferences/ManagedInstalls InstallAppleSoftwareUpdates -bool True

or via equivalent configuration profile.

For OS X versions prior to 10.11, you may also direct Munki to use a different Apple Software Update server (for example, one you host internally) by setting the SoftwareUpdateServerURL key in Munki’s preferences to the appropriate CatalogURL:

<key>SoftwareUpdateServerURL</key>
<string>http://applesus.myorg.org:8088/index-leopard-snowleopard.merged-1.sucatalog</string>

or again with the defaults command:

defaults write /Library/Preferences/ManagedInstalls SoftwareUpdateServerURL "http://applesus.myorg.org:8088/index-leopard-snowleopard.merged-1.sucatalog"

(Beginning with OS X 10.11, setting this value is not currently recommended)

4.0.4.1 Apple update behavior notes

Munki updates and Apple Software updates can appear and be installed in the same Munki session. To prevent possible conflicts, if any item to be installed or removed from the Munki server is an Apple item, Apple updates will not be processed in the same session. An item from the Munki server is identified as an Apple item if it has the optional apple_item key set toTrue in its pkginfo file.

Additionally, an item will be treated as an apple_item during an update check if the apple_item key is missing but the item contains either a receipts array with a packageid key that starts with com.apple or an installs array with a CFBundleIdentifier key that starts with com.apple.

It is important to note that any Apple application scheduled for install without an apple_item key explicitly set to False will cause the item to be treated as an apple_item during an update check. The implication of this is that if a user has an update waiting to be installed for Pages, as an example, and the Pages update has no apple_item key set no Apple software update checks will be performed for as long as the user postpones the Pages update.

In reality this means that if any high-profile Apple software updates (Security Update, OS X update) became available after the user first received the Pages update they will not be available for install until after Pages is installed. If an important OS X update has also been given a force_install_date by the admin via the apple_update_metadata method and the user doesn’t install the waiting Pages until after the forced date expires, before long Managed Software Center will initiate the final one hour grace period countdown and logout to install the waiting Apple update. This may be a problem from a UX point of view and makes directly managing the apple_item key very important in order to prevent long periods of Apple software update “blackout” for users who tend to postpone waiting updates for long periods on end, or any surprises arising from passed forced install deadlines.

In order to prevent such a blackout the admin has two options:

  • Mark all Apple updates in Munki as unattended where possible
  • Set the apple_item key to <false/> in any Apple item’s pkginfo file

For additional notes on the apple_item key see this section of the Munki wiki.

4.0.4.2 Mavericks and Yosemite notes

Due to changes in how the /usr/sbin/softwareupdate tool works in OS X 10.9 and 10.10, you may have unexpected/undesirable results if you use MCX or configuration profiles to manage the CatalogURL in com.apple.SoftwareUpdate. See this discussion: https://groups.google.com/d/topic/munki-dev/fxnOkoweSIo/discussion

As an alternative to managing this preference with MCX or configuration profiles, consider just directly setting your desired CatalogURL in /Library/Preferences/com.apple.SoftwareUpdate.plist.

4.0.4.3 El Capitan and Sierra notes

Due to changes in how the /usr/sbin/softwareupdate tool works in OS X 10.11, it is no longer recommended to set SoftwareUpdateServerURL in Munki’s preferences. Instead you should just allow Munki to use whatever Apple Software Update is using “normally” – either the system defaults, or a CatalogURL value set in the com.apple.SoftwareUpdate preferences domain.

With the 2.8.0 release of the Munki tools, the SoftwareUpdateServerURL, if set, will be ignored under 10.11+.

Unlike with earlier versions of macOS/OS X, under El Capitan and Sierra, due to the changed implementation, it’s fine to manage com.apple.SoftwareUpdate’s CatalogURL using a configuration profile (or MCX!).

4.0.4.4 Apple Update Metadata

Munki supports admin-provided additional metadata for Apple updates, which allows admins to better control the timing and conditions of Apple updates. Adding metadata information for an Apple update cannot cause Munki to offer any update Apple Software Update will not offer. It can only change how the update, if available from Apple Software Update, is installed. It can allow Munki to install an Apple update in an unattended manner; it can require a logout or restart even if the update normally would not require these, or it can be force installed after a certain date. Again, if Software Update is not offering the item to the client, Apple Update Metadata cannot force it to do so.

More info on Apple Update Metadata is [[Pkginfo For Apple Software Updates|Pkginfo-For-Apple-Software-Updates]].

4.0.4.5 Unattended Apple Updates

The most common use for Apple Update Metadata has been to mark updates as unattended so that Munki will install them in the background.

With the 2.5.0 release of the Munki tools and on OS X Mavericks or later, setting UnattendedAppleUpdates to true, in munki Preferences, will cause Munki to automatically install all possible Apple updates in the background without notifying the user, such as iTunes, Safari, and Command Line Tools updates. Updates requiring a reboot will be ignored by this setting, and blocking applications are automatically extracted from the update’s distribution file. This alleviates the need to create the metadata specified above unless there is a need for using force_install_by_date

<key>UnattendedAppleUpdates</key>
<true/>

4.0.4.6 Using the Munki tools only to install Apple Software Updates

You can use the Munki tools without any Munki repository to install Apple updates. In /Library/Preferences/ManagedPreferences.plist, set AppleSoftwareUpdatesOnly to True.

defaults write /Library/Preferences/ManagedInstalls AppleSoftwareUpdatesOnly -bool True

managedsoftwareupdate will then not request a manifest and catalog(s) from a Munki server, but will proceed directly to checking for (and possibly installing) Apple Software Updates.

Apple Update Metadata functionality is not available with this configuration, since the additional metadata is stored in a Munki repo.
Support for authorized restarts of FileVault 2 volumes

4.1 Introduction

Munki 3 adds the ability to perform FileVault 2 Authorized Restarts. If the needed requirements are met Munki will attempt to perform an authrestart instead of a normal restart. This restarts the system, bypassing the initial unlock. This is especially useful for when doing full OS upgrades, as the actual OS install does not happen until after an initial reboot.

4.2 Requirements

4.2.1 Munki

You’ll need a version of Munki that supports this feature. The current release of Munki 3 is recommended.

New Munki [[Preferences]] controlling authorized restart behavior:

Key Type Default Description
PerformAuthRestarts boolean false Set this to true to configure Munki to attempt authrestarts. Munki admins must opt into Authorized Restarts since there may be some security implications.
RecoveryKeyFile string (Optional) The path of a plist file that contains the credentials used to perform an authrestart. e.g. /var/root/restart.plist This plist file should contain a key RecoveryKey with the value set to either a personal/individual recovery key or the password of an authorized user enabled in FileVault. An example of the file is below.

4.2.1.1 Recovery Key File plist 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>RecoveryKey</key>
    <string>super-secret-password-or-recovery-key</string>
</dict>
</plist>

If a RecoveryKeyFile is not specified, or is specified and the file does not exist or is in the wrong format, Managed Software Center will prompt for a password if:

  • Pending updates require a restart.
  • A user is logged in to the GUI.
  • The current GUI user is in the list of FileVault authorized users.

If Munki cannot obtain the required password or recovery key (either through the RecoveryKeyFile, or by prompting for a password), no auth restart will be attempted, and it will fall back to a normal restart.

4.2.2 OS/Hardware Requirements

Not all versions of macOS and not all hardware types are capable of performing authrestarts. Munki uses fdesetup to check to make sure the machine meets the necessary criteria as well as for the restart.

4.2.2.0.1 fdesetup isactive

Munki will check to make sure FileVault is active (on). If FileVault isn’t on you probably don’t need to be performing an authorized restart. This is checked by running /usr/bin/fdesetup isactive

4.2.2.0.2 fdesetup supportsauthrestart

The authorized restart ability works on 10.8(+) and must also have supported hardware. This is checked by running /usr/bin/fdesetup supportsauthrestart.

4.3 WARNING!

If you decide to use a RecoveryKeyFile, note that leaving a recovery key or password on disk may pose an additional security risk. The use of this feature is up to the discretion of the admin.


4.3.0.1 Implementation notes for auth restarts with user-provided password

Munki 3 adds a new authrestartd daemon. Managed Software Center.app uses UNIX/POSIX sockets to communicate with the daemon, which can run fdesetup commands as root, and allow Managed Software Center.app to tell if FileVault is on, if authrestart is supported, and if the current user is in the list of FileVault users. After asking for and getting a password from the user, Managed Software Center.app communicates again with the authrestartd daemon and sends it the password, which the daemon stores in memory. Soon after, Managed Software Center.app triggers a logout.

When the loginwindow loads, a launchd job causes /usr/local/munki/managedsoftwareupdate to run and install pending updates. After the install, if a restart is required, managedsoftwareupdate uses UNIX/POSIX sockets to communicate with authrestartd and asks authrestartd to perform the restart.

authrestartd, running as root, uses the password it has in memory to perform an authrestart if possible, falling back to a normal restart.

The user password is never written to disk, and is only stored in memory by authrestartd. authrestartd does not ever communicate the stored password to any process other than fdesetup.

4.3.1 Introduction

Munki supports the concept of ‘blocking_applications’. This causes Munki to skip unattended_installs or uninstalls if certain applications are running, and causes Managed Software Center.app to warn the user to quit conflicting applications if they are running when the user chooses to update without logging out.

4.3.2 Details

Munki will skip any unattended_installs or unattended_uninstalls if:

  • There is a blocking_applications key in the pkginfo, and any application listed is running, or
  • There is no blocking_applications key in the pkginfo, and any application in the installs list (if it exists) is running.

Additionally, using similar logic as above, Managed Software Update.app will display an alert asking the user to quit any blocking apps that are running if the user chooses to update without logging out.

The blocking_applications list may be added to the pkginfo for any package, and takes this form:

    <key>blocking_applications</key>
    <array>
        <string>Firefox</string>
        <string>Safari</string>
        <string>Opera</string>
    </array>

or

    <key>blocking_applications</key>
    <array>
        <string>Firefox.app</string>
        <string>Safari.app</string>
        <string>Opera.app</string>
    </array>

This sample blocking_applications list would be suitable for use with the Adobe Flash Player installation package.

The string used to identify the application should be the name of the application bundle – the “.app” extension is optional. Apps do not have to be installed or managed by munki to be included in a blocking_applications list.

Even though it might be useful to block on faceless background applications (like iTunesHelper) or other processes, since normal users do not have the ability to easily quit such processes, don’t use them as blocking_applications; instead specify the item needs a logout or restart as applicable. It would be confusing and frustrating for a user to be notified that installation cannot continue because “Microsoft Database Daemon” is running.

4.3.2.1 blocking_applications vs. installs

If there is no blocking_applications array, and there is an installs array containing one or more applications, Munki will use those applications as a substitute blocking_applications array. This can be convenient, as Munki can “automagically” discover blocking applications for drag-n-drop dmg installs. If you need to customize this behavior, simply create an actual blocking_applications array listing the actual applications you want to block an install. If you want NO applications to block an install, provide an empty blocking_applications array.

<key>blocking_applications</key>
<array>
</array>

4.3.3 Introduction

Many Mac administrators have adapted a modular approach to imaging using tools like InstaDMG or Apple’s System Image Utility. The “modules” of the modular approach are Apple packages, and these tools build installation images using these packages.

If you are using Munki, you might consider making your images very “thin” and using Munki to bootstrap a machine’s configuration.

4.3.4 Details

The concept here is simple. Instead of a lengthy process of building an installation image from a great number of packages, you build a “thin” image that consists of the OS, perhaps an admin account, and the Munki tools. You restore the image to the target machine, and upon reboot, the Munki tools take over and complete the configuration of the machine by installing all the rest of the software your organization needs, including the majority of your configuration packages.

The “thin” image needs to have only enough to allow the target machine to boot and run the Munki tools; Munki installs everything else, including any needed Apple Software Updates.

To cause Munki to check for updates and install at startup, make sure the file /Users/Shared/.com.googlecode.munki.checkandinstallatstartup exists. You can create a package that installs that file and make it part of your thin image, or you can have a script touch that file.

A package that installs the required file is available here: https://github.com/munki/contrib/blob/master/munki_kickstart.pkg?raw=true

When /Users/Shared/.com.googlecode.munki.checkandinstallatstartup exists, Munki will check for and install updates. If a reboot is required after installing updates, after the reboot, Munki will check and install again, continuing until there are no updates to be installed. This allows you to bootstrap the configuration of a machine, including installing Apple Software Updates, with no user intervention.

Pros - Some advantages of this approach:

  1. Less duplication of effort. You don’t need to add packages to both Munki and a modular disk image workflow.
  2. More packages work. There are a non-insignificant number of packages that fail to install correctly in a modular imaging workflow because scripts within these packages make invalid assumptions. Munki installs packages to the current startup disk, which is more likely to result in success with these problematic packages.
  3. Can be used with a “no imaging” approach. Taking the “thin imaging” concept one step further, you may be able to deploy machines without imaging at all. This begins with taking a new Mac out of the box, using the image installed on it at the factory. You install the Munki tools only, and allow Munki to reconfigure the machine to your standard. This approach allows you to rapidly deploy new hardware releases from Apple without needed to take the time and resources to build a new deployment image.

Cons - Some disadvantages of this approach:

  1. Slower. Configuring a machine this way is much slower than block-copying a “pre-compiled” modular image built with AutoDMG, SIU or similar tools.
  2. Integration with other tools - it can be tricky at times to get integration correct. For example, DeployStudio now does some post-imaging tasks on the first reboot after installing an image. If Munki was set to run on the first reboot as well, the DeployStudio scripts could reboot the machine in the middle of a Munki run. The solution in this case is to make the creation of the /Users/Shared/.com.googlecode.munki.checkandinstallatstartup file one of the tasks DeployStudio performs after the first reboot. When DeployStudio reboots the machine again, Munki will run on the second reboot.

4.3.5 Munki 3.1 changes

Munki 3.1 contains changes to improve the bootstrapping experience on machines encrypted with FileVault 2.

managedsoftwareupdate has two new options: --set-bootstrap-mode and --clear-bootstrap-mode.

managedsoftwareupdate --set-bootstrap-mode creates the needed /Users/Shared/.com.googlecode.munki.checkandinstallatstartup file, and also turns off FileVault auto login (this is the automatic login to the account of the user who unlocks the FV2-encrpyted disk at boot), by setting the com.apple.loginwindow DisableFDEAutoLogin preference to True. (See https://support.apple.com/en-us/HT202842)

managedsoftwareupdate --clear-bootstrap-mode removes the /Users/Shared/.com.googlecode.munki.checkandinstallatstartup file and resets the com.apple.loginwindow DisableFDEAutoLogin preference to its previous value.

When performing a macOS upgrade (using an Install macOS.app/startosinstall), Munki uses these new mechanisms in order to effectively re-bootstrap after an OS upgrade.

Previously, on a FileVault 2-encrypted machine, after the upgrade was complete, the user would need to unlock the startup disk in order to boot into the newly-upgraded OS. After unlocking the startup disk with the user’s login password, the OS would normally continue logging into the user’s account, bypassing the loginwindow. This resulted in the re-bootstrapping (Munki running to check for and install all needed updates for the new OS) not happening properly. With the changes in Munki 3.1, the automatic account login is temporarily suppressed, allowing Munki the opportunity to run over the loginwindow after the macOS upgrade is complete.

You probably won’t need to use/care about these changes when bootstrapping a brand-new machine, since it most likely will not have FileVault 2 turned on, but if for some reason you do, you can use managedsoftwareupdate --set-bootstrap-mode to set up bootstrapping mode.

4.3.6 Building a Munki Installer Package

Milestone releases of the Munki tools are made available here: https://github.com/munki/munki/releases

Automated builds of the Munki installer packages are available at https://munkibuilds.org. These are not official builds, but are made available by a friendly third party.

4.3.7 Building it yourself

You can also build a Munki installer package yourself.

4.3.7.1 Requirements

Xcode – recent versions of Munki can be built using Xcode 7 or Xcode 8.
git (which you get for “free” when you install Xcode…)

4.3.7.2 Procedure

In a directory you can write to, run:

git clone https://github.com/munki/munki
This will create a new “munki” directory containing the latest git repo. Change into the directory:

cd munki

Run the build script:

./code/tools/make_munki_mpkg.sh

Provide your password when requested (certain steps require sudo).

If the script runs successfully, it will tell you where to find the Installer package:

Distribution package created at /Users/Shared/munki-git/munki/munkitools-3.0.0.3333.pkg.

4.3.7.3 Building other versions of Munki

You can also build other versions of Munki using the make_munki_mpkg_from_git.sh script.

./code/tools/make_munki_mpkg_from_git.sh -b Munki2 will build the latest (now final) Munki 2 package.

./code/tools/make_munki_mpkg_from_git.sh -b Munki1 will build the latest (now final) Munki 1 package. You may need an older version of Xcode to successfully build the applications, or access to older OS X SDKs. Almost certainly this is not worth the effort and you should stick with a pre-built package.

./code/tools/make_munki_mpkg_from_git.sh -b BRANCHNAME will build Munki based on the code in BRANCHNAME.

./code/tools/make_munki_mpkg_from_git.sh -r GIT_REVISION_HASH will build Munki based on the code in a particular Git commit (revision).
Notes on building Munki packages

4.3.8 Introduction

Note: These docs are for building the Munki (1) tools. For Munki 2, see [[Building Munki2 Pkgs]].

Munki releases are made available via Apple packages here:
https://github.com/munki/munki/releases

These packages are built and released only for major development milestones. If you want to be on the cutting edge, or want to test a new feature before the official release, you may need to build your Munki tools from source.

4.3.9 Details

4.3.9.1 Requirements

A Leopard or Snow Leopard machine. See the next requirement.

Xcode 3<br>
Currently, to successfully build the Munki tools from source, you must be using Xcode 3.x on Leopard or Snow Leopard. Building on Lion is not currently supported because there is no way to build “universal” applications that run on PowerPC and Intel under Xcode 4. If you don’t care about PowerPC compatibility, it is possible to use Xcode 4 on Lion, but this document does not describe that yet.

Git<br>
While not absolutely, strictly necessary to build the Munki tools, in order to follow this document you must also install Git. Git is a distributed revision control system. It is not installed by default on Leopard or Snow Leopard. You can find installation packages here: http://git-scm.com/download/mac

4.3.9.2 Building Munki

So now a bit of the chicken-and-the-egg problem. You need the Munki build script available here:

https://munki.googlecode.com/git/code/tools/make_munki_mpkg_from_git.sh

You can quickly download and execute it like so:

curl https://munki.googlecode.com/git/code/tools/make_munki_mpkg_from_git.sh | bash

This uses curl to download the latest make_munki_mpkg_from_git.sh script, and pipes it to the bash shell, which executes it.

When it’s done, in the current directory, you’ll have a Git clone of the current Munki code (munki-git) and a metapackage of the tools.

4.3.9.3 That’s still too much work!

Timothy Sutton has set up an autobuild server for Munki, available here:

http://munkibuilds.org

This machine automatically builds and makes available the the most recent Git commits. If you want to test a Git revision and don’t want to/can’t build it yourself, you can take advantage of these automatic builds.

4.3.10 Introduction

Building a Munki 2 Installer Package

Milestone releases of the Munki tools are made available here: https://github.com/munki/munki/releases

Automated builds of the Munki 2 installer packages are available at https://munkibuilds.org. These are not official builds, but are made available by a friendly third party.

4.3.11 Building it yourself

You can also build a Munki installer package yourself.

4.3.11.1 Requirements

  • Xcode 7, which requires either Yosemite or El Capitan depending on the version.
  • git (which you get for “free” when you install Xcode…)

4.3.11.2 Procedure

In a directory you can write to, run:

git clone https://github.com/munki/munki

This will create a new “munki” directory containing the latest git repo. Change into the directory:

cd munki

Run the build script:

./code/tools/make_munki_mpkg.sh

Provide your password when requested (certain steps require sudo).

If the script runs successfully, it will tell you where to find the Installer package:

Distribution package created at /Users/Shared/munki/munkitools-2.8.1.2835.pkg.

4.3.12 Introduction

Munki supports embedding metapackage ChoiceChangesXML information into a pkginfo item to customize the installation of a metapackage.

4.3.13 Details

It’s possible to customize metapackage installs with Apple’s installer using a “ChoiceChangesXML” file.
This is a snippet of plist-compatible XML that modifies package selection choices when installing a metapackage. See man installer for more information. The installer that ships with Mac OS X 10.6.6 or later contains more and better information than earlier versions on ChoiceChangesXML files.

Munki supports embedding ChoiceChangesXML information into a pkginfo item to customize the installation of a metapackage.

Previously, generating a working ChoiceChangesXML was difficult. With 10.6.6 or later’s /usr/sbin/installer, you can generate a template ChoiceChangesXML file like so:

installer -showChoiceChangesXML -pkg /path/to/pkg -target /

Let’s use the munki tools metapackage as an example:

installer -showChoiceChangesXML -pkg munkitools-0.7.1.1173.0.mpkg -target /
<?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">
<array>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>visible</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>enabled</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>visible</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>enabled</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>visible</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>enabled</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>visible</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <true/>
        <key>choiceAttribute</key>
        <string>enabled</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
</array>
</plist>

There are four subpackage choices and three choiceAttributes (“visible”, “enabled”, and “selected”) for each choice, for a total of twelve dictionaries inside the array. Changing the “visible” and “enabled” attributes only affects their display in Installer.app; to control what is installed, we need to control the “selected” choiceAttributes. We can delete the other choiceAttributes, and are left with:

<array>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
</array>

Note that I’ve also removed the plist “wrapper” from around the array. We are going to later add this array to a pkginfo file and we don’t want the plist wrapper.

If we don’t want to install the munki admin tools (Currently: makecatalogs, makepkginfo, and munkiimport) we’d change the attributeSetting to 0 for choiceAttribute “selected” for choiceIdentifier “admin”:

<array>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>0</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
</array>

We can then add this plist/XML snippet to a pkginfo item. The key is “installer_choices_xml”:

<key>installer_choices_xml</key>
<array>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>core</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>0</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>admin</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>app</string>
    </dict>
    <dict>
        <key>attributeSetting</key>
        <integer>1</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>launchd</string>
    </dict>
</array>

When installing, munki will pass this ChoiceChangesXML to /usr/sbin/installer to customize the installation of the munkitools metapackage. You can use this same technique to customize the installation of most metapackages.

If you change what is installed via this technique, the “receipts” array generated by makepkginfo/munkiimport is likely to contain receipts for components that aren’t (now) installed. This can cause Munki to offer the item repeatedly for installation, since the items its looking for to verify installed state are not present. You may need to add an installs array, or edit the receipts array (possibly marking some receipts as optional). See [[How Munki Decides What Needs To Be Installed]] for even more information on this topic.

4.3.13.1 Pre-10.6.6

ChoiceChangesXML generated by 10.6.6 or later’s /usr/sbin/installer are usable with the installer in earlier versions of Mac OS X, at least back through 10.5, which is the earliest version of the OS on which Munki will run. My recommendation is to save yourself the pain of manually creating ChoiceChangesXML and let /usr/sbin/installer in 10.6.6 or later assist you.

4.3.14 Introduction

Managed Software Center can be customized for your organization. Further, you can customize it per site, workgroup, or even user. Customization requires some familiarity with basic web development tools and techniques.

4.3.15 Details

Most of what Managed Software Center displays is within a WebKit WebView. The views are generated dynamically, combining HTML templates with live data and static resources (images, CSS, JavaScript).

The default templates are in Managed Software Center.app/Contents/Resources/templates/ and the static assets are in Managed Software Center.app/Contents/Resources/WebResources/

One approach to customization would be to replace some of these files and (optionally) add additional files to these directories. You’d have to be certain to re-do your modifications each time Managed Software Center.app was updated, so that might be a tedious method of customization.

Instead, you can create one or more zip archives of your desired customization files and make them available at a URL, typically in your Munki repo. managedsoftwareupdate will attempt to download any client customization resources when it runs; Managed Software Center.app will use any custom resources downloaded by managedsoftwareupdate.

4.3.15.1 Customization overview

While you can customize anything in Managed Software Center.app/Contents/Resources/templates/, the most common customizations (and the only ones officially supported) are for these template files:

  • showcase_template.html – controls the banner images and any links
  • sidebar_template.html – the right-side sidebar displayed in the main Software view
  • footer_template.html – the page footer

While it is possible to customize any of the other template files, it’s possible (or even likely) that a future release of Managed Software Center.app will include changes to the default/included versions of these template files. This could lead to unexpected/undesired behavior if you did not also update your versions of the customized files. Therefore, when you make your archive of customized files, include ONLY those files you actually customize. Do not include any other template files.

4.3.15.2 Showcase banner images requirements

When customizing the showcase_template.html, you will typically want to provide your own banner images.

Banner images may be any format that WebKit can display natively; png might be a good choice.
Images should be 1158x200 (or at least look good when resized to that resolution). Since the main window can be resized, you should test the images to make sure they don’t hide any important information when the window is sized smaller than 1158 pixels wide. (The window can be as small as 1000px wide, so the displayed part of the image will be even smaller than that: it’s approximately 960px wide on Mavericks, but exact measurements might vary on different OS versions.)

If you provide custom banner images, even if they share the same names as the stock/default images, you must also provide a customized showcase_template.html to refer to the custom images, which will be at a different path from the stock images.

4.3.15.3 showcase_template.html example

Here’s an example of a customized showcase_template.html. Note that this is a copy of the file at Managed Software Center.app/Contents/Resources/templates/showcase_template.html. The JavaScript at the beginning of the file is left unchanged (though you could change it if you wanted different behaviors). In this example, we are only customizing the actual images shown and what they link to.

<script type="text/javascript">
var currentSlide = 0, playing = 1

function slides(){
    return document.querySelectorAll('div.stage>img')
}

function showSlide(slideNumber){
    theSlides = slides()
    for (c=0; c<theSlides.length; c++) {
        theSlides[c].style.opacity="0";
    }
    theSlides[slideNumber].style.opacity="1";
}

function showNextSlide(){
    if (playing) {
        currentSlide = (currentSlide > slides().length-2) ? 0 : currentSlide + 1;
        showSlide(currentSlide);
    }
}

function stageClicked() {
    slide = slides()[currentSlide];
    target = slide.getAttribute('target');
    if (target == '_blank') {
        window.AppController.openExternalLink_(slide.getAttribute('href'));
    } else {
        window.location.href = slide.getAttribute('href');
    }
}

window.onload=function(){
    showSlide(0);
    if (slides().length > 1) {
        setInterval(showNextSlide, 7500);
    }
}
</script>

<div class="showcase">
    <div class="stage" onClick='stageClicked();'>
        <img target="_blank" href="http://www.apple.com" alt="Apple" src="custom/resources/Apple.png" />
        <img href="detail-GoogleChrome.html"  alt="Google Chrome" src="custom/resources/Chrome.png" />
        <img href="developer-Google.html" alt="Google Applications" src="custom/resources/Google.png" />
    </div>
</div>

We have three images, "custom/resources/Apple.png", "custom/resources/Chrome.png", and "custom/resources/Google.png". These will be in our archive of custom files. You could, if you wished, link to a full (external) http URL for these images, but Managed Software Center.app would display broken image link placeholders if it can’t reach those URLs (for example, if the images are hosted on an internal web server not available when a user is at home or out of the office).

There are two optional attributes that can be added to each img element: target and href. href is a link – it can point to any full or relative URL. if target="_blank", the URL will be forwarded to the user’s default browser; otherwise Managed Software Center.app will attempt to display the contents of the URL.

Notice the special links for the second and third images. These are URLs internal to Managed Software Center.app to cause it to display specific content. "detail-GoogleChrome.html" links to the detail view for GoogleChrome; "developer-Google.html" shows all items whose developer is “Google”. More documentation on these internal links will be available in the future.

Here’s an example of a customized sidebar_template.html showing some of the possibilities:

<div class="sidebar">
    <div class="chart titled-box quick-links">
        <h2>Quick Links</h2>
        <div class="content">
            <ol class="list">
                <li class="link user-link"><a href="#">Welcome</a></li>
                <li class="link user-link"><a href="#">Support</a></li>
                <li class="separator"><hr/></li>
                <li class="popup">
                    <div class="select links">
                        <label>
                            <span></span>
                            <select id="category-selector" onchange="category_select()">
                                ${category_items}
                            </select>
                        </label>
                    </div>
                </li>
                <li class="link"><a href="http://www.apple.com/osx/whats-new/">What's new in Mavericks</a></li>
                <li class="link"><a target="_blank" href="http://www.apple.com">Apple</a></li>
                <li class="link"><a target="_blank" href="http://google.com">Search Google</a></li>
                <li class="link"><a target="_blank" href="http://bing.com">Search Bing</a></li>
                <li class="separator"><hr/></li>
                <li class="link"><a target="_blank" href="http://www.apple.com/support/">Apple support</a></li>
                <li class="link"><a target="_blank" href="http://www.apple.com/support/mac/">Mac</a></li>
                <li class="link"><a target="_blank" href="http://www.apple.com/support/osx/">OS X</a></li>
                <li class="link"><a target="_blank" href="http://www.apple.com/support/mac-apps/">Mac Apps</a></li>
            </ol>
        </div>
    </div>
</div>

The customized sidebar would look like this:

Finally, an example of a customized footer_template.html:

<div class="bottom-links">
    <ul class="list" role="presentation">
        <li><a target="_blank" href="http://www.apple.com">Apple</a></li>
        <li><a target="_blank" href="http://www.google.com">Google</a></li>
        <li><a href="updates.html">Updates</a></li>
    </ul>
</div>

4.3.16 Creating the client customization archive

The archive of client customization files has a specific format.
Create two directories: “templates” and “resources”. Place all your customized template files in “templates”; custom images, css and JavaScript (or anything else referred to in your customized templates) should go in “resources”.

I recommend that you use the command-line zip tool to create the actual archive. Using the Finder’s Compress “foo” contextual menu will not create archives with the expected layout.

Assuming you are in the directory containing your templates and resources directories:

zip -r site_default.zip resources/ templates/

-r tells zip to add the resources and templates directories recursively to the archive named site_default.zip (without the ‘-r’ flag, you’ll get only empty directories in the archive!).

To verify the contents of an archive you’ve created, use

unzip -l site_default.zip

You’ll see a listing of the archive contents. It should look similar to this:

Archive:  /Library/Managed Installs/client_resources/custom.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  04-28-16 12:53   resources/
   104982  03-10-16 13:27   resources/branding.png
   232535  09-22-14 14:29   resources/branding1.png
    61665  09-26-14 08:57   resources/branding2.png
        0  07-24-14 12:48   templates/
      281  09-22-14 15:51   templates/footer_template.html
     1580  04-28-16 13:02   templates/showcase_template.html
     1628  03-09-16 14:00   templates/sidebar_template.html

A sample archive is here: https://github.com/munki/contrib/raw/master/site_default.zip

4.3.17 Making client customization archives available to clients

managedsoftwareupdate as part of its update check, attempts to download client customization resources. Typically, you can make these available from your Munki repo by creating a “client_resources” directory at the top level of the repo. If you want to make these available at a different URL, you can set Munki’s ClientResourceURL to an alternate base URL. (This follows the pattern of ManifestURL, CatalogURL and PackageURL as alternate base URLs.)

If Munki’s ClientResourcesFilename preference is defined, this filename will be used (appending “.zip”) if needed; otherwise managedsoftwareupdate will request an archive with the same name as the primary manifest (plus “.zip”), falling back to “site_default.zip”.

Requests will be of the form “http://munki/repo/client_resources/site_default.zip”. If no client customization resources are found, the default resources within Managed Software Update.app will be used.

4.3.18 Behind the scenes

Client customization resources are downloaded to Munki’s data directory; typically /Library/Managed Installs, in a client_resources subdirectory, with the filename custom.zip – no matter the name of the remote file at the URL.

On launch, Managed Software Center.app checks for the existence of this file. If it exists, it’s checked to see if it has the expected layout (top-level “resources” and “templates” directories), and if so, these directories are expanded into ~/Library/Caches/com.googlecode.munki.ManagedSoftwareCenter/html, which is where Managed Software Center.app finds all of its HTML/CSS/JavaScript, etc resources.

You can open these same files (the ones in ~/Library/Caches/com.googlecode.munki.ManagedSoftwareCenter/html) in Safari (and use Safari’s web inspector, etc) to debug if things aren’t behaving as you’d expect.

5 Introduction

There are many different ways that Munki can be used. Let’s outline a few of these setups.

5.1 Apple Updates Only

If you do not want to setup the infrastructure for a full blown Munki setup, you can have Munki install only Apple Software Updates. This is helpful because this allows users without administrative rights the ability to install Apple updates. See [[Apple Software Updates With Munki]] for details.

5.2 Integrate with Existing Environment

If you currently use a monolithic or modular image to build your machines, you can use Munki to update the software on machines after they’ve been deployed. This requires a Munki repository plus installing and configuring the Munki tools on each client machine. This method can be put into place on top of any environment that isn’t currently managed by any other means. An example of this workflow would be as follows:

New or Reimaged Machines

  • Apply Image
  • Munki Pushes updates to machines as you add them

Existing Machines

  • Install and configure Munki
  • Munki ensures software is up to date

5.2.1 Benefits

  • After Imaging, machines are fully updated by munki
  • Less work up front

5.2.2 Drawbacks

  • Packages are managed in multiple places
  • Duplication of effort with multiple images
  • Not as agile when new machines are released
  • More prone to human error

5.3 Thin Imaging

Thin imaging is when you take a minimal base image (For example, 10.7 with only Apple Software Updates applied) or no image at all (Install software on top of new machines as they come from Apple). This method uses the functionality found here: [[Bootstrapping With Munki]]

Example Workflow:

New Machine

  • Apply Munki Client + Configuration
  • Boot Machine and Munki installs software

Reimage Machine

  • Apply Base Image
  • Apply Munki Client + Configuration
  • Boot Machine and Munki installs software

Existing Machines

  • Install Munki Client + Configuration
  • Munki ensures software is up to date

5.3.1 Benefits

  • Packages are managed in only one place
  • After “Imaging,” machines are fully updated
  • Extremely agile when new machines are released
  • Reusable for future configurations
  • Little work duplication

5.3.2 Drawbacks

  • Takes slightly longer to complete
  • More work up front

    5.3.2 Introduction

This mechanism allows Munki to conditionally install or remove items based on certain conditions.

5.3.3 Details

Manifests may contain a “conditional_items” array.

conditional_items contains an array of dictionaries. Each dictionary contains a “condition” key, whose value is an NSPredicate-style string. Additional keys and values are the same as for the “main” part of a manifest: included_manifests, managed_installs, managed_uninstalls, managed_updates, and optional_installs (and also conditional_items !).

<key>conditional_items</key>
<array>
    <dict>
        <key>condition</key>
        <string>machine_type == "laptop" AND os_vers BEGINSWITH "10.7"</string>
        <key>managed_installs</key>
        <array>
            <string>LionVPNprofile</string>
        </array>
        <key>managed_uninstalls</key>
        <array>
            <string>CiscoVPNclient</string>
        </array>
    </dict>
    <dict>
        <key>condition</key>
        <string>machine_type == "laptop" AND os_vers BEGINSWITH "10.6"</string>
        <key>managed_installs</key>
        <array>
            <string>CiscoVPNclient</string>
        </array>
    </dict>
</array>

The above conditional_items section will cause the CiscoVPNclient to be installed on laptops running Snow Leopard. If such a laptop is later upgraded to Lion, the CiscoVPNclient will be removed and a Lion profile that configures VPN will be installed.

Example #2:

 <key>conditional_items</key>
  <array>
    <dict>
      <key>condition</key>
      <string>date &gt; CAST("2016-03-02T00:00:00Z", "NSDate")</string>
      <key>managed_installs</key>
      <array>
        <string>AdobePhotoshopCC2015</string>
      </array>
      <key>managed_uninstalls</key>
      <array>
        <string>AdobePhotoshopCS6</string>
      </array>
    </dict>
  </array>

This would cause Photoshop CS6 to be removed, and Photoshop CC 2015 to be installed starting at midnight local time on 02 March 2016.

5.3.3.1 Built-in Conditions

Currently available built-in attributes for conditional comparison:

Attribute Type Description Example Comparison
hostname string Hostname hostname == “LobbyiMac”
arch string Processor architecture. e.g. ‘powerpc’, ‘i386’, ‘x86_64’. arch == “x86_64”
os_vers string Full OS Version e.g. “10.7.2” os_vers BEGINSWITH “10.7”
os_vers_major integer Major OS Version e.g. ‘10’ os_vers_major == 10
os_vers_minor integer Minor OS Version e.g. ‘7’ os_vers_minor == 7
os_vers_patch integer Point release version e.g. ‘2’ os_vers_patch >= 2
machine_model string ‘Macmini1,1’, ‘iMac4,1’, ‘MacBookPro8,2’ machine_model == “iMac4,1”
machine_type string ‘laptop’ or ‘desktop’ machine_type == “laptop”
catalogs array of strings This contains the current catalog list for the manifest being processed. catalogs CONTAINS “testing”
ipv4_address array of strings This contains current IPv4 addresses for all interfaces. ANY ipv4_address CONTAINS ‘192.168.161.’
munki_version string Full version of the installed munkitools munki_version LIKE ‘*0.8.3*
serial_number string Machine serial number serial_number == “W9999999U2P”
date UTC date string Date and time. Note the special syntax required to cast a string into an NSDate object. date > CAST(“2013-01-02T00:00:00Z”, “NSDate”)
5.3.3.1.1 Notes

Dates in conditions: The date string must be written in UTC format, but is interpreted as a local date/time.
The condition date > CAST("2013-01-02T00:00:00Z", "NSDate") is True if the local time is after midnight local time on 02 Jan 2013.

Comparisons are implemented via Cocoa’s NSPredicate objects.
Predicate syntax documented here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html

Important: since pkginfo files are XML, you must escape the characters & and < to &amp; and &lt; if you are hand-editing the predicates. (You may also escape > as &gt; but it is not necessary.)

5.3.3.2 Literal types in comparisions

  • Strings are delimited by either single or double-quotes: os_vers BEGINSWITH "10.7"

  • Integers have no quotes: os_vers_major == 10

  • Booleans are indicated as TRUE or FALSE (and have no quotes, or they’d be strings!): some_custom_condition == TRUE

  • Dates are possible, but you need to cast them from ISO 8601 strings: date > CAST("2013-01-02T00:00:00Z", "NSDate")

5.3.3.3 Admin Provided Conditions

Administrators may create their own custom conditions (key/value pairs) by way of authoring condition scripts. Condition scripts should be placed in /usr/local/munki/conditions and can be written in any language of your choosing (shell, python, perl, ruby, etc.) and are evaluated each time managedsoftwareupdate is executed (command-line or GUI).

5.3.3.3.1 Requirements

To be able to provide a stable framework for admin provided conditions, the following guidelines should be followed:

  • Permissions for the conditions directory and its scripts should follow the same standards as preflight/postflight scripts (i.e. same permissions as /usr/local/munki/managedsoftwareupdate).
  • Each condition script must output to ConditionalItems.plist in the Managed Install directory, which is /Library/Managed Installs by default. Note that no one script should be permitted to completely overwrite this plist as any conditions gathered by previously run script(s) would be lost.
  • Each “write” to ConditionalItems.plist must contain a key/value pair. A value may also be an ‘array’ of values, similar to the built-in conditions ‘ipv4_address’ or ‘catalogs’.
  • Items in /usr/local/munki/conditions that begin with a period or are directories will be ignored.
5.3.3.3.2 Notes and Considerations (will be updated as seen necessary)

Authoring condition scripts is a great way to extend your munki administrative capabilities in your environment. There are however a few items to consider:

  • A condition script’s key/value output will overwrite another’s previous output if the keys are the same. This applies to both built-in conditions and admin provided conditions. Example: “machine_type” is a built-in key, but a condition script has been instructed to use the same key but with a potentially different value or array of values.
  • There’s more than one way to write out to ConditionalItems.plist, please see the examples for a jumping-off point
  • A condition script may output more than one key/value pair. Perhaps you’d like to collate all of your custom conditions into one script or keep each condition organized in its own separate script - the choice is yours.
  • Build in an “exit strategy” so that your condition script doesn’t hang indefinitely or stall for a lengthy period of time. Since scripts are executed on each managedsoftwareupdate run, the potential exists to bog down overall execution. Those familiar with preflight/postflight script usage should understand this.
  • If you’re troubleshooting and looking for ConditionalItems.plist after a managedsoftwareupdate run, you won’t find it. Look for the ‘Conditions’ dictionary in /Library/Managed Installs/ManagedInstallReport.plist for a full list of any conditions your scripts generated.

5.3.3.4 Examples (condition scripts)

This first example (albeit not terribly useful), creates a key/value pair of active hardware ports. Note that outputted key “hardware_ports” contains an array of values. Also note that since we’re using the defaults command, we must ensure that the ConditionalItems.plist is converted to xml and does NOT remain in binary format.

#!/bin/sh
# This is an example of a bash conditional script which outputs a key with an array of values
# Please note how the array is created and used within the defaults statement for proper output
    
# Read the location of the ManagedInstallDir from ManagedInstall.plist
managedinstalldir="$(defaults read /Library/Preferences/ManagedInstalls ManagedInstallDir)"
# Make sure we're outputting our information to "ConditionalItems.plist" 
# (plist is left off since defaults requires this)
plist_loc="$managedinstalldir/ConditionalItems"
    
IFS=$'\n' # Set our field separator to newline since each unique item is on its own line
for hardware_port in `networksetup -listallhardwareports | awk -F ": " '/Hardware Port/{print $2}'`; do
    # build array of values from output of above command
    hardware_ports+=( $hardware_port )
done
    
# Note the key "hardware_ports" which becomes the condition that you would use in a predicate statement
defaults write "$plist_loc" "hardware_ports" -array "${hardware_ports[@]}"
    
# CRITICAL! Since 'defaults' outputs a binary plist, we need to ensure that munki can read it by 
# converting it to xml
plutil -convert xml1 "$plist_loc".plist
    
exit 0

This second example, while similar to the built-in ‘ipv4_address’, generates two key/value pairs; the first is the name of the primary network interface, and the second is its IP address. Note that they’re represented by keys “primary_interface_name” and “primary_ip_address”. Additionally, we’re ensuring that we read the ConditionalItems.plist and adding our additional key/value pairs prior to writing the plist back out. Python’s ‘plistlib’ will completely overwrite an existing plist if this is not performed.

#!/usr/bin/python
'''This is a basic example of a conditional script which outputs 2 key/value pairs:
Examples:
primary_interface_name: en0
primary_ip_address: 192.168.1.128
    
NOTE: Information gathered is ONLY for the primary interface'''
    
from SystemConfiguration import *    # from pyObjC
import collections
import os
import plistlib
    
from Foundation import CFPreferencesCopyAppValue
    
# Read the location of the ManagedInstallDir from ManagedInstall.plist
BUNDLE_ID = 'ManagedInstalls'
pref_name = 'ManagedInstallDir'
managedinstalldir = CFPreferencesCopyAppValue(pref_name, BUNDLE_ID)
# Make sure we're outputting our information to "ConditionalItems.plist"
conditionalitemspath = os.path.join(managedinstalldir, 'ConditionalItems.plist')
    
NETWORK_INFO = {}
def getIPAddress(service_uuid):
    ds = SCDynamicStoreCreate(None, 'GetIPv4Addresses', None, None)
    newpattern = SCDynamicStoreKeyCreateNetworkServiceEntity(None,
                                                             kSCDynamicStoreDomainState,
                                                             service_uuid,
                                                             kSCEntNetIPv4)
    
    newpatterns = CFArrayCreate(None, (newpattern, ), 1, kCFTypeArrayCallBacks)
    ipaddressDict = SCDynamicStoreCopyMultiple(ds, None, newpatterns)
    for ipaddress in ipaddressDict.values():
        ipv4address = ipaddress['Addresses'][0]
        return ipv4address
    
    
def getNetworkInfo():
    ds = SCDynamicStoreCreate(None, 'GetIPv4Addresses', None, None)
    
    pattern = SCDynamicStoreKeyCreateNetworkGlobalEntity(None,
                                                         kSCDynamicStoreDomainState,
                                                         kSCEntNetIPv4)
    patterns = CFArrayCreate(None, (pattern, ), 1, kCFTypeArrayCallBacks)
    valueDict = SCDynamicStoreCopyMultiple(ds, None, patterns)

    ipv4info = collections.namedtuple('ipv4info', 'ifname ip router service')
        
    for serviceDict in valueDict.values():
        ifname = serviceDict[u'PrimaryInterface']
        NETWORK_INFO['interface'] = serviceDict[u'PrimaryInterface']
        NETWORK_INFO['service_uuid'] = serviceDict[u'PrimaryService']
        NETWORK_INFO['router'] = serviceDict[u'Router']
        NETWORK_INFO['ip_address'] = getIPAddress(serviceDict[u'PrimaryService'])
    
        netinfo_dict = dict(
            primary_interface_name = ifname,
            primary_ip_address = NETWORK_INFO['ip_address'],
        )
    
        # CRITICAL!
        if os.path.exists(conditionalitemspath):
            # "ConditionalItems.plist" exists, so read it FIRST (existing_dict)
            existing_dict = plistlib.readPlist(conditionalitemspath)
            # Create output_dict which joins new data generated in this script with existing data
            output_dict = dict(existing_dict.items() + netinfo_dict.items())
        else:
            # "ConditionalItems.plist" does not exist,
            # output only consists of data generated in this script
            output_dict = netinfo_dict
    
        # Write out data to "ConditionalItems.plist"
        plistlib.writePlist(output_dict, conditionalitemspath)
    
getNetworkInfo()

This last example, shows a custom condition used as a “conditional_item” within a manifest. It specifically demonstrates that if any of the active hardware ports contain the string “Wi-Fi”, the ‘managed_install’ package, “TestPackage”, will be considered for deployment.

<key>conditional_items</key>
<array>
    <dict>
        <key>condition</key>
        <string>ANY hardware_ports CONTAINS 'Wi-Fi'</string>
        <key>managed_installs</key>
        <array>
            <string>TestPackage</string>
        </array>
    </dict>
</array>

5.3.4 Nested conditional_items

If you’d like to achieve a higher degree of granularity, you may also nest conditional_items:

<key>conditional_items</key>
<array>
    <dict>
        <key>condition</key>
        <string>machine_type == "laptop"</string>
        <key>conditional_items</key>
        <array>
            <dict>
                <key>condition</key>
                <string>os_vers BEGINSWITH "10.7"</string>
                <key>managed_installs</key>
                <array>
                    <string>LionVPNProfile</string>
                </array>
            </dict>
            <dict>
                <key>condition</key>
                <string>os_vers BEGINSWITH "10.6"</string>
                <key>managed_installs</key>
                <array>
                    <string>CiscoVPNClient</string>
                </array>
            </dict>
        </array>
    </dict>
</array>

which is functionally the same as:

<key>conditional_items</key>
<array>
    <dict>
        <key>condition</key>
        <string>machine_type == "laptop" AND os_vers BEGINSWITH "10.7"</string>
        <key>managed_installs</key>
        <array>
            <string>LionVPNProfile</string>
        </array>
    </dict>
    <dict>
        <key>condition</key>
        <string>machine_type == "laptop" AND os_vers BEGINSWITH "10.6"</string>
        <key>managed_installs</key>
        <array>
            <string>CiscoVPNClient</string>
        </array>
    </dict>
</array>

But either style is fine, and either might be easier to maintain/understand in different circumstances.
The Munki project welcomes contributions!

5.3.5 Contributor License Agreement

All contributors must complete and sign a Contributor License Agreement. A copy can be found here.

5.3.5.1 GitHub ID

The CLA does not explicitly ask for this, but when you send in your signed CLA, please mention your GitHub ID to make it easier to map between real/legal names required by the CLA and GitHub names.

5.3.6 Preferred contribution methods

5.3.6.1 Bug fixes

Bug fixes should be submitted as Pull Requests.

5.3.6.2 Enhancements/New features

Before starting work on a new feature or enhancement, consider bringing your idea up for discussion on the munki-dev mailing list. This might save you a lot of wasted effort. Once you have code for a new feature complete, push it to your own GitHub clone. You can then ask others to test it first, or proceed directly to creating a Pull Request.

Learn more about cloning a GitHub repository here.
Learn more about GitHub pull requests here.

5.3.7 Introduction

The copy_from_dmg installer type is typically used for “drag-n-drop” disk images; where the vendor has supplied their software on a disk image and expects the user to drag the software from the mounted disk image to some place on the the startup disk (typically, but not always, /Applications/).

copy_from_dmg supports copying arbitrary items from a disk image to arbitrary locations on the startup disk. You can also specify owner, group, and mode for the copied items.

5.3.8 Details

The munkiimport tool will automatically generate a pkginfo file using copy_from_dmg if the item to be imported is a disk image that contains an application at the root of the mounted filesystem.

You can manually create a pkginfo file using the copy_from_dmg method. Use makepkginfo to create a pkginfo item like so:

makepkginfo /Volumes/repo/pkgs/apps/GoogleEarthMacNoUpdate-Intel-5.2.dmg --owner=root --group=admin --mode=go-w --item="Google Earth Web Plug-in.plugin" --destinationpath="/Library/Internet Plug-ins"

This creates a pkginfo item instructing Munki to copy “Google Earth Web Plug-in.plugin” from the root of the mounted disk image to “/Library/Internet Plug-ins”; to set its owner to “root,” group to “admin,” and to remove the write bit for “other”. The resulting plist looks like this:

<?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>installer_item_location</key>
    <string>apps/GoogleEarthMacNoUpdate-Intel-5.2.dmg</string>
    <key>installer_item_size</key>
    <integer>23168</integer>
    <key>installer_type</key>
    <string>copy_from_dmg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleShortVersionString</key>
            <string>5.2</string>
            <key>path</key>
            <string>/Library/Internet Plug-ins/Google Earth Web Plug-in.plugin</string>
            <key>type</key>
            <string>bundle</string>
        </dict>
    </array>
    <key>items_to_copy</key>
    <array>
        <dict>
            <key>destination_path</key>
            <string>/Library/Internet Plug-ins</string>
            <key>group</key>
            <string>admin</string>
            <key>mode</key>
            <string>go-w</string>
            <key>source_item</key>
            <string>Google Earth Web Plug-in.plugin</string>
            <key>user</key>
            <string>root</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>Google Earth Web Plug-in</string>
    <key>uninstall_method</key>
    <string>remove_copied_items</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>5.2.0.0.0</string>
</dict>
</plist>

The Google Earth disk image actually contains two items you might want to install – the Google Earth application itself, and the Google Earth Web Plug-in. You have two options here:

  1. Create two separate pkginfo items, one for Google Earth.app and one for Google Earth Web Plug-in.plugin. You could then add an “update_for” key to the Google Earth Web Plug-in item, marking it as an update for Google Earth. When munki is instructed to install Google Earth, it will install the Google Earth Web Plug-in as well.<br><br>
  2. Combine the “installs” and “items_to_copy” sections from the two pkginfo items into a single pkginfo item. makepkginfo currently only supports a single installation item when creating a copy_from_dmg pkginfo item, but the plist itself can support multiple items. Such a combined pkginfo item would look like this:
<?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>installer_item_location</key>
    <string>apps/GoogleEarthMacNoUpdate-Intel-5.2.dmg</string>
    <key>installer_item_size</key>
    <integer>23168</integer>
    <key>installer_type</key>
    <string>copy_from_dmg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.Google.GoogleEarthPlus</string>
            <key>CFBundleName</key>
            <string>Google Earth</string>
            <key>CFBundleShortVersionString</key>
            <string>5.2</string>
            <key>path</key>
            <string>/Applications/Google Earth.app</string>
            <key>type</key>
            <string>application</string>
        </dict>
        <dict>
            <key>CFBundleShortVersionString</key>
            <string>5.2</string>
            <key>path</key>
            <string>/Library/Internet Plug-ins/Google Earth Web Plug-in.plugin</string>
            <key>type</key>
            <string>bundle</string>
        </dict>
    </array>
    <key>items_to_copy</key>
    <array>
        <dict>
            <key>destination_path</key>
            <string>/Applications</string>
            <key>source_item</key>
            <string>Google Earth.app</string>
        </dict>
        <dict>
            <key>destination_path</key>
            <string>/Library/Internet Plug-ins</string>
            <key>group</key>
            <string>admin</string>
            <key>mode</key>
            <string>go-w</string>
            <key>source_item</key>
            <string>Google Earth Web Plug-in.plugin</string>
            <key>user</key>
            <string>root</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>Google Earth</string>
    <key>uninstall_method</key>
    <string>remove_copied_items</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>5.2.0.0.0</string>
</dict>
</plist>

5.3.9 Introduction

munki requires all bundle-style packages to be encapsulated in a disk image. This has the effect of converting a bundle-style package, which is actually a special type of folder containing additional folders and files, into a single compressed file. This makes uploading and downloading such a package from a web server much more convenient and compatible with a wider range of web servers. This document explains how to “wrap” a bundle-style package into a disk image.

5.3.10 Summary

munkiimport will wrap bundle-style packages and metapackages and applications in disk images for you. You generally need not do anything other than:

munkiimport /path/to/the/item

Read on for more detail.

5.3.11 Details

5.3.11.1 What is a bundle package?

Since the release of Mac OS X 10.5 (Leopard), there have been two major formats for Apple Installer packages. Leopard introduced a new “flat” style of package, where the package is a single file. But prior to Leopard, all packages were “bundle-style” packages, consisting of a directory of files and folders. This style of package still works in Leopard and Snow Leopard, and is required for use with Tiger and earlier OSes, so it is still the most common style of package to be found.

5.3.11.2 Identifying a bundle package

How can you tell if a given package is a “bundle-style” package?

  • From the Finder, control-click on the package to get a contextual menu. If “Show Package Contents” appears in the menu, the package is a bundle-style package. Otherwise, the package is a “flat” package.

  • From the command-line, either attempt to cd into the package, or perform an ls -al on the directory containing the package. If you can cd into the package or it displays as a directory in an extended listing, it is a bundle-style package

I still can’t tell for some reason…

  • Then wrap it in a disk image anyway. Bundle-style packages must be wrapped in a disk image file. Flat packages are not required to be encapsulated in a disk image, but will work fine if they are in a disk image.

5.3.11.3 Wrapping it up

  • /usr/local/munki/munkiimport will automatically convert items to diskimages as needed. This is the recommended method to create disk images for use with Munki.

  • From the Finder: drag the package onto the Disk Utility application located in /Applications/Utilities. Disk Utility will launch and prompt you for a location and name to save the disk image. Be certain to create a read-only disk image, or you will get checksum hash errors when Munki tries to download your disk image.

  • From the command-line: sudo hdiutil create -srcfolder /path/to/some.pkg /path/to/some.dmg – I recommend running this with sudo to avoid permissions issues.
    Adding custom help for Managed Software Center

5.3.12 Details

As of build 2.0.0.2163, Managed Software Center will check Munki’s preferences for a HelpURL key. If that key is present and the user chooses “Managed Software Center Help” from Managed Software Center’s Help menu, that URL will be opened using the URL’s default application. (In other words, http/https URLs will be opened by the user’s default browser, etc.)

sudo defaults write /Library/Preferences/ManagedInstalls HelpURL http://webserver.my.org/msc_help.html

(or use MCX or a configuration profile, etc…)
Setting up a demonstration Munki Repo and client

5.3.13 Introduction

Since Munki can use virtually any web server as its server, and since Mac OS X ships with Apache 2, it’s very easy to set up a demonstration Munki server on any available Mac. You can even set up a Munki server on a single machine that is also a Munki client, and that is what we’ll do here. We will set up Munki on a machine running OS X (non-server).

It is certainly possible to set up a Munki repo on OS X Server. A Munki repo is simply a set of files on a web server. The exact configuration details vary from version to version of OS X Server, and are not documented here. See Apple documentation on how to configure the web service for your specific version of OS X Server.
Nick McSpadden has published some notes on setting up a Munki repo on Yosemite Server here: https://osxdominion.wordpress.com/2015/02/26/setting-up-munki-with-os-x-yosemite-server/

This wiki page is adapted and updated from the MacTech column here.

5.3.14 Details

5.3.14.1 Building a “server” repository

To set up our Munki “server” (in this case, a web server running on the same machine that is also our demonstration client), we’re going to create a directory structure in /Users/Shared, and then configure Apache2 to serve it via HTTP. You can do the next few steps via the Finder or via the Terminal, but it’s easier to write them out as Terminal commands:

cd /Users/Shared/
mkdir munki_repo
mkdir munki_repo/catalogs
mkdir munki_repo/icons
mkdir munki_repo/manifests
mkdir munki_repo/pkgs
mkdir munki_repo/pkgsinfo

You might be wondering what that last directory is. The pkgsinfo directory holds data that is not used directly by Munki clients, but is used by other Munki tools to create the catalogs. One more thing: let’s make sure the Apache 2 can read and traverse all of these directories:

chmod -R a+rX munki_repo

Next, we need to tell Apache2 to serve the munki_repo directory via HTTP. You could edit the /etc/apache2/http.conf file, or one of the other .conf files used by Apache2, but there’s a much easier method for this demonstration.

sudo ln -s /Users/Shared/munki_repo /Library/WebServer/Documents/

This creates a symlink inside /Library/WebServer/Documents/ that points to our new munki_repo directory. By default on Mac OS X, /Library/WebServer/Documents/ is Apache 2 ‘s DocumentRoot, so it will serve anything in that directory via HTTP. However, by default on MacOS Server the web server’s DocumentRoot is located in /Library/Server/Web/Data/Sites/Default.

5.3.14.2 Activate Apache

If you are running Lion or earlier, turn on Web Sharing in the Sharing preferences pane.

If you are running Mountain Lion or later, you can turn on Apache 2 like so:

sudo apachectl start

This activates the Apache web server, and also activates the launchd job so that Apache will be active across restarts.
To revert this change:

sudo apachectl stop

If you are using Mavericks or earlier for this demonstration setup, now that Apache is running, you can test your work so far. You can use your favorite web browser and navigate to http://localhost/munki_repo. If you’ve done things correctly to this point, you should see a directory listing, showing the catalogs, manifests, pkgsinfo, and pkgs directories. If you don’t see a directory listing, and instead get a 403 error: “Forbidden You don’t have permission to access /munki_repo/ on this server.” see the following note.

NOTE: On OS X Mavericks and earlier, Apache 2 serves directory listings by default. This has the helpful effect of making it easier for us to see what is going on. (More commonly, and specifically in OS X Server and in 10.10+, Apache is configured to NOT list directory contents.) In production use, you will almost certainly want to disable directory listings, as they’d allow people to easily discover the contents of your pkgs directory and perhaps then “help themselves” to software they are not entitled to. Munki does not require directory listings to operate. If directory listings are not turned on for your configuration of Apache, you can safely ignore the 403 error and continue on.

5.3.14.3 Populating the repo

We now have a working Munki repo – but it’s completely empty and not useful at all. So let’s start to populate the repo.

We’re going to use some tools distributed with munki to import packages into our new Munki repo. Download the current munki installation package at https://github.com/munki/munki/releases/latest.

Install the Munki tools by mounting the disk image and double-clicking the Installer package and installing like any other package. A restart is required after installation.

The tools you’ll use as an administrator are available from the command-line, and are installed in /usr/local/munki. This location is not in the standard search path, so you’ll need to either add this directory to your search paths, or be sure to type the full path when invoking these tools.

The tool we will use to import packages into the munki repo is called munkiimport. We need to configure it before we can use it – telling it where to find our repo, among other things.

bash-3.2$ /usr/local/munki/munkiimport --configure
Repo URL (example: afp://munki.example.com/repo): file:///Users/Shared/munki_repo
pkginfo extension (Example: .plist): <just hit return>
pkginfo editor (examples: /usr/bin/vi or TextMate.app): TextMate.app <substitute your favorite text editor>
Default catalog to use (example: testing): testing
Repo access plugin (defaults to FileRepo): <just hit return>

We are first asked for the path to the Munki repo, and since we set one up at /Users/Shared/munki_repo, that’s what we enter with the file:// prefix. If you were hosting a repo remotely, this would typically be an afp:// or smb:// URL specifying the share.

We are then asked to specify an extension to append to the name of pkginfo files. Some admins prefer “.plist”, some prefer “.pkginfo”. Personally, I just leave it blank – Munki doesn’t care.

Next, you are asked for an editor to use for the pkginfo files. If you like command-line editors, you can specify /usr/bin/vi or /usr/bin/emacs for example. If you, like me, prefer GUI text editors, you can specify a GUI text editor application by name (but be sure to include the “.app” extension). I picked TextMate.app, but you could choose TextWrangler.app, BBEdit.app, or even TextEdit.app.

Next, you are asked for the default catalog new packages/pkginfo should be added to. We’ll use a “testing” catalog for this.

Finally, you’ll be asked what Repo access plugin to use. Leave this blank, since we’ll be using FileRepo.

Next, let’s get a package to import. Firefox is a good example package, and you can download it from http://www.mozilla.com/. As of this writing, the current version is 53.0.3, and when I download it using Safari, a disk image named “Firefox 53.0.3.dmg” is downloaded to my Downloads folder.

We’ll return to the command line to import the Firefox package.

5.3.14.4 Importing Firefox

bash-3.2$ /usr/local/munki/munkiimport ~/Downloads/Firefox\ 53.0.3.dmg 
           Item name: Firefox 
        Display name: Mozilla Firefox
         Description: Web browser from Mozilla
             Version: 53.0.3 
            Category: Internet
           Developer: Mozilla
  Unattended install: False
Unattended uninstall: False
            Catalogs: testing    
Import this item? [y/n] y
Upload item to subdirectory path []: apps/mozilla
Path /Users/Shared/munki_repo/pkgs/apps/mozilla doesn't exist. Create it? [y/n] y
No existing product icon found.
Attempt to create a product icon? [y/n] y
Attempting to extract and upload icon...
Created icon: /Users/Shared/munki_repo/icons/Firefox.png
Copying Firefox 53.0.3.dmg to /Users/Shared/munki_repo/pkgs/apps/mozilla/Firefox 53.0.3.dmg...
Edit pkginfo before upload? [y/n]: y
Saving pkginfo to /Users/Shared/munki_repo/pkgsinfo/apps/mozilla/Firefox-53.0.3...

We run the munkiimport tool and provide it a path to our downloaded disk image.

munkiimport then asks us to confirm or override some basic information about the package. We accept the item name by simply hitting return, but provide a new “Display name” and “Description”. We accept the version and the catalogs, again, by simply hitting return. We entered a category and developer.

munkiimport then prints back our choices and asks if we want to import the item. (If we made any mistakes, this would be a good time to say “no”!) We agree, and munkiimport asks us if we’d like to upload the package to a subdirectory path. We could just skip this, and upload everything to the top level of the pkgs directory in the munki repo, but as our number of packages grows, that might get hard to navigate. So we’re going to upload this into a directory named “Mozilla” inside a directory named “apps”. As a sanity check, munkiimport warns us that the subdirectory path we’ve chosen doesn’t yet exist. Since this is a brand new repo, we knew in advance that the directory didn’t exist, so we want munkiimport to create it for us.

munkiimport looks for an existing uploaded icon for Firefox and doesn’t find one, so it offers to create one for us. We agree.

Finally, munkiimport copies the Firefox package to /Users/Shared/munki_repo/pkgs/apps/mozilla/ and saves the pkginfo to /Users/Shared/munki_repo/pkgsinfo/apps/mozilla/Firefox-53.0.3.

Since I chose TextMate.app as my editor when I configured munkiimport earlier, munkiimport next gives the option to open the newly created pkginfo file in TextMate. No matter which editor you choose–if you choose to edit the pkginfo at this time–you’ll see a standard Apple property list file (plist) describing the package you just imported.

This gives you another opportunity to edit the pkginfo using your favorite text editor. In this case, we don’t need to make any changes, though, so we can just close it. If we return our attention to the terminal window we used to run munkiimport, we’ll see it’s prompting us for one more bit of information:

Rebuild catalogs? [y/n] 

Remember that munki clients don’t use the individual pkginfo files; instead they download and consult munki catalogs to find available software. So to actually make use of the pkginfo we just generated, we need to build new versions of all the defined catalogs. Answering “y” to this prompt causes munkiimport to rebuild the munki catalogs.

Rebuild catalogs? [y/n] y
Adding apps/mozilla/Firefox-53.0.3 to testing...

Since we only have one package (and its corresponding pkginfo) in our munki repo, we see a single item has been added to the testing catalog.
Again we can check our work so far. In your web browser, navigate tohttp://localhost/munki_repo/catalogs/testing. You should see a property list which contains the pkginfo for Firefox.

5.3.14.5 Creating a client manifest

We now have one package in our Munki repo. Our next step is to create a client manifest so that Munki knows what to install on a given machine.

We’ll use the manifestutil tool to create our manifest.

% /usr/local/munki/manifestutil 
Entering interactive mode... (type "help" for commands)
> new-manifest site_default
> add-catalog testing --manifest site_default
Added testing to catalogs of manifest site_default.
> add-pkg Firefox --manifest site_default
Added Firefox to section managed_installs of manifest site_default.
> exit

We’ve created a new manifest named “site_default”. “site_default” is one of the manifests a Munki client looks for by default if not configured to look for a specific manifest by name.
We added “testing” to the list of catalogs to consult, and “Firefox” to the list of packages to install.

If you examine the file at /Users/Shared/munki_repo/manifests/site_default, it should look like this:

<?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>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>included_manifests</key>
    <array>
    </array>
    <key>managed_installs</key>
    <array>
        <string>Firefox</string>
    </array>
    <key>managed_uninstalls</key>
    <array>
    </array>
</dict>
</plist>

Again, you can check your work in your web browser by navigating to http://localhost/munki_repo/manifests/site_default. You should see the file you just created displayed in your web browser.

5.3.14.6 Munki Client Configuration

We’re done (for now) with the server. Next, we need to configure the Munki client so it knows about our server. The Munki client stores its configuration in /Library/Preferences/ManagedInstalls.plist. Unless you’ve run the Munki client before, this file won’t yet exist. We’ll use the defaults command to create it with the data we need.

sudo defaults write /Library/Preferences/ManagedInstalls SoftwareRepoURL "http://localhost/munki_repo"

We’ve told the client tools the top-level URL for the munki repo – http://localhost/munki_repo. That’s it for the client configuration. If you’d like, check your work:

defaults read /Library/Preferences/ManagedInstalls

Make sure the value of “SoftwareRepoURL” is as expected.

5.3.14.7 Testing the Munki client software

Now the moment of truth: let’s run the Munki client from the command line.

sudo /usr/local/munki/managedsoftwareupdate 
Managed Software Update Tool
Copyright 2010-2014 The Munki Project
https://github.com/munki/munki
    
Downloading Firefox 53.0.3.dmg...
    0..20..40..60..80..100
Verifying package integrity...
The following items will be installed or upgraded:
    + Firefox-53.0.3
        Web browser from Mozilla
    
Run managedsoftwareupdate --installonly to install the downloaded updates.

Success! Munki saw that we needed Firefox 53.0.3 and downloaded it. (It did not yet install it – we’ll get to that in a bit.)

But what if instead when you run managedsoftwareupdate you see this:

sudo /usr/local/munki/managedsoftwareupdate 
Managed Software Update Tool
Copyright 2010-2014 The Munki Project
https://github.com/munki/munki
    
No changes to managed software are available.

The most likely reason you see this is because you already have Firefox 53.0.3 (or later) installed. If you really want to test Munki, delete your copy of Firefox:

sudo rm –r /Applications/Firefox.app

Then run /usr/local/munki/managedsoftwareupdate again – you should see it being downloaded as in the example above.

5.3.14.8 Demonstrating Managed Software Center.app

We ran managedsoftwareupdate from the command line and verified that the munki client tools could talk to our munki server and download the Firefox package. But, as we’ve noted, managedsoftwareupdate did not actually install Firefox. We could call managedsoftwareupdate again, this time passing it the -–installonly flag to make it install what it just downloaded. But instead, we’re going to introduce another tool – the one “regular” users would interact with – Managed Software Center.app. You’ll find it in the /Applications folder. Double-click it to launch it.

Managed Software Center will check for updates with the Munki server, and should shortly display a window (closely resembling Apple’s App Store application’s main window) displaying Firefox 53.0.3.

If you click on Update, Firefox will be installed.

5.3.15 Conclusion

You’ve set up a demonstration of Munki’s server and client components. Please be sure to also read Munki’s Frequently Asked Questions

For a more in-depth introduction to Munki, see these MacTech articles:

Managing Software Installs with Munki – Part 1
Managing Software Installs with Munki – Part 2
Managing Software Installs with Munki – Part 3
Managing Software Installs with Munki – Part 4
Discussion group for the development of Munki is here: http://groups.google.com/group/munki-dev

Other related discussion groups:<br/>
General Munki discussion: https://groups.google.com/forum/#!forum/munki-discuss<br/>
MunkiAdmin: https://groups.google.com/forum/#!forum/munkiadmin-dev<br/>
MunkiReport: https://groups.google.com/forum/#!forum/munkireport<br/>
MunkiWebAdmin: https://groups.google.com/forum/#!forum/munki-web-admin<br/>
Sal: https://groups.google.com/forum/#!forum/sal-discuss<br/>
Simian: https://groups.google.com/forum/#!forum/simian-discuss<br/>

6 A list of documentation that would be nice to have.

A list of documentation that would be beneficial to the Munki community, and are looking for an author.

  • Using catalogs to implement development/testing/release groups – Done 25-Aug-2010 by joshpadilla
  • Removing packages with munki
  • Dependencies in munki
  • Deploying “patch-style” updates with munki (as opposed to just installing a complete new package)
  • Using “installs” keys to auto-repair installs
  • Apple Software Updates with munki – Added 16-oct-2010 by MagerValp
  • The structure and contents of ManagedInstallReport.plist needs to be documented
  • How to repackage Installer VISE, InstallAnywhere, and other custom installed apps for distribution with munki. - Added 10-Nov-2010 by gregneagle
  • Knowledge Base of applications on how to repackage them (if needed) and make a good PkgInfo file.
    How to future-proof your Munki configurations by using a preflight script to download the newest configuration information from your repository.

NOTE: This is a user-contributed solution and is not directly part of Munki. It may not work in your environment, or with future OS releases or future releases of Munki.

Configuring a Munki client for the first time isn’t difficult. Mostly it’s just copying a single ManagedInstalls.plist into the /Library/Preferences folder. This, however, kind of paints you into a corner.

What if you ever want to change your repository URL? What if you want to change how often users get notified? What if you want to change your policy, and allow users to cancel updates after you’ve already rolled out Munki to the entirety of your organization? In these scenarios, you’ll have to touch every single machine either physically or virtually(through SSH, etc.) to make those configuration changes. That’s not a good use of anyone’s time. These may seem like crazy things to want to account for in advance, but they actually can be accounted for very simply through the use preflight scripting.

If we think about the informational problems involved for a moment, we can see that there’s really only one thing a client absolutely has to know about the configuration…the URL of the server. The server URL is the only setting Munki can’t live without. Every other setting has some sort of default that will allow the program to work in some fashion.

The following script abuses that fact:

6.0.0.1 preflight

import sys
import os
from munkilib import fetch
from munkilib import FoundationPlist

#Dynamic Config Munki Preflight Script by John Rozewicki
#2010-12-08
#
#Script merges config from Munki repo into local config if newer.

## disturbing hack warning! (untested for < 10.11)
## this works around an issue with App Transport Security on 10.11
## Remove the comment hashes from the following 4 lines for 10.11+
#from Foundation import NSBundle
#bundle = NSBundle.mainBundle()
#info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
#info['NSAppTransportSecurity'] = {'NSAllowsArbitraryLoads': True}

RepoURL = "http://YOUR_REPO_ROOT_URL_HERE"
ConfigName = "ManagedInstalls.plist"
ServerConfigName = "ManagedMunkiServer.plist"
ConfigDir = "/Library/Preferences"
ConfigPath = os.path.join(ConfigDir, ConfigName)
ServerConfigURL = os.path.join(RepoURL, ServerConfigName)
ServerConfigPath = os.path.join(ConfigDir, ServerConfigName)

def MergePlists(FromPlist, ToPlist):
    FromPlistData = FoundationPlist.readPlist(FromPlist)
    ToPlistData = FoundationPlist.readPlist(ToPlist)
    for item in FromPlistData:
        ToPlistData[item] = FromPlistData[item]
    FoundationPlist.writePlist(ToPlistData, ToPlist)

if (sys.argv[1] != "logoutinstall") and (sys.argv[1] != "installwithnologout"):
    os.system("touch /Users/Shared/.com.googlecode.munki.checkandinstallatstartup")
    print "Checking for new %s" % (ServerConfigName)
    if fetch.munki_resource(
            ServerConfigURL, ServerConfigPath):
        print "     Merging new server settings into configuration."
        MergePlists(ServerConfigPath, ConfigPath)

This script looks to the munki repository for a file called ManagedMunkiServer.plist. This file is a version of the configuration that contains all non-unique configuration items such as the URL of our Server, the time between notifications, whether a user can cancel updates or not, etc. If the file on the server is newer than the version on the disk then it downloads it. It then opens this file, and overwrites the elements of ManagedInstalls.plist with the elements from the newly downloaded ManagedMunkiServer.plist.

This means we can change the configuration of all of our clients at any point by editing a file on the server. If this technique is used in conjunction with WPKGlikeDynamicManifestsWithoutCGI then we have an extremely dynamic configuration with global configuration options and client -> manifest linking all handled by just 2 extra files on the server with 1 preflight script on the client.

Client configuration in this setup then becomes a simple matter of dropping a preflight script into the /usr/local/munki directory. As long as the preflight script is there, the client will always download the newest configuration from the server, and it will always link the right manifest to the client.
Using munki with a LogoutHook

6.0.1 Introduction

When Munki logs a user out to install software, it first returns to the loginwindow, pauses for a few moments, then initiates its installation via a LaunchAgent. It is possible to initiate the Munki installation via a LogoutHook instead, in order to execute the installation right at logout rather than right after logging out. This causes Munki to behave similarly to Apple Software Update (as of 10.5) when installing packages that require a restart.

6.0.2 Details

No configuration changes to Munki are required. Executing an installation via a LogoutHook harmlessly preempts Munki’s own com.googlecode.munki.managedsoftwareupdate-loginwindow.plist LaunchAgent.

The following script can be called directly by a LogoutHook, or integrated into your organization’s existing LoginHook/LogoutHook regime.

    #!/bin/bash
    
    if [ -e /private/tmp/com.googlecode.munki.installatlogout ]; then
    
    export ManagedSoftwareUpdateMode=MunkiStatus
    
    /Applications/Managed\ Software\ Center.app/Contents/MacOS/Managed\ Software\ Center&
    
    /usr/local/munki/managedsoftwareupdate --logoutinstall
    
    fi
    
    exit 0

7 See also

https://support.apple.com/kb/HT2420

https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CustomLogin.html

https://afp548.com/static/mactips/loginhooks.html

7.1 Frequently Asked Questions


7.1.1 General questions


7.1.1.1 Q: How do you pronounce Munki?

A: Same as “monkey.”

7.1.1.2 Q: Does Munki stand for something?

A: Nope. Just a fun name that evokes “helper monkeys.”


7.1.2 Munki Installation


7.1.2.1 Q: Where do I get the latest release of the Munki tools?

A: Official releases (and release candidates) are here: Munki Releases

7.1.2.2 Q: Why does the munkitools.mpkg/launchd.pkg require a restart? This prevents an unattended upgrade of the Munki tools!

A: It is non-trivial to load launchd jobs, especially user-level LaunchAgents, in the correct Mach context from a package postinstall script in all possible execution contexts in which a package can be installed. But more importantly, the launchd jobs control Munki itself, and so Munki could not unload and reload these jobs without killing itself during the unload. So for maximum reliability, we require a restart so we ensure the jobs are loaded in the correct context and that Munki can actually complete the task!
As for unattended updates of the Munki tools, in most cases it is possible to upgrade them without requiring a logout or restart. See [[Updating Munki Tools|Updating-Munki-Tools]] for additional information.

7.1.2.3 Q: Can I skip the installation of the Munki admin tools on my managed clients?

A: Yes, but it’s probably not worth the effort. In order to make changes to the Munki repo, your clients/users need write access to it. Having the repo editing tools installed is no more “dangerous” than having a text editor, vi, or PlistBuddy installed. On the other hand, having the admin tools installed means you don’t have to track which machines belong to people who are Munki admins in your org. If you really, really want to not install the admin tools, take a look here: [[ChoiceChangesXML|ChoiceChangesXML]] and here [[Updating Munki Tools|Updating-Munki-Tools]] for info on how you could skip the install of the admin tools. (No, it’s not spelled out explicitly – because it’s recommended to just install the entire set of tools.)


7.1.3 Munki Capabilities


7.1.3.1 Q: What installer formats does Munki support?

A: Munki supports the following formats:

  • Apple Installer packages (.pkg/.mpkg)
  • Drag-and-drop Application disk images (Disk images that contain an application at the root of the mounted disk)
  • Adobe CS3/CS4/CS5/CS6/CC Deployment “packages” created with Adobe’s Enterprise Deployment tools - CS3 info, CS4/CS5/CS6 info, CC info
  • Many Adobe CS3/CS4/CS5/CS6/CC product updaters
  • Adobe Acrobat Pro 9.x updater disk images as downloaded from Adobe

Munki does not directly support other third-party installer formats like InstallerVISE, InstallAnywhere, BitRock Installer, etc, or “installers” that are actually applications that just copy stuff onto the disk.

7.1.3.2 Q: Can Munki install Apple Software Updates?

A: Yes. See [[Apple Software Updates With Munki|Apple-Software-Updates-With-Munki]] for more information.

7.1.3.3 Q: Can I deploy Mac App Store apps using Munki?

A: In many cases, yes. See App Store Apps

7.1.3.4 Q: Can I deploy Configuration Profiles using Munki?

A: Yes. Munki can install Device profiles (but not User profiles). See [[Managing Configuration Profiles|Managing-Configuration-Profiles]]

7.1.3.5 Q: Can I manage printers using Munki?

A: Yes. While not a core feature of Munki, it is possible. See [[Managing Printers With Munki|Managing-Printers-With-Munki]]

7.1.3.6 Q: Can I install/manage (insert some other random thing) with Munki?

A: If you can put it into an Apple package or write a script to do it as the root user, probably! If it’s something that must be done at the user level, you may need to look at other tools.

7.1.3.7 Q: Can Munki upgrade itself? Can I use Munki to install an updated version of Munki?

A: Yes. See [[Updating Munki Tools|Updating-Munki-Tools]].

7.1.3.8 Q: Can I use Munki to install major OS X/macOS upgrades (like upgrade machines to Sierra)?

A: Yes. See [[Installing OS X|Installing-OS-X]].


7.1.4 Munki Behaviors


7.1.4.1 Q: How often do Munki clients check for updates?

A: On average, once an hour. The exact time between checks is randomized somewhat to prevent every client from hitting the Munki server all at once. A launchd job defined at /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist runs at every 10 past the hour (e.g. 9:10). It, in turn, calls /usr/local/munki/supervisor, which sleeps a random time between 0 and 60 minutes (3600 seconds, to be exact) before performing an ‘auto’ run. This means that the time between any two Munki runs can vary from a few minutes to almost an hour. (See [[Launchd Jobs and Changing When Munki Runs]] for more info.)

7.1.4.2 Q: How is a user notified of available updates?

A: In Munki 2, an application named “Managed Software Center”, which looks very much like Apple’s App Store application, will open and display available updates. Like with Apple’s App Store, the user can then choose to install the updates now, or wait until later. Unlike with Apple’s App Store, the user cannot pick and choose among the updates. Those are managed by the Munki administrator. If any update requires a logout or restart, Managed Software Center triggers a logout before proceeding. Otherwise, the user can choose to update immediately.

In Munki 3, Munki uses Notification Center notifications to notify users of pending updates. If a user ignores pending updates for too long (default 3 days), notifications revert to Munki 2’s behavior.

7.1.4.3 Q: Does Munki support Notification Center notifications?

A: Munki 3 adds support for Notification Center. See [[Notification Center Support]]. Earlier versions of Munki do not support Notification Center notifications.

7.1.4.4 Q: Will Munki pop up notifications if a user is doing a presentation in front of an audience?

A: Sadly, yes, it might.
There is no reliable way to detect that a user is “doing a presentation”, so Munki can’t automagically not notify when a presentation is happening. There are many, many possible presentation applications. Here are a few: Keynote, PowerPoint, Preview, Prezi, Acrobat, Acrobat Reader, Safari, Chrome, Firefox – even the Finder by using the full-screen slideshow feature. There are multiple ways for an app to display content full-screen, and not all of them are “detectable” by other apps.

Apple provides a mechanism: Notification Center’s “Do Not Disturb” setting. It is designed to temporarily suppress all Notification Center notifications. Munki 3 uses Notification Center and respects Do Not Disturb. But your users must remember to activate it.

Do note that if a user ignores pending updates for too long (default: 3 days; admin-configurable), Munki 3 stops posting Notification Center notifications and instead launches Managed Software Center to display the list of available updates, and this could well happen during a “presentation”.

7.1.4.5 Q: What happens if the user chooses to update without logging out, but some of the updates are for applications that are currently open?

A: Munki can check for certain applications and notify the user to quit them before proceeding. See [[Blocking Applications|Blocking-Applications]] for more info on this feature.

7.1.4.6 Q: What if there is no user logged in?

A: The check schedule is the same (roughly once an hour). If there are updates available, Munki will install them if there is no user logged in and the machine has been idle for 10 seconds or longer. A status window is displayed over the loginwindow, and the loginwindow is disabled so that no-one can login while updates are occurring.

7.1.4.7 Q: How does Munki determine if the correct version of an application is installed?

A: If the path to the application appears in the “installs” array, Munki will first check that path. If the application is found at the given path, its CFBundleShortVersionString string is checked. If it matches what’s listed in the the manifest, Munki knows the correct version is installed. If the application isn’t found at the given path, LaunchServices and Spotlight are consulted to gather a list of all installed applications. If the application is listed with the correct version number, Munki knows the correct version is installed. If it’s not listed, or it has an earlier version number, Munki knows the application must be installed.

If there is no “installs” list, Munki relies on package receipts listed in the “receipts” array to determine installation status.

See [[How Munki Decides What Needs To Be Installed|How-Munki-Decides-What-Needs-To-Be-Installed]] for even more information on this topic.


7.1.5 Troubleshooting


7.1.5.1 Q: How do I get more information about what is happening when Munki runs?

A: There are a couple of ways to get more information:

  • You can raise the logging level: sudo defaults write /Library/Preferences/ManagedInstalls LoggingLevel 4. Then view/monitor the ManagedSoftwareUpdate log (usually found at /Library/Managed Installs/Logs/ManagedSoftwareUpdate.log)
  • You can run the tools at the command line with additional verbose flags: sudo managedsoftwareupdate -vvv

See also [[Troubleshooting|Troubleshooting]].

7.1.5.2 Q: I keep getting ‘Can’t install Foo-1.0 because the integrity check failed.’

A: Most likely the disk image containing Foo-1.0 is a read/write disk image. Possible solutions:

  • Convert the disk image to read-only and reimport the item.
  • Recreate the disk image as read-only and reimport the item.
  • Configure Munki to not verify package checksums (not recommended). See the PackageVerificationMode key in https://github.com/munki/munki/wiki/Preferences.

7.1.5.3 Q: I keep seeing warnings like WARNING: Could not process item Office2011_update-14.4.2 for update. No pkginfo found in catalogs: production, yet there is definitely an item named “Office2011_update-14.4.2” in the production catalog. What is happening?

A: A name followed by a hyphen and a version number (or a number!) has special meaning: it means NAME-VERSION. So Munki is actually looking for an item named “Office2011_update” with a version of “14.4.2”. It is NOT looking for an item with the name “Office2011_update-14.4.2”. To avoid this type of confusion, don’t put versions into names. It’s rarely good practice to do so. If you must, don’t precede the version with a hyphen. (Any number preceded by a hyphen is likely to be interpreted as a version number.)

7.1.5.4 Q: Each time Munki runs, it wants to install the same software again. Why is this?

A: The most likely explanation is that the install has failed. On the next run, Munki sees the item is not installed, and tries again. If the item actually is installed, see the next question…

7.1.5.5 Q: Munki successfully installed some software, but now each time Munki runs, it wants to install the software again. Why is this?

A: Munki usually uses one of two arrays in the pkginfo to determine if an item is installed. If the “installs” array exists, each item in the array is checked; if it does not exist or the currently installed version is older than the one described in the pkginfo, Munki will attempt to install the item. If there is no “installs” array, Munki will use the “receipts” array, again installing if any receipt is missing or is an older version that that described in the pkginfo.
If Munki repeatedly presents an item for install after a successful installation, then one or more items in the “installs” array is not being installed, or one or more items in the “receipts” array is not being recorded in the receipts database. You’ll need to determine what is not being installed and remove it from the installs or receipts array. (Or in the case of a receipt, mark it as “optional”.) Alternately, if there is no installs array, you can often resolve this issue by adding an installs array.
See [[How Munki Decides What Needs To Be Installed|How-Munki-Decides-What-Needs-To-Be-Installed]] for even more information on this topic.

7.1.5.6 Q: I just set up Munki and there’s nothing available under “Software” or “Categories” and the icons are greyed out. How do I make things available there?

A: Add items to optional_installs in the relevant manifests. Items under “Software” or “Categories” can be installed or removed under the user’s control: they aren’t enforced as installed, updated, or removed. If there are no items in optional_installs, there’s nothing for the user to choose to install (or remove.)


7.1.6 More


7.1.6.1 Q: I have a question that isn’t answered here. Where do I go for help?

A: Try these resources:

Support for Featured Items in Managed Software Center is a new feature for Munki 3.

7.2.1 Overview

Managed Software Center will display “Featured” items if there are any in the list of optional installs. If there are any “Featured” items, it replaces the “All Items” view.

7.2.2 Implementation

Add a featured_items section to a manifest containing the items you wish to feature:

        <key>featured_items</key>
        <array>
            <string>Office2016</string>
            <string>Slack</string>
            <string>SuperSolitaire2017</string>
        </array>

Featured items must be available via optional_installs; in other words, adding an item to featured_items does not automatically make it an optional_install – it only makes it “Featured” if it is an optional_install. Yes, this means maintaining an item in two lists: optional_installs to make it available as an optional install, and featured_items to have it displayed with other featured items. But this allows one to feature different items for different groups.

You’ll likely want to edit the FileMaker Pro .mpkg to get your organization’s license information into the Assisted Install.txt. You can find those steps on FileMaker Pro’s website.

FileMaker Pro will get into an endless install loop unless you create the proper installs array.

For Munki 2, you may want to do the installs array based on the Info.plist instead of the larger bundle, since more recent versions of FileMaker still have com.filemaker.client.advanced12 as the CFBundleIdentifier.

Here’s an example of getting the installs array based on the Info.plist:
makepkginfo -f /Applications/FileMaker\ Pro\ 14\ Advanced/FileMaker\ Pro\ Advanced.app/Contents/Info.plist

And the resulting installs array you’d put into the pkginfo file:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleShortVersionString</key>
            <string>14.0.6</string>
            <key>CFBundleVersion</key>
            <string>14.0.6</string>
            <key>path</key>
            <string>/Applications/FileMaker Pro 14 Advanced/FileMaker Pro Advanced.app/Contents/Info.plist</string>
            <key>type</key>
            <string>plist</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Based on changes in Munki 3, it may be okay to get the installs array from the general bundle:
makepkginfo -f /Applications/FileMaker\ Pro\ 14\ Advanced/FileMaker\ Pro\ Advanced.app

7.2.3 Deploying GarageBand with Munki

Deploying GarageBand itself is pretty straightforward however the Apple Loops element can cause issues if not done correctly.

7.2.3.1 Import GarageBand

GarageBand 10 is now a App Store application, please follow the guidelines for the importing GarageBand from the [[ App Store Apps | App-Store-Apps ]] page.

7.2.4 Import Audio Content

In shared environments where users aren’t admin users, you will want to deploy at least the mandatory Apple Loops so users are not prompted to install themselves on first launch. If you decide to skip installing these mandatory loops, GarageBand will download them on first launch. Followed by prompting an administrator for their authorization to start the installation of these packages.

7.2.4.1 Method 1

As of January 2017 this is the best practices solution as it mimics how the GarageBand application obtains the loops from Apple.

  1. @carlashley currently hosts a script that will download the latest loops for you located appleLoops. Please see the repo README for more information.

  2. Download the appleLoops repo:

    $ git clone https://github.com/carlashley/appleLoops.git
    $ cd appleLoops
  3. Download the mandatory apple loops packages.

    $ ./appleLoops.py --package-set garageband --mandatory-only --destination ~/Desktop/loops
  4. Import these packages and set them as an update_for to your GarageBand application. These ‘essential’ 33 packages can be mass imported with a something like @aysiu’s BulkMunkiImport.sh.

7.2.4.2 Method 2


This method installs the “CoreContents” packages in order to avoid the GarageBand first run download. As of January 23rd, 2017 and GarageBand 10.1.5 this method still works but could become deprecated at anytime.
***

7.2.4.2.1 Import Apple Loops
  1. Download the two CoreContents packages:
  2. Now you will want to use munkiimport on the two packages.

    Requirements (for silent install):

    MAContent10_GarageBandCoreContent_v3.pkg
    MAContent10_GarageBandCoreContent2.pkg
  3. The above CoreContent packages contain the same package identifier as such munki will, by default, only attempt to install the latest version (V3) however GarageBand 10.1.0 requires both. You will need to modify your pkginfo for the MAContent10_GarageBandCoreContent_v3.pkg package to require MAContent10_GarageBandCoreContent2.pkg. Sample snippets below:

    MAContent10_GarageBandCoreContent-2.0.0.0.1.1256150330.plist

        <key>update_for</key>
        <array>
            <string>GarageBand</string>
        </array>
        <key>version</key>
        <string>2.0.0.0.1.1256150330</string>

    MAContent10_GarageBandCoreContent-3.0.0.0.1.1256150330.plist

        <key>requires</key>
        <array>
            <string>MAContent10_GarageBandCoreContent-2.0.0.0.1.1256150330</string>
        </array>
        <key>update_for</key>
        <array>
            <string>GarageBand</string>
        </array>
        <key>version</key>
        <string>3.0.0.0.1.1256150330</string>
  4. Optional Apple Loops packages can be set placed in your manifests optional_installs array or set as an update_for if you wish for them to be deployed as well.

Resource: Download all of the GarageBand content loops

Geometer’s Sketchpad’s own documentation on silent installs is actually incorrect.

To get the silent install to work properly, you need to use single quotes instead of double quotes when activating, and you need to wait a few seconds before doing so. Here’s an example of what would be your postinstall_script in your Munki pkginfo:

#!//bin/bash
sleep 3
/Applications/GSP5.app/Contents/MacOS/GSP5_Rel_KCPT_31_105 -license register -name 'Name of Your School' –code ************************
sleep 2

Similarly, your preuninstall_script would be:

#!/bin/bash
/Applications/GSP5.app/Contents/MacOS/GSP5_Rel_KCPT_31_105 -license deregister -name 'Name of Your School' –code ************************
sleep 3

Definition of common munki terms.

7.2.4.3 Catalog

A list of items available on the server, created by the makecatalogs tool. There can be multiple catalogs. Stored in the “catalogs” directory on the munki server.

7.2.4.4 Info File (or PkgInfo File)

A plist file that describes an installer item. Stored in the “pkgsinfo” directory on the munki server. Contains, among other things, a list of catalogs the installer item appears in. All installer items are automatically included in the “all” catalog.

7.2.4.5 Installer Item

Piece of software to be installed. May be be either a flat Apple package (.pkg), or a disk image (.dmg). Stored in the “pkgs” directory, or sub-directories there of, on the munki server. (Flat packages, introduced with OS X 10.5, are packages in the form of a single file. “Bundle-style” packages are actually directories, and must be encapsulated in a disk image. This has the effect of converting them into a single file, making them easier to download from a web server.)

7.2.4.6 Manifest

Describes what software a client should have installed or uninstalled. Stored in the “manifests” directory on the munki server.
Stuff to look for:

  • ! arbitrarily in front of words
  • Code blocks that are not displaying properly
  • Tables that are completely messed up
  • Descriptions in huge letters (Removing the first line normally fixes this).

Feel free to add any other common artifacts that are found.

7.3 Getting started with Munki

7.3.1 Overview

See here for a basic overview of what Munki does and does not do.

To search this wiki use the “Search” field in the GitHub navigation bar above. Then on the search results page select the “Wiki” option or click here.

7.3.3 Details

See [[Demonstration Setup]] for a walk-through of setting up a functional Munki client and server on a single machine; no separate web server needed. This is a quick and easy way to get started with Munki, and is a recommended starting point for people new to Munki.

7.3.3.1 Munki Versions

  • Munki 1.x and earlier support Mac OS X 10.5–10.9.x.
  • Munki 2.x supports Mac OS X 10.6 – 10.11.x
  • Munki 2.3.1 or higher is recommended for use with OS X 10.11 and macOS 10.12.
  • Munki 3.x supports OS X 10.8 and higher.

7.3.3.2 Requirements:

7.3.3.2.1 Python

Munki requires Python 2.5 or higher with Objective-C Python bindings, which is included by default in Mac OS X. Munki 1.x is supported on Leopard through Mavericks (10.5-10.9). Munki 2 drops support for Leopard, and supports Snow Leopard or higher (10.6+). Munki 3 drops support for Snow Leopard and Lion, and supports Mountain Lion or higher (10.8+).

To see how to report cases where Python dependencies are broken, see [[Report Broken Client]].

7.3.3.2.2 Web server

A basic Munki server is simply a web server. You do not need the Munki tools installed on the server. You can set up a Munki server on any platform that supports a web server. You can use OS X client, OS X Server, Linux, Windows or even a NAS appliance as a Munki server. You are simply setting up a filesystem on a web server for clients to access.

7.3.3.2.3 A Mac to administer your Munki server

This machine will use the Munki admin tools to create pkginfo files, catalogs and manifests. This machine must be running Mac OS X and it needs the munkitools.mpkg installed. You can also use your Munki server for this (if the server is running Mac OS X or Mac OS X Server) but it’s not required. Installing the munki tools prompts a reboot so maybe your server isn’t the best choice depending what other services it hosts. Common choices for an admin machine: The Mac you do your day to day work on, a spare Mac, your Munki server (if it’s running OS X).

If your Munki server is on an OS X Server and you do decide to also use it as an admin station, consider installing only the admin tools. Installing the full package will also cause the server to be an unconfigured Munki client, which could lead to unwanted consequences ranging from unexpected software installs to security exploits by bad actors.

7.3.3.2.4 User / Client Machines

These are your users machines that you want to install updates and packages on via Munki. munkitools.mpkg must be installed on all client machines. munkitools.mpkg contains 4 sub packages: app, core, launchd and admin. The admin package is not required for your clients, but it’s much simpler to just install the whole package.

The easiest way to start is by downloading the current packaged release here:
https://github.com/munki/munki/releases

The installer package installs the munki command-line tools in /usr/local/munki/, and the GUI Managed Software Center.app in /Applications/ (alongside an Managed Software Update.app alias in /Applications/Utilities/).

Then follow the walkthrough here: [[Demonstration Setup]] to setup a demo Munki server and client.

7.3.3.3 Key tools

Admin tools:

munkiimport: A tool that helps an admin import software installation packages into the Munki server. See [[munkiimport]] for more info on this tool.

makepkginfo: A lower level tool. Given an installer package, creates basic pkginfo (metadata) for it. The admin should edit this and add to this metadata - if it was all automatically discoverable, we wouldn’t need the separate pkginfo metadata file in the first place! See [[makepkginfo]] for more.

makecatalogs: Builds Munki catalogs from pkginfo files generated by makepkginfo or munkiimport. See [[makecatalogs]] for more.

manifestutil: A tool for manipulating manifest files. See [[manifestutil]] for documentation.

Client tools:

managedsoftwareupdate - checks with the server and retrieves current manifest(s); walks though the manifest(s), downloads catalogs, retrieves detail on individual manifest items and then builds a list of items that need to be installed, and a list of items that need to be removed. More info here: [[managedsoftwareupdate]]

Calling managedsoftwareupdate --installonly - installs or removes items.

GUI application:

Managed Software Center.app: Located at /Applications/Managed Software Center.app

This app is used to notify the user that there are updates to be installed. It also provides visual progress feedback during installs, even over the loginwindow. Additionally, it serves as an App Store-like source for on-demand/optional software installs and removals.

Users can also run this app to trigger a check for available updates; if there are no available updates (in InstallInfo.plist) when it is launched, it will run a check and return the results.

7.3.3.4 Demonstration setup of Munki server and client

See [[Demonstration Setup]] for a walkthrough of setting up a demo Munki server and client.

7.3.3.5 Where to go for more info and help

If, after working through the [[Demonstration Setup]] – and reading the other documentation here – you are still perplexed and need some help, post a a question on the munki-discuss Google Group.

There is also a #munki channel on the MacAdmins Slack group. Join here: https://macadmins.herokuapp.com

If you are looking for professional support or a managed solution, start here: Professional Support
Overview of the check phase and the use of receipts/installs

7.3.4 Introduction

When checking to see what needs to be installed, Munki uses information in the pkginfo items to decide whether or not a given item is installed. A Munki admin must understand how this works in order to create functional pkginfo items.

7.3.5 Details

Each time managedsoftwareupdate runs (except when in –installonly mode), it checks the lists of managed_installs, managed_updates, optional_installs, and managed_uninstalls items to see if they are installed.

Listed below, in order of precedence, are the methods used by munki to determine if a given item should be installed (or removed).
The order is as follows:

  • OnDemand
  • installcheck_script
  • Configuration Profiles
  • installs items
  • receipts

When combining these methods, only the highest priority method is used. For example, if a given pkginfo item has both an “installs” list and a “receipts” list, the receipts will be ignored for purposes of determining installation status. Even in this case, though, receipts may be used when removing an item, as they help Munki determine exactly which files were installed.

7.3.5.1 OnDemand

Pkginfo items marked as OnDemand will always be installed.

7.3.5.2 Install Check Script

As of munkitools 0.8.3 Build 1581, support has been added for including an “installcheck_script” within a pkginfo file. The purpose is to provide a method for determining if an item needs to be installed where providing “installs/receipts” is inadequate. Command-line tools typically installed via port (macports) or Python modules installed using easy_install are prime examples as they provide no easy method for determining their installed version.

An “installcheck_script” should be crafted such that an exit code of 0 indicates that the item is currently not installed and should therefore be installed. All non-zero exit codes indicate that the item in question is installed.

Here’s an example “installcheck_script” illustrating a check to determine if the current version of the argparse Python module is installed:

#!/bin/sh
    
# Grab current version of installed python module
version="$(python -c 'import argparse;print argparse.__version__' 2>/dev/null)"
    
# Compare with the version we want to install
if [ ${version:-0} < 1.2.1 ]; then
    exit 0
else
    exit 1
fi

Same script, embedded in a pkginfo file…

    <key>installcheck_script</key>
    <string>#!/bin/sh

# Grab current version of installed python module
version="$(python -c 'import argparse;print argparse.__version__' 2&gt;/dev/null)"

# Compare with the version we want to install
if [ ${version:-0} &lt; 1.2.1 ]; then
    exit 0
else
    exit 1
fi
    </string>

Inversely, if an item that included an “installcheck_script” were to be a “managed_uninstall”, this same script would be used to determine if the item is installed so that a removal can be processed. This is similar to how removals are processed, based on “installs” items.

7.3.5.3 Uninstall Check Script

Optionally, an explicit “uninstallcheck_script” can be provided to determine whether or not an item should be removed. In this case, the script would provide an exit code of 0 to indicate that the item is currently installed and that removal should occur. All non-zero exit codes indicate that the item in question is not installed.

7.3.5.4 Configuration Profiles

Pkginfo items with the installer_type of profile will use the following conditions to determine whether to install the profile. They are checked, in order, and if any of these conditions is true, Munki will install the profile. Please see Managing Configuration Profiles for more information.

  1. Is the profile’s identifier in the output of profiles -C?

Every profile has an identifier, with a recommended value of a reverse-domain name uniquely identifying the profile. (e.g. com.myorganization.SoftwareUpdateSettings). Munki will compare the profile it is considering installing with the results of profiles -C to see if there is a match. For this reason, updates to an existing profile must use the same identifier (but a different version) to be considered for installation.

  1. Is there a receipt for this profile identifier?

Even if a profile has been manually installed, without a profile receipt, Munki will install the profile.

  1. Does the hash of this profile match the receipt’s hash_value match?

The hash value is generated by feeding the .mobileconfig file through a sha256 hashing algorithm. The hash is not based on the identifier, nor the UUID.

  1. Does the ProfileInstallDate from the profile’s receipt match the ProfileInstallDate specified by profiles -C?

In the event that these dates differ, even though the identifier and hash match, Munki will install the profile.

7.3.5.5 Installs

This list is generated for you by makepkginfo or munkiimport for some types of installation items (“drag-n-drop” disk images; Adobe installers), but not for Apple packages. You can generate (or modify) this list yourself.

This is the most flexible mechanism for determining installation status. The “installs” list can contain any number of items. These can be applications, Preference Panes, Frameworks, or other bundle-style items, Info.plists, or simple directories or files. The Munki admin can use any combination of items to help Munki determine if an item is installed or not.

Here’s an auto-generated “installs” list for Firefox 6.0:

<key>installs</key>
<array>
    <dict>
        <key>CFBundleIdentifier</key>
        <string>org.mozilla.firefox</string>
        <key>CFBundleName</key>
        <string>Firefox</string>
        <key>CFBundleShortVersionString</key>
        <string>6.0</string>
        <key>minosversion</key>
        <string>10.5</string>
        <key>path</key>
        <string>/Applications/Firefox.app</string>
        <key>type</key>
        <string>application</string>
    </dict>
</array>

To determine if Firefox 6 is installed, Munki looks for an application with a CFBundleIdentifier of “org.mozilla.firefox” and if found, verifies that its version (“CFBundleShortVersionString”) is at least 6.0.

If it can’t find the application or its version is lower than 6.0, Munki considers Firefox-6.0 as not installed.

Installs lists can contain multiple items. If any item is missing or has an older version, the item will be considered not installed.

You can manually generate items to add to an “installs” list using makepkginfo:

/usr/local/munki/makepkginfo -f /Library/Internet\ Plug-Ins/Flash\ Player.plugin
<?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>installs</key>
    <array>
        <dict>
            <key>CFBundleShortVersionString</key>
            <string>10.3.183.5</string>
            <key>path</key>
            <string>/Library/Internet Plug-Ins/Flash Player.plugin</string>
            <key>type</key>
            <string>bundle</string>
        </dict>
    </array>
</dict>
</plist>

You could then copy and paste the entire “installs” key and value, or copy just the dict value and add it to and existing installs list.

In this example, Munki would check for the existence of “/Library/Internet Plug-Ins/Flash Player.plugin” and if found, check its version. If the version was lower than “10.3.183.5”, this item would be considered not installed.

You can generate “installs” items for any filesystem item, but Munki only knows how to determine versions for bundle-style items that contain an Info.plist or version.plist with version information. For other filesystem items, Munki can only determine existence (in the case of a non-bundle directory), or can calculate a checksum (for files). For files with checksums, the test will fail (and therefore the item will be considered not installed) if the checksum for the file on disk does not match the checksum in the pkginfo.

<key>installs</key>
<array>
    <dict>
        <key>md5checksum</key>
        <string>087fe4805b63412ec3ed559b0cd9be71</string>
        <key>path</key>
        <string>/private/var/db/dslocal/nodes/MCX/computergroups/loginwindow.plist</string>
        <key>type</key>
        <string>file</string>
    </dict>
</array>

If you’d like Munki to only check for the existence of a file and do not care about its contents, remove the generated md5checksum information in the installs item info. Be sure to leave the path intact!

<key>installs</key>
<array>
    <dict>
        <key>path</key>
        <string>/private/var/db/dslocal/nodes/MCX/computergroups/loginwindow.plist</string>
        <key>type</key>
        <string>file</string>
    </dict>
</array>

7.3.5.6 Receipts

When an Apple-style package is installed, it leaves a receipt on the machine. Metapackages leave multiple receipts. makepkginfo and munkiimport add the names and versions of those receipts to a “receipts” array in the pkginfo for a package.

Here’s is a receipts array for the Avid LE QuickTime codecs, version 2.3.4:

<key>receipts</key>
<array>
    <dict>
        <key>filename</key>
        <string>AvidCodecsLE.pkg</string>
        <key>installed_size</key>
        <integer>1188</integer>
        <key>name</key>
        <string>AvidCodecsLE</string>
        <key>packageid</key>
        <string>com.avid.avidcodecsle</string>
        <key>version</key>
        <string>2.3.4</string>
    </dict>
</array>

If Munki is using the “receipts” array to determine installation status, it checks for the existence and the version of each receipt in the array. If any receipt is missing or has a lower version number than the version specified for that receipt in the “receipts” array, the item is considered not installed. Only if every receipt is present and all versions are the same as the ones in the pkginfo (or higher) is the item considered installed.

If you are troubleshooting, you can use the pkgutil tool on Snow Leopard and Lion to examine the installed receipts:

# pkgutil --pkg-info com.avid.avidcodecsle
No receipt for 'com.avid.avidcodecsle' found at '/'.

In this case, the receipt for the Avid LE QuickTime codecs was not found on this machine.

A common complication with receipts is this: with many metapackages, the installation logic results in only a subset of the subpackages being installed. Generally, the “receipts” list contains a receipt for every subpackage in a metapackage (and needs this info if Munki is asked to remove the software based on package receipts). But if it is normal and expected that not every subpackage will actually be installed, Munki will continually mark the item as not currently installed and offer to install it again and again.

One solution for this issue is to add an “optional” key with the value of “true” to the receipts that are optionally installed. Munki will then not consider these receipts when determining installation status.

<key>receipts</key>
<array>
    <dict>
        <key>filename</key>
        <string>mandatory.pkg</string>
        <key>installed_size</key>
        <integer>1188</integer>
        <key>name</key>
        <string>Mandatory</string>
        <key>packageid</key>
        <string>com.foo.mandatory</string>
        <key>version</key>
        <string>1.0</string>
    </dict>
    <dict>
        <key>filename</key>
        <string>optional.pkg</string>
        <key>installed_size</key>
        <integer>1188</integer>
        <key>name</key>
        <string>Optional</string>
        <key>optional</key>
        <true/>
        <key>packageid</key>
        <string>com.foo.optional</string>
        <key>version</key>
        <string>1.0</string>
    </dict>
</array>

Another solution for this situation is to provide an “installs” array that lists items that are installed by the package. Munki can use that information instead of the receipts to determine installation status.
Packaging the OS X installer for use with Munki

7.3.6 Munki 3 note

Munki 3 provides a “native” option: see [[macOS Installer Application support]]. Use this native support for upgrading to Sierra or later with Munki 3 or later. The remainder of this document is for historical record, or for those still running Munki 2 and/or “upgrading” to a release of macOS older than 10.12.

7.3.7 Introduction

It is possible to package up OS X installers in order to install (or more accurately, upgrade to) Lion, Mountain Lion, Mavericks, Yosemite, El Capitan or Sierra using Munki. Once you’ve packaged the OS X installer in this way, you may use Munki to install Lion, Mountain Lion, Mavericks, Yosemite, El Capitan, or Sierra in the same way you install, say, Microsoft Office. And you would likely want to name each major macOS upgrade installer item differently, the same way you would name Office2011 and Office2016 differently.

7.3.8 Details

7.3.8.1 Getting Started

You’ll need some tools to package up the OS X installer.

You can download a zip archive here:

https://github.com/munki/createOSXinstallPkg/archive/master.zip

Or you may clone the Git repo:

git clone https://github.com/munki/createOSXinstallPkg.git

See https://github.com/munki/createOSXinstallPkg/blob/master/README.md for more info on the use of the tools.

7.3.9 pkginfo notes

To prevent Apple softwareupdates from being offered in the same Munki install session as one with a package you built with createOSXInstallPkg (for example, to prevent a 10.10.5 update or Apple Security update from being applied at the same time Munki is applying an upgrade to El Capitan), make sure to add

<key>apple_item</key>
<true/>

to the pkginfo for your OS X upgrade package.

7.3.9.1 receipts

The receipt left behind by a createOSXinstallPkg-generated package may not be useful if you also want to detect that the OS has been upgraded/installed by other means.

(In other words: if you were to add an “InstallMountainLion” package to the managed_installs for a certain machine, but that machine already had Mountain Lion, installed some other way, Munki would fail to find the receipt and attempt to install Mountain Lion anyway.)

So instead we should look for receipts that will be there no matter how OS X is installed.

To find the exact packagid version string run pkgutil on a Mac with the current version of OS X you want to install.

pkgutil --pkg-info com.apple.pkg.BaseSystemBinaries

Here are examples of what I’ve been using successfully:

7.3.9.2 Lion:

<key>receipts</key>
<array>
    <dict>
        <key>packageid</key>
        <string>com.apple.pkg.BaseSystemBinaries</string>
        <key>version</key>
        <string>10.7.0.1.1.1306847324</string>
    </dict>
</array>

7.3.9.3 Mountain Lion:

<key>receipts</key>
<array>
    <dict>
        <key>packageid</key>
        <string>com.apple.pkg.BaseSystemBinaries</string>
        <key>version</key>
        <string>10.8.0.1.1.1306847324</string>
    </dict>
</array>

7.3.9.4 Mavericks:

<key>receipts</key> 
<array>
    <dict>
        <key>packageid</key> 
        <string>com.apple.pkg.BaseSystemBinaries</string>
        <key>version</key>
        <string>10.9.0.1.1.1306847324</string>
    </dict>
</array>

7.3.9.5 Yosemite:

<key>receipts</key>
<array>
    <dict>
        <key>packageid</key>
        <string>com.apple.pkg.BaseSystemBinaries</string>
        <key>version</key>
        <string>10.10.0.1.1.1412852630</string>
    </dict>
</array>

7.3.9.6 El Capitan

Beginning with El Capitan, com.apple.pkg.BaseSystemBinaries is not part of the install. Instead of modifying the receipts array, I recommend adding an installs array instead. (You could also do this with older versions of OS X.)

    <key>installs</key>
    <array>
        <dict>
            <key>ProductVersion</key>
            <string>10.11</string>
            <key>path</key>
            <string>/System/Library/CoreServices/SystemVersion.plist</string>
            <key>type</key>
            <string>plist</string>
            <key>version_comparison_key</key>
            <string>ProductVersion</string>
        </dict>
    </array>

7.3.9.7 Sierra

Sierra would have a similar installs array to El Capitan.

    <key>installs</key>
    <array>
        <dict>
            <key>ProductVersion</key>
            <string>10.12</string>
            <key>path</key>
            <string>/System/Library/CoreServices/SystemVersion.plist</string>
            <key>type</key>
            <string>plist</string>
            <key>version_comparison_key</key>
            <string>ProductVersion</string>
        </dict>
    </array>

7.3.9.8 Avoiding Unsupported Hardware

Munki will gladly offer (and allow the built-in checks to make it fail) the OS install on hardware that is not capable of running that particular release. You can use logic like the one found here for Sierra to do a conditional item and prevent this from looping at the worst, or polluting logs with errors and warnings at the least.
NOTE: These instructions are no longer current and are considered deprecated. This document remains for historical reasons only. For instructions on setting up a demonstration Munki server and client, see [[DemonstrationSetup|Demonstration-Setup]]

These instructions describe how to install and configure Munki to work on a single machine (tested with Mac OS X 10.6.2 Client). For demonstration purposes, we’ll be deploying Firefox. This is useful for testing, but is not recommended for production use.

8 Server Setup

  1. Turn on Web Sharing
  2. Check System Preferences -> Sharing -> Web Sharing
  3. Download and install Munki Package
  4. Create server directory structure
  5. Open Terminal.app
  6. cd
  7. mkdir Sites/munki Sites/munki/catalogs Sites/munki/manifests Sites/munki/pkgs Sites/munki/pkgsinfo
  8. Copy Firefox disk image to Sites/munki/pkgs
  9. Give webserver permission to read disk image
  10. `chmod 644 Sites/munki/pkgs/[1. Create pkginfo file for package
  11. /usr/local/munki/makepkginfo Sites/munki/pkgs/[NAME_OF_DISK_IMAGE](NAME_OF_DISK_IMAGE]) > Sites/munki/pkgsinfo/[1. Create catalog
  12. /usr/local/munki/makecatalogs Sites/munki
  13. Create a testing manifest at Sites/munki/manifests/testing. (Be careful about the name of the manifest file – for this example we’re naming it “testing” with no filename extension.)
    3a18f66e57c114e5d5346e2ff484c45e

9 Client Setup

  1. Edit /Library/Preferences/!ManagedInstalls.plist
  2. Set !ClientIdentifier to testing
  3. Set SoftwareRepoURL to http://localhost/~USERNAME/munki where USERNAME is the short name of your user account.

It might be easiest to use the defaults command for this:

defaults write /Library/Preferences/ManagedInstalls ClientIdentifier testing
defaults write /Library/Preferences/ManagedInstalls SoftwareRepoURL http://localhost/~USERNAME/munki

10 Running the Client Tools

  1. sudo /usr/local/munki/managedsoftwareupdate <br>- or -<br>
  2. Launch /Applications/Utilities/Managed Software Update.app

11 Updating Software

==On the Server==

  1. Copy new version of Firefox disk image to Sites/munki/pkgs
  2. Create pkginfo file for new package
  3. /usr/local/munki/makepkginfo ~/Sites/munki/pkgs/[NAME_OF_DISK_IMAGE](NAME_OF_DISK_IMAGE].pkginfo) > ~/Sites/munki/pkgsinfo/[NAME_OF_DISK_IMAGE].pkginfo`
  4. Create catalog
  5. /usr/local/munki/makecatalogs ~/Sites/munki
    ==On the Client==
  6. Launch /Applications/Utilities/Managed Software Update.app

12 More info

For a more in-depth introduction to Munki, see these !MacTech articles:

http://www.mactech.com/articles/mactech/Vol.26/26.10/2610MacEnterprise-ManagingSoftwareInstallswithMunki/index.html<br>
http://www.mactech.com/articles/mactech/Vol.26/26.11/2611MacEnterprise-ManagingSoftwareInstallswithMunki-Part2/index.html<br>
http://www.mactech.com/articles/mactech/Vol.26/26.12/2612MacEnterprise-ManagingSoftwareInstallswithMunki-Part3/index.html<br>
http://www.mactech.com/articles/mactech/Vol.27/27.01/2701MacEnterprise-ManagingSoftwareInstallswithMunki-Part4/index.html

12.0.0.1 A collection of known issues and workarounds

12.0.0.1.1 Managed Software Center cosmetic issues under Yosemite

Managed Software Center has some cosmetic display issues in the toolbar under Yosemite. Some elements will sometimes draw without a background, and the available update count badge when displayed sometimes causes the Updates icon to be drawn scaled-down. See https://github.com/munki/munki/issues/378

12.0.0.1.2 curl, client certificates and Mavericks+

Starting with OS X Mavericks, the Apple-supplied curl uses Apple’s SecureTransport instead of OpenSSL for its support of server and client certificates. See: https://www.afp548.com/2013/11/18/coping-with-curl-on-mavericks/

These issues affect Munki versions prior to 2.1. In Munki 2.1, the reliance on curl was removed.

13 Introduction and Background

Munki has four LaunchDaemons which support functions that require root privileges, and three LaunchAgents for all things visible in the GUI. In this document we will break down all seven of those bundled files and describe how they operate. launchd jobs are similar to a hybrid bewteen cron jobs and init scripts or scheduled tasks; they wrap processes. More background on launchd itself can be found here (Apple’s canonical overview, somewhat out of date as of Yosemite), in the man pages, and on third party websites for utilities like Lingon and LaunchControl.

13.1 Stopping Munki from Running

The most common task one may be trying to accomplish when consulting this document is how to disable the (roughly) hourly background checks that Munki makes. launchctl is the tool which manipulates launchd jobs, and since that particular task is in the root context, you can disable it (if you have rights to sudo on the local machine) with sudo /bin/launchctl unload -w /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist
The -w flag is optional, but including it means Munki won’t run in the background even after a reboot.

13.1.1 Notes Regarding Hosting / Naming

A general thing to note is that the naming of the files and their associated job labels reflect the previous hosting of the Munki project on Google Code, but it is now hosted solely on GitHub. Likewise, you will see references to a ‘managedsoftwareupdate’ tool, which is the primary command-line complement of the Managed Software Center application.

13.1.1.0.1 /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-install.plist

When the client running Managed Software Center.app has cached updates that require user notification, or the end user has selected an item they wish to install from the offered Optional Installs, the mechanism that allows the app to run as the root user so it may perform system-wide actions is controlled by the managedsoftwareupdate-install launchdaemon. It checks for the existence of a trigger file at /private/tmp/.com.googlecode.munki.managedinstall.launchd, at which point the previously described supervisor utility runs managedsoftwareupdate with the --installwithnologout option. This is also ‘wired-up’ to the ‘Install’ button found under the Updates tab when there are waiting updates already queued or otherwise actions ready to be performed.


13.1.1.0.2 /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-manualcheck.plist

Similar to the above, a trigger file /private/tmp/.com.googlecode.munki.updatecheck.launchd can be placed by the Managed Software Center app to perform an on-demand check in with the configured Munki server for updates to the clients manifest. Installations will not be performed, but otherwise the ‘Check Again’ button under the Updates tab can initiate this functionality until its state changes to ‘Install’.

14 LaunchAgents

14.0.0.0.1 /Library/LaunchAgents/com.googlecode.munki.ManagedSoftwareCenter.plist

If a background check finds an action requiring user notification should be performed, it needs to open the app in the users context. It uses a trigger file located at /var/run/com.googlecode.munki.ManagedSoftwareCenter.plist to perform this action, with specific checks so we’re sure who the current user is even if FastUserSwitching might be in use.

14.0.0.0.2 /Library/LaunchAgents/com.googlecode.munki.MunkiStatus.plist

And finally, what actually displays status over the loginwindow and provides feedback to users so they know to hold off on logging in is an app that covers the login window while actions are being performed. It is called MunkiStatus, and is nested in Managed Software Center.app in Contents/Resources. The job that triggers it uses the same three paths as the previous com.googlecode.munki.managedsoftwareupdate-loginwindow.plist, but also with a dedicated

  • /var/run/com.googlecode.munki.MunkiStatus trigger file.
    Information on Munki’s support for querying for available license seats for uninstalled optional_installs

14.0.1 Introduction

Beginning with the 0.9.1 builds of the munki tools, Munki can query a webserver to determine if there are available seats for licensed software (or any software you wish to make available via optional_installs, yet control the number of deployed copies).

14.0.2 Details

14.0.2.1 What’s needed

  • Client running munkitools 0.9.1.x or later
  • Web service that is tracking available seats and that provides information in a specific format in response to queries. One such server is MunkiWebAdmin as of 16 July 2013.

If you have a running instance of MunkiWebAdmin, make sure you’ve updated to the latest code.
See this post: https://groups.google.com/d/msg/munki-web-admin/rofv6CiYNto/MzwvP3CGEFIJ for basic info on entering license seat info in MunkiWebAdmin.

Once you have MWA functioning with license seat tracking, and you’d updated one or more clients to 0.9.1.x, you’ll need to tell the client(s) where to ask for license info. This is stored in Munki’s preferences in LicenseInfoURL:

% defaults read /Library/Preferences/ManagedInstalls LicenseInfoURL
http://mwa:8444/licenses/available/

You must mark the pkginfo for any licensed item]to say “this one has licensed seat info on the server”. Only uninstalled optional installs with this key will be checked for available licensed seats; if there is no response from the server, we act as though the number of available seats is zero.

<key>licensed_seat_info_available</key>
<true/>

14.0.2.2 How does this work?

During a managedsoftwareupdate run that includes checking with the server for updates, if there are any uninstalled optional_installs that have licensed_seat_info_available=true Munki crafts one or more queries of the form:

LicenseInfoURL?name=ItemOne&name=ItemTwo&name=ItemThree

where LicenseInfoURL is the license info URL (for MunkiWebAdmin, that’s something like http://mwaserver/licenses/available/) and ItemOne, ItemTwo and ItemThree are names of pkginfo items.

The server then looks up license seat info for ItemOne, ItemTwo and ItemThree and responds with a plist:

% curl "http://mwa:8444/licenses/available/?name=MicrosoftOffice2008&name=MicrosoftOffice2011&name=FooBarBaz"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>MicrosoftOffice2008</key>
    <false/>
    <key>MicrosoftOffice2011</key>
    <true/>
</dict>
</plist>

The returned plist should contain key/value pairs, where the key is the item name and the value is a boolean: true if there are available seats, false otherwise. If the server has no information for an item (as is the case for item “FooBarBaz”) it is acceptable to return nothing. A request and response for only “FooBarBaz” looks like this:

% curl "http://mwa:8444/licenses/available/?name=FooBarBaz"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

The returned results are recorded in /Library/Managed Installs/InstallInfo.plist. Any optional_installs item with license seat info gets a new key – licensed_seats_available:

<dict>
    <key>description</key>
    <string>Installs Adobe Photoshop CS5 and related components.</string>
    <key>display_name</key>
    <string>Adobe Photoshop CS5</string>
    <key>installed</key>
    <false/>
    <key>installed_size</key>
    <integer>1028875</integer>
    <key>installer_item_size</key>
    <integer>1028875</integer>
    <key>licensed_seats_available</key>
    <true/>
    <key>name</key>
    <string>AdobePhotoshopCS5</string>
    <key>uninstallable</key>
    <true/>
    <key>version_to_install</key>
    <string>12.0.0.0.0</string>
</dict>

When Managed Software Update is displaying Optional Software, any item with a licensed_seats_available key equal to false will have its checkbox greyed out, preventing a user from selecting it for install. Additionally, the Status column will read “No available licensed seats”.

Note that there is no explicit mechanism for a client to notify the server that it has installed an item (or will install an item). Instead, the client submits an updated ApplicationInventory.plist to the server. The server uses this information to determine the number of installed seats. (A server other than MunkiWebAdmin is free to use some other method to determine the number of installed seats.)

15 Localization Maintainers.

15.1 Localizations and their Maintainers

  • Danish - originally by Thomas Tvegaard
  • Dutch - Pepijn Bruienne
  • Finnish - originally by Hannes Juutilainen
  • French - originally by Claude Perrin
  • German - originally by Martin R. Hufsky; recent updates by Steve Kueng
  • Norwegian - originally by Frank Paul Silye
  • Russian - Rostislav Soldatenko
  • Spanish - Noel Alonso, Erik Gomez
    Logger Pro comes as a password-protected .dmg.

To get it into your Munki repo, just use the password you got from Vernier to get to the .pkg on the disk image, and then run munkiimport on the .pkg.

Install Logger Pro on a client machine and run makepkginfo -f /Applications/Logger\ Pro\ 3/Logger\ Pro.app (or whatever the relevant path is) and then paste the installs array into the pkginfo for Logger Pro. The installs array will prevent the Logger Pro item from getting into an endless install loop.

Here’s an example of what that installs array might look like:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.vernier.loggerpro</string>
            <key>CFBundleName</key>
            <string>Logger Pro</string>
            <key>CFBundleShortVersionString</key>
            <string>3.11</string>
            <key>CFBundleVersion</key>
            <string>3.11</string>
            <key>path</key>
            <string>/Applications/Logger Pro 3/Logger Pro.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Logging user actions in Managed Software Update GUI

15.1.1 Introduction

One can enable exact logging of user actions in the Managed Software Update (MSU) GUI app. This can help to verify that various events within the GUI are occuring, e.g.

  • When did a user last see a popup notification to update?
  • Did a user choose to install updates, or defer until later?
  • Did the user see available Apple updates?
  • Are available optional software choices being reviewed?

With MSU logging the Munki admin can determine these facts.

15.1.2 Enable Logging

By default logs are disabled. To enable MSU logging, set the key MSULogEnabled to True in ManagedInstalls.plist on Munki clients:

sudo defaults write /Library/Preferences/ManagedInstalls MSULogEnabled -bool TRUE

Additional debug logging about internal actions in Managed Software Center can be obtained by setting another key:

sudo defaults write /Library/Preferences/ManagedInstalls MSUDebugLogEnabled -bool TRUE

15.1.3 Log Location and Format

Logs are written to the directory:

/Users/Shared/.com.googlecode.munki.ManagedSoftwareUpdate.logs/

Multiple log files may exist in this directory. Each user who runs MSU will have 1 or more log files written. By default the log filename will be “username.log”, however if permissions problems occur additional log files will be written with random suffixes. This is done to avoid potential security problems due to the global writable nature of /Users/Shared/.

The log file consists of one text representation of a log event after another, separated by newlines.

float_timestamp INFO username : @@source:event@@ description

e.g.
1300743459.788060 INFO user : @@MSU:appleupdates@@

Note that log files are opened, written to, and closed upon each single log event write, even during one MSU application instance. Therefore external third party tools to roll or process logs should not have much problem with dangling open files, etc.

15.1.4 Log Event Properties

Each log event has 4-5 properties:

  • Timestamp at which the item was written
  • Username of the logged in user
  • Source of the event (source)
  • Event name (event)
  • Optional descriptive text (desc) to supply more detail.

The following table describes source/event pairs in more detail:

<table>
<tr><th>source</th><th>event</th><th>desc</th><th>Description</th></tr>
<tr><td>MSU</td><td>launched</td><td></td><td>MSU launched and presented the initial GUI window to interact with the user.</td></tr>
<tr><td>MSU</td><td>exit_munkistatus</td><td></td><td>This MSU instance launched only to present a status window, and now it is exiting.</td></tr>
<tr><td>MSU</td><td>exit_installwithnologout</td><td></td><td>MSU is now exiting after being told to install without logout.</td></tr>
<tr><td>MSU</td><td>no_updates</td><td></td><td>MSU was started manually but no updates are available.</td></tr>
<tr><td>MSU</td><td>cant_update</td><td>cannot contact server</td><td>Underlying munki cannot contact the server, therefore updates cannot occur (and MSU is reporting this).</td></tr>
<tr><td>MSU</td><td>cant_update</td><td>failed preflight</td><td>Underlying munki tried to run managedsoftwareupdate, preflight failed, therefore updates cannot occur.</td></tr>
<tr><td>MSU</td><td>conflicting_apps</td><td>(application names)</td><td>An application could not be installed because conflicting apps in (desc) are running. The user was told to quit these apps.</td></tr>
<tr><td>MSU</td><td>cannot_start</td><td></td><td>Total configuration problem preventing managedsoftwareupdate from running.</td></tr>
<tr><td>MSU</td><td>appleupdates</td><td></td><td>Available Apple Software Update packages were presented to the user.</td></tr>
<tr><td>user</td><td>cancelled</td><td></td><td>User was given the choice, after deciding to install packages, to optionally install with logout, or just stay logged in and perform the install. Instead of picking an install action, the user hit “cancel” and did not complete the choice, thus aborting the install.</td></tr>
<tr><td>user</td><td>exit_later_clicked</td><td></td><td>The user clicked the “later” button and deferred installation of available packages until next MSU run.</td></tr>
<tr><td>user</td><td>install_with_logout</td><td></td><td>The user selected the “install and logout” option.</td></tr>
<tr><td>user</td><td>install_without_logout</td><td></td><td>The user selected the “install without logout” option.</td></tr>
<tr><td>user</td><td>quit</td><td></td><td>MSU is exiting after doing nothing, either because of errors (like MSU:cant_update) or because no updates were available to install.</td></tr>
<tr><td>user</td><td>view_optional_software</td><td></td><td>User clicked the View Optional Software button.</td></tr>
</table>

15.1.5 Log Growth Behavior

Once logs are enabled, the logs will be written to at any point where the MSU GUI generates an event. It is up to the Munki admin to process these logs in some way, and also to roll them away and/or clean them up.

One potential place to perform log harvesting and cleanup would be in a preflight or postflight script.
Documentation for makecatalogs tool

15.1.6 Details

Usage: /usr/local/munki/makecatalogs [[/path/to/repo](options])

Options:

-h, --help            show this help message and exit
-V, --version         Print the version of the munki tools and exit.

This tool scans the repo/pkgsinfo directory and builds catalogs from the pkginfo files.

You should run this after any change to pkginfo items to update all catalogs. munkiimport will offer to run this for you after a successful import.

/path/to/repo is optional if you have configured the path to the Munki repo using munkiimport --configure or manifestutil --configure. If this value is absent, the value stored in ~/Library/Preferences/com.googlecode.munki.plist will be used.

The pkgsinfo subdirectory must exist and be readable; the catalogs subdirectory must exist and be writable.
Details on using Managed Preferences to configure munki clients.

15.1.7 Introduction

The Munki tools support configuration profile (or MCX) management of the Munki configuration.

Munki 3.1 new feature <p/> managedsoftwareupdate has a new --show-config option, which will print Munki’s current configuration. This can be helpful when troubleshooting the potentially confusing interaction between different preference levels and managed preferences.

15.1.8 Details

Since Munki preferences are not user-level preferences, it probably makes the most sense to manage these at the Computer or ComputerGroup level with MCX, or as a Device Profile when using Configuration Profiles.

Do not manage the following preferences, or you may see unexpected/undesired behavior:

  • InstalledApplePackagesChecksum
  • LastAppleSoftwareUpdateCheck
  • LastCheckDate
  • LastCheckResult
  • LastNotifiedDate
  • OldestUpdateDays
  • PendingUpdateCount

ManagedInstalls keys defined as Managed Preferences take precedence over the same key defined in /var/root/Library/Preferences/ManagedInstalls.plist and /Library/Preferences/ManagedInstalls.plist.

Managed Software Update.app (Munki 1 only) contains an MCX manifest ready for import by Workgroup Manager. This is not included in Munki 2 or 3, but the MCX manifest can be downloaded from ManagedInstalls.manifest on Munki1 branch of the repository.
Introduction to Managed Software Center

15.1.9 Introduction

Managed Software Center was introduced in Munki 2.

It features a new, customizable, App Store-like user interface, replacing Managed Software Update.

Optional installs are now front-and-center. Instead of being buried in a hard-to-notice list, they are now the first thing your users see when launching Managed Software Center. Take user empowerment and self-service to the next level by making more items available for self-install.


How to manage local administrative rights for users and groups with Munki.

15.1.10 Introduction

There is a simple way to manage users and groups who need local admin rights on specific client machines or groups of client machines using Munki.

Benefits of managing local admin rights using this method:

  • Faster: Add and remove users and groups to and from the local admin group on machines in an automated-fashion.
  • Secure: Ability to track and audit who has admin rights on machines, and remove those rights if necessary.

15.1.11 Details

We are going to create a script that will do a few things. It will either add a user or a group to the local admin group on a machine. The script will then create an uninstall script and place it on the target system. This script can then be called by Munki to remove the user’s or group’s admin rights from the machine. The script will also create a file that Munki will use to check if the package is installed.

Steps:

  1. Create a postflight script for a package that will be installed using Munki. This is the script I made that you can use or modify if you deem it necessary:

    #!/bin/sh
    
    # (c) 2010 Walter Meyer SUNY Purchase College
    # Add a user or group to the administrators group on a workstation in a "Munki-Friendly" way.
    
    # Change one variable, either the USER or GROUP that you want to give administrative rights to.
    # Make sure to leave one variable empty depending on whether you are adding a user or group.
    USER="some.user"
    GROUP=""
    
    # Create a directory to store the files we will need.
    /bin/mkdir -p /Library/Scripts/Administrative-Rights
    
    # Add the USER or GROUP to the local admin group.
    if [ -n "${USER}" ]; then
        /usr/sbin/dseditgroup -o edit -n /Local/Default -a $USER -t user admin
    
        # Create a file based on what user or group is getting admin rights that Munki can checksum.
        /bin/echo "$USER" > /Library/Scripts/Administrative-Rights/granted-admin-rights_$USER
    
        # Create script that can be used by Munki to remove the user from the admin group.
        uninstall_script="/Library/Scripts/Administrative-Rights/remove-admin-rights_$USER.sh"
        /bin/echo "#!/bin/sh" > "$uninstall_script"
        /bin/echo "/usr/sbin/dseditgroup -o edit -n /Local/Default -d $USER -t user admin" >> "$uninstall_script"
        /bin/echo "/usr/bin/srm /Library/Scripts/Administrative-Rights/granted-admin-rights_$USER" >> "$uninstall_script"
        /bin/echo "/usr/bin/srm /Library/Scripts/Administrative-Rights/remove-admin-rights_$USER.sh" >> "$uninstall_script"
        /bin/echo "exit 0" >> "$uninstall_script"
    else
        /usr/sbin/dseditgroup -o edit -n /Local/Default -a $GROUP -t group admin
    
        # Create a file based on what user or group is getting admin rights that Munki can checksum.
        /bin/echo "$GROUP" > /Library/Scripts/Administrative-Rights/granted-admin-rights_$GROUP
    
        # Create script that can be used by Munki to remove the user from the admin group.
        uninstall_script="/Library/Scripts/Administrative-Rights/remove-admin-rights_$GROUP.sh"
        /bin/echo "#!/bin/sh" > "$uninstall_script"
        /bin/echo "/usr/sbin/dseditgroup -o edit -n /Local/Default -d $GROUP -t group admin" >> "$uninstall_script"
        /bin/echo "/usr/bin/srm /Library/Scripts/Administrative-Rights/granted-admin-rights_$GROUP" >> "$uninstall_script"
        /bin/echo "/usr/bin/srm /Library/Scripts/Administrative-Rights/remove-admin-rights_$GROUP.sh" >> "$uninstall_script"
        /bin/echo "exit 0" >> "$uninstall_script"
    fi
    
    # Permission the directory properly.
    /usr/sbin/chown -R root:admin /Library/Scripts/Administrative-Rights
    /bin/chmod -R 700 /Library/Scripts/Administrative-Rights
    
    exit 0
  2. Make a package that contains the postflight script. I recommend using The Luggage to build the package, but you don’t have to. http://wiki.github.com/unixorn/luggage/

  3. Add the package to munki and run makepkginfo on the package you made.

  4. Install the package on a test workstation. Then run the following command (if you used my script):

    makepkginfo -f /Library/Scripts/Administrative-Rights/granted-admin-rights_some.user

Take the installs key information and append it to your pkginfo file you created.

  1. Next change the uninstall_method key in the pkginfo file to look
    like this:

        <key>uninstall_method</key>
        <string>/Library/Scripts/Administrative-Rights/remove-admin-rights_some.user.sh</string>

    Using Munki to manage configuration profiles

15.1.12 Introduction

Since version 2.2, Munki offers “native” support for configuration profiles. Instead of having to wrap a configuration profile in a package to be able to deploy with Munki, Munki supports configuration profiles as an item it knows how to install and remove without “wrapping”.

15.1.13 Limitations

Munki manages system-level configuration profiles, as it runs as root. Enrollment profiles, for configuring the computer to be managed by an MDM server, are not supported.

15.1.14 Details

Use munkiimport /path/to/some.mobileconfig to import a .mobileconfig file into your Munki repo. Like a package, munkiimport will create a pkginfo file, add it to your pkginfo directory, and import the .mobileconfig file into the pkgs directory.

Configuration profiles should use the pkginfo key install_type with value profile to specify that Munki should use the /usr/bin/profiles command to install the profile. Likewise, an uninstall_method of remove_profile specifies that Munki should use profiles to remove the profile as well.

Upon installing a configuration profile, Munki writes a receipt to the client’s Managed Installs directory. Note, this is not the same as the OS X installer package receipts database. When removing a profile, Munki will remove this receipt.

The profiles command will replace an existing profile with a new profile if the profiles share an identifier. Therefore, the profile’s identifier value is used for determining identity. The UUID is not considered.

You can treat a profile item in manifests as you would any other piece of software – you can add it to managed_installs, managed_uninstalls, optional_installs, etc.

If you need to update a profile, be sure to keep the identifier the same and bump the version number in the pkginfo. Do not attempt to use the PayloadVersion key inside the profile itself to track your internal version info – that refers to the version of the configuration profile format – which to date, is always 1.

15.1.15 How Munki Determines if a Profile Should be Installed

When examining whether to install a profile, Munki considers several conditions. If any of these conditions are false, Munki will try to install the profile.

Munki considers the following conditions, in this order:

  1. Is the profile’s identifier in the output of profiles -C?

Every profile has an identifier, with a recommended value of a reverse-domain name uniquely identifying the profile. (e.g. com.myorganization.SoftwareUpdateSettings). Munki will compare the profile it is considering installing with the results of profiles -C to see if there is a match. For this reason, updates to an existing profile must use the same identifier (but a different version) to be considered for installation.

  1. Is there a receipt for this profile identifier?

Even if a profile has been manually installed, without a profile receipt, Munki will install the profile.

  1. Does the hash of this profile match the receipt’s hash_value match?

The hash value is generated by feeding the .mobileconfig file through a sha256 hashing algorithm. The hash is not based on the identifier, nor the UUID.

  1. Does the ProfileInstallDate from the profile’s receipt match the ProfileInstallDate specified by profiles -C?

In the event that these dates differ, even thought the identifier and hash match, Munki will install the profile.
How to add, remove, and manage printers with Munki.

15.1.16 Introduction

Why add and remove printers using Munki? Why not just use MCX/Profiles?

One major issue with managing printer lists with MCX or Profiles is if the driver file isn’t installed on the client system prior to the printer, the printer will be added using the Generic Printer Driver. Even if the printer driver file is installed later the printer continues to use the Generic Printer Driver. Using Munki, the administrator can make the drivers be required to be installed ahead of time.

15.1.17 Automated Scripts Method

Graham Gilbert has created a script to automate this for the Munki administrator. printer-pkginfo can be found here.

  1. Download the zip file, and uncompress it.
  2. Modify example .plist file to include your version number, name, queue name, display name, path to driver file, cosmetic location, address, and any required pkgs for Munki to install prior to the printers.
  3. In Terminal navigate to the directory housing the python script ./printer-pkginfo --plist /PATH/TO/example-hp4100.plist -> PATH/TO/example_pkginfo-1.0.plist.
  4. Run makecatalogs.

Nick McSpadden has also created a similar script, PrinterGenerator, that leverages the “nopkg” method described below.

  1. PrinterGenerator accepts command line options, or a path to a CSV file that lists all the necessary fields for your printers.
  2. Use PrinterGenerator to produce your .pkginfo files: ./printer_generator.py --csv /PATH/TO/printers.csv
  3. Copy your pkginfo files into your Munki repository, somewhere in your munki/pkgsinfo/ directory.
  4. Run makecatalogs.

15.1.18 nopkg Method

As of Munki 0.8.3.1634, there is now a “nopkg” type for package-free installation. This allows us to run scripts directly in Munki without having to create packages to install. We can use this “nopkg” type to run all of our printer installs from Munki pkginfos, which allows for easy editing in the future.

There are some pros and cons to this approach, but here’s the method.

15.1.18.1 Concepts Behind Installing Printers Using nopkg

Normally, when installing packages with Munki, we check receipts or installs arrays to determine whether an install/update is necessary. Payload-free packages don’t leave receipts, so we’d use an installs array. With nopkg, we can’t use receipts because no packages are being installed, so we have to have the logic take place in an installcheck_script instead.

We can use the installcheck_script to determine:

  1. Does the printer currently exist on the system?
  2. Do the current options of the printer match our specified set of options?

From there, the postinstall_script can actually make the necessary changes by removing any existing matching printer queue and then adding it, with all specified options.

Lastly, the uninstall_script makes it easy to delete the queue by using lpadmin -x.

15.1.18.2 How the “nopkg” Pkginfo Works

1) The installcheck_script should check the options of the printer. Note that we don’t have to separately call lpstat to determine if the printer is installed, because lpoptions will exit non-zero if the print queue name doesn’t exist. If you have no printer options to specify, just leave the printerOptions dictionary empty:

#!/usr/bin/python
import subprocess
import sys

printerOptions = { }

cmd = ['/usr/bin/lpoptions', '-p', 'PRINTERNAME', '-l']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpoptOut, lpoptErr) = proc.communicate()

if lpoptErr:
    sys.exit(0)

for option in lpoptOut.splitlines():
    for myOption in printerOptions.keys():
        optionName = option.split("/", 1)[0]
        optionValues = option.split("/",1)[1].split(":")[1].strip().split(" ")
        for opt in optionValues:
            if "*" in opt:
                actualOptionValue = opt.replace('*', '')
                break
        if optionName == myOption:
            if not printerOptions[myOption] == actualOptionValue:
                sys.exit(0)
                
sys.exit(1)

2) The postinstall_script is where the print queue is installed. If it already exists, remove it first and then reinstall:

#!/usr/bin/python
import subprocess
import sys

# Populate these options if you want to set specific options for the printer. E.g. duplexing installed, etc.
printerOptions = { OPTIONS }

cmd = [ '/usr/sbin/lpadmin', '-x', 'PRINTERNAME' ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminxOut, lpadminxErr) = proc.communicate()

# Install the printer
cmd = [ '/usr/sbin/lpadmin',
        '-p', 'PRINTERNAME',
        '-L', 'LOCATION',
        '-D', 'DISPLAY_NAME',
        '-v', 'lpd://ADDRESS',
        '-P', '/Library/Printers/PPDs/Contents/Resources/DRIVER',
        '-E',
        '-o', 'printer-is-shared=false',
        '-o', 'printer-error-policy=abort-job' ]

for option in printerOptions.keys():
    cmd.append("-o")
    cmd.append(str(option) + "=" +  str(printerOptions[option]))

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminOut, lpadminErr) = proc.communicate()

if lpadminErr:
    print "Error: %s" % lpadminErr
    sys.exit(1)
print "Results: %s" % lpadminOut    
sys.exit(0)

3) The uninstall_script is very simple:

#!/bin/bash
/usr/sbin/lpadmin -x PRINTERNAME

4) The complete pkginfo looks more like this:

<?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>DESCRIPTION</string>
    <key>display_name</key>
    <string>DISPLAY_NAME</string>
    <key>installcheck_script</key>
    <string>#!/usr/bin/python
import subprocess
import sys

printerOptions = { OPTIONS }

cmd = ['/usr/bin/lpoptions', '-p', 'PRINTERNAME', '-l']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpoptOut, lpoptErr) = proc.communicate()

if lpoptErr:
    sys.exit(0)

for option in lpoptOut.splitlines():
    for myOption in printerOptions.keys():
        optionName = option.split("/", 1)[0]
        optionValues = option.split("/",1)[1].split(":")[1].strip().split(" ")
        for opt in optionValues:
            if "*" in opt:
                actualOptionValue = opt.replace('*', '')
                break
        if optionName == myOption:
            if not printerOptions[myOption] == actualOptionValue:
                sys.exit(0)
                
sys.exit(1)</string>
    <key>installer_type</key>
    <string>nopkg</string>
    <key>minimum_os_version</key>
    <string>10.7.0</string>
    <key>name</key>
    <string>AddPrinter-PRINTERNAME</string>
    <key>postinstall_script</key>
    <string>#!/usr/bin/python
import subprocess
import sys

# Populate these options if you want to set specific options for the printer. E.g. duplexing installed, etc.
printerOptions = { OPTIONS }

cmd = [ '/usr/sbin/lpadmin', '-x', 'PRINTERNAME' ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminxOut, lpadminxErr) = proc.communicate()

# Install the printer
cmd = [ '/usr/sbin/lpadmin',
        '-p', 'PRINTERNAME',
        '-L', 'LOCATION',
        '-D', 'DISPLAY_NAME',
        '-v', 'lpd://ADDRESS',
        '-P', '/Library/Printers/PPDs/Contents/Resources/DRIVER',
        '-E',
        '-o', 'printer-is-shared=false',
        '-o', 'printer-error-policy=abort-job' ]

for option in printerOptions.keys():
    cmd.append("-o")
    cmd.append(str(option) + "=" +  str(printerOptions[option]))

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminOut, lpadminErr) = proc.communicate()

if lpadminErr:
    print "Error: %s" % lpadminErr
    sys.exit(1)
print "Results: %s" % lpadminOut    
sys.exit(0)</string>
    <key>unattended_install</key>
    <true/>
    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/bash
/usr/sbin/lpadmin -x PRINTERNAME</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>VERSION</string>
</dict>
</plist>

This pkginfo makes it an unattended_install, which means it’ll trigger even if a user is logged in, without requiring the GUI to activate. It’s also an unattended_uninstall, so it can also be removed without user intervention.

The important parts to change:

  • DESCRIPTION - This is the cosmetic description in Munki.
  • DISPLAY_NAME - The name that users see in Managed Software Center.
  • PRINTERNAME - This is the name of the print queue itself.
  • VERSION - The version number of the pkginfo. When updating this pkginfo, make sure you update the version accordingly, for your own sanity.
  • LOCATION - The location of the printer as displayed in the System Preferences.
  • ADDRESS - The IP or DNS address of the printer to add.
  • DRIVER - The name of the driver file used for this printer.
  • OPTIONS - A dictionary of options to configure the printer with on creation. Since this is a Python dictionary, it should look like “HPOptionDuplexer”:“True” for each option you want to specify, comma-separated. See the section below for more details.

5) Throw your pkginfo into your Munki repo and run makecatalogs. Add it to a manifest, and test it out!

15.1.18.3 Pros & Cons to the nopkg Approach

The advantage to using the nopkg method is that all of your logic is being done in the pkginfo directly. To make any changes to the process simply involves editing the pkginfo. You don’t have to rebuild packages when you make these changes.

This solution offers a bit more flexibility than rebuilding packages, because there’s no intermediate step between making changes and seeing results on end clients.

The disadvantage is that your printer installation is tethered to Munki compatibility only. If you built standard Apple packages, you could optionally use any tool that supports package installation to install these printers - ARD, Casper, even a thumb drive and double clicking and going through Installer.app. If you have a need to install printers without always being able to use Munki, consider building a package that runs the postinstall-script from above instead.

15.1.18.3.1 An important note about printer drivers and lpadmin

If the printer driver that is specified is not installed at the time lpadmin installs the printer, you won’t see it show up in the Printers pane of the System Preferences. However, you will still see it listed via lpstat or lpinfo - which is why Munki may think the printer is installed, even if your users can’t actually use it.

In other words, it’s important that /Library/Printers/PPDs/Contents/Resources/DRIVER exists before you use lpadmin to install a printer using that driver. You can do this with Munki logic, by adding a “Requires” array and adding your printer driver packages to it, which will guarantee that the printer won’t be installed until after Munki has successfully installed the driver.

15.1.19 How do I find out what options are available to configure the printer with (Duplex, etc.)?

Install the printer in question on your system first.

Then in terminal:

lpoptions -p YOUR_CUPS_PRINTER_QUEUE_NAME -l

This command will output a list of configurable options for your printer.
So if the output is this:

BRMonoColor/Color/Grayscale: *Color Mono
BRSlowDrying/Slow Drying Paper: *OFF ON

You could set the options variables in the above script to look like this:

printerOptions = { "BRMonoColor":"Color", "BRSlowDrying":"OFF" }

15.1.20 Legacy Method using The Luggage to build packages

*Note: The following method uses The Luggage, however any packager can be used.

To install and remove a printer using Munki, do the following:

I. Install The Luggage

  1. Install XCode: http://developer.apple.com/technologies/xcode.html

  2. Install The Luggage: Download: https://github.com/unixorn/luggage/zipball/master

  3. Open Terminal and type:

    cd ~/Downloads/directory_you_extracted_the_luggage_to/
    make pkg
  4. Install the package that was created by the previous command. This installs The Luggage on your system.

II. Prepare the Printer Install Script

  1. Create a postflight script for a package that will be installed using Munki. This simple shell
    script can be modified as necessary:

    #!/bin/sh
    
    # (c) 2010 Walter Meyer SUNY Purchase College
    
    # Script to install and setup printers on a Mac OS X system in a "Munki-Friendly" way.
    # Make sure to install the required drivers first!
    
    # Variables. Edit these.
    printername="SOME_PRINTER_NAME"
    location="SOME LOCATION"
    gui_display_name="HP Color LaserJet 9500N Example"
    address="lpd://printserver.yourcompany.org/SOME_PRINTER_NAME"
    driver_ppd="/Library/Printers/PPDs/Contents/Resources/hp color LaserJet 9500.gz"
    # Populate these options if you want to set specific options for the printer. E.g. duplexing installed, etc.
    option_1=""
    option_2=""
    option_3=""
    
    ### Printer Install ###
    # In case we are making changes to a printer we need to remove an existing queue if it exists.
    /usr/bin/lpstat -p $printername
    if [ $? -eq 0 ]; then
        /usr/sbin/lpadmin -x $printername
    fi
    
    # Now we can install the printer.
    /usr/sbin/lpadmin \
            -p "$printername" \
            -L "$location" \
            -D "$gui_display_name" \
            -v "$address" \
            -P "$driver_ppd" \
            -o "$option_1" \
            -o "$option_2" \
            -o "$option_3" \
            -o printer-is-shared=false \
            -E
    # Enable and start the printers on the system (after adding the printer initially it is paused).
    /usr/sbin/cupsenable $(lpstat -p | grep -w "printer" | awk '{print$2}')
    
    # Create an uninstall script for the printer.
    uninstall_script="/private/etc/cups/printers_deployment/uninstalls/$printername.sh"
    mkdir -p /private/etc/cups/printers_deployment/uninstalls
    echo "#!/bin/sh" > "$uninstall_script"
    echo "/usr/sbin/lpadmin -x $printername" >> "$uninstall_script"
    echo "/usr/bin/srm /private/etc/cups/printers_deployment/uninstalls/$printername.sh" >> "$uninstall_script"
    
    # Permission the directories properly.
    chown -R root:_lp /private/etc/cups/printers_deployment
    chmod -R 700 /private/etc/cups/printers_deployment
    
    exit 0

The script installs a printer based on the variables set at the beginning of the script.

III. Build the Package

The administrator must build a package that contains the postflight script made using The Luggage.

  1. Create a directory where you want the printer installer package to be output to and stored in on your system.

  2. Create a file called ‘Makefile’ in the directory you created. You can use the example Makefile below. Edit the TITLE and the REVERSE_DOMAIN at a minimum.

    #
    #   Copyright 2009 Joe Block <jpb@ApesSeekingKnowledge.net>
    #
    #   Licensed under the Apache License, Version 2.0 (the "License");
    #   you may not use this file except in compliance with the License.
    #       You may obtain a copy of the License at
    #
    #       https://www.apache.org/licenses/LICENSE-2.0
    #
    #   Unless required by applicable law or agreed to in writing, software
    #   distributed under the License is distributed on an "AS IS" BASIS,
    #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #   See the License for the specific language governing permissions and
    #   limitations under the License.
    #
    # 
    #  Luggage makefile for building a package that installs a printer.
    
    include /usr/local/share/luggage/luggage.make
    
    TITLE=SOME_UNIQUE_PRINTER_INSTALLER_NAME
    REVERSE_DOMAIN=com.yourcompany
    PAYLOAD=pack-script-postflight
    PACKAGE_VERSION=1.0
  3. Put the postflight script made earlier in this directory.

  4. Open terminal and navigate to the directory with your Makefile and postflight script. cd /PATH/TO/FILES/

  5. Run this command: make dmg This will create a dmg file, ready for Munki.

IV. Add the dmg to your munki repo

  1. Run makepkginfo on your printer install dmg/package located on your repo.
    E.g:

    makepkginfo /PATH/TO/munki_repo/path_to_your_pkg.dmg > /PATH/TO/munki_repo/path_to_your_pkg.dmg.pkginfo
  2. Next change the uninstall_method key in the pkginfo file to look like so (edit this):

        <key>uninstall_method</key>
    <string>/etc/cups/printers_deployment/uninstalls/your_printername_variable_from_the_postflight_script.sh</string>
  3. Finally add a requires key to the pkginfo file and reference the required driver installation package(s) for the printer (if you haven’t added the printer driver installer(s) to your repo yet do it now). E.g.:

        <key>requires</key>
        <array>
            <string>PRINT_DRIVER_INSTALLER.pkg</string>
        </array>

    Here is an example pkginfo file: http://pastebin.com/uwakXxVH

    <?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>printer_deployments</string>
        </array>
        <key>description</key>
        <string></string>
        <key>display_name</key>
        <string>printserver01_PRINTER01</string>
        <key>installer_item_hash</key>
        <string>5b27f8f3df91798b33b74d858adc293b6cbcd1e5d728e0f48c17c19a42bc4592</string>
        <key>installer_item_location</key>
        <string>printer_deployments/printers/printserver01_PRINTER01-1.1.dmg</string>
        <key>installer_item_size</key>
        <integer>13</integer>
        <key>minimum_os_version</key>
        <string>10.4.0</string>
        <key>name</key>
        <string>printserver01_PRINTER01</string>
        <key>receipts</key>
        <array>
            <dict>
                <key>filename</key>
                <string>printserver01_PRINTER01-1.1.pkg</string>
                <key>installed_size</key>
                <integer>0</integer>
                <key>packageid</key>
                <string>edu.purchase.printserver01_PRINTER01</string>
                <key>version</key>
                <string>1.0</string>
            </dict>
        </array>
        <key>uninstall_method</key>
        <string>/etc/cups/printers_deployment/uninstalls/printserver01_PRINTER01.sh</string>
        <key>uninstallable</key>
        <true/>
        <key>version</key>
        <string>1.0</string>
    </dict>
    </plist>

Specifying options

Install the printer in question on your system first.

Then in terminal:

    lpoptions -p YOUR_CUPS_PRINTER_QUEUE_NAME -l

This command will output a list of configurable options for your printer.
So if the output is this:

    BRMonoColor/Color/Grayscale: *Color Mono
    BRSlowDrying/Slow Drying Paper: *OFF ON

I could set the options variables in the script to look like this:

    option_1="BRMonoColor=Mono"
    option_2="BRSlowDrying=ON"
    option_3=""

Potential Problems:

If a privileged user removes the printer manually, Munki would have no way of knowing that the printer has been removed. Munki is only aware of the printer being installed based on the fact that your package was installed.

If you change the ‘printername’ variable in the script with the intention of changing the CUPS name of a printer that is already installed, this will not work. A new printer will be installed if you try this. If you want to change the CUPS printer name for a printer that is already installed you have to remove the existing printer with Munki first.

Also remember that Munki determines whether a printer package is installed based on the information set in your Makefile you built the package with. If you change the TITLE or REVERSE_DOMAIN and build a package with the intention of modifying an existing install it won’t work! Just iterate the PACKAGE_VERSION from 1.0 to 1.1 or 1.1 to 1.2, etc.

Info about munki manifest files

15.1.21 Introduction

Format of munki manifest files and supported keys

15.1.22 Details

Manifests are essentially just a simple list of the items to install or verify their installation or to remove or verify their removal.

A basic manifest would contain a list of one or more catalogs to be searched for packages, and a list of packages to install. Here’s an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>catalogs</key>
   <array>
      <string>production</string>
   </array>
   <key>managed_installs</key>
   <array>
      <string>Firefox</string>
      <string>Thunderbird</string>
   </array>
</dict>
</plist>

In this example, Munki is told to search the production catalog for Firefox and Thunderbird, and ensure the latest versions of these items are installed. The concept of “catalogs” is an important one. It is possible to have different versions of software available in different catalogs. A very common and powerful configuration is to maintain a “testing” catalog and a “production” catalog. New versions of software are first added to the “testing” catalog. Only a subset of managed machines is configured to use the “testing” catalog, and this subset gets the newer versions of software first. Once you are satisfied there are no major issues with a new version of a piece of software, you can add the new version to the “production” catalog, where the rest of your managed machines will find it and install it.

15.1.22.1 catalogs

The key ‘catalogs’ defines which catalogs to search for the given items. The catalogs are searched in order, but any valid match stops the search, so in the below example, a matching item in the testing catalog would stop the search - the production catalog would not be searched.

    <dict>
        <key>catalogs</key>
        <array>
            <string>testing</string>
            <string>production</string>
        </array>
        <key>managed_installs</key>
        <array>
            <string>ServerAdminTools</string>
            <string>TextWrangler</string>
            <string>Silverlight</string>
        </array>
    </dict>

15.1.22.2 included_manifests

Manifests support references to other manifests (nested manifests):

    <dict>
        <key>catalogs</key>
        <array>
            <string>testing</string>
            <string>production</string>
        </array>
        <key>included_manifests</key>
        <array>
            <string>standard_apps</string>
        </array>
        <key>managed_installs</key>
        <array>
            <string>TextWrangler</string>
        </array>
    </dict>

Where there is a manifest “standard_apps” that contains some, well, standard apps for your users:

    <dict>
        <key>managed_installs</key>
        <array>
            <string>MicrosoftOffice2008</string>
            <string>Firefox</string>
            <string>Thunderbird</string>
        </array>
    </dict>

Included manifests do not need to have a “catalogs” entry (and in most cases, should not include a “catalogs” list) – if this is missing, the catalogs of the parent manifest will be searched.

15.1.22.3 managed_installs

managed_installs contains a list of items you would like to ensure are installed and kept up-to-date:

    <key>managed_installs</key>
    <array>
        <string>MicrosoftOffice2008</string>
        <string>Firefox</string>
        <string>Thunderbird</string>
    </array>

The names here (and for managed_uninstalls, managed_updates and optional_installs) correspond to the values for the “name” key of a pkginfo item. They are case-sensitive.

Think of this list as meaning “These items must be installed and must be kept up-to-date”.

15.1.22.4 managed_uninstalls

You may include a “managed_uninstalls” key:

    <key>managed_uninstalls</key>
    <array>
        <string>ServerAdminTools</string>
        <string>TextWrangler</string>
        <string>Silverlight</string>
    </array>

These items will be checked to see if they’re installed, and removed if possible.

Think of this list as meaning “These items must not be installed”.

15.1.22.5 optional_installs

Manifests may also have an “optional_installs” key:

    <key>optional_installs</key>
    <array>
        <string>GoogleChrome</string>
        <string>GoogleEarth</string>
        <string>GoogleSketchUp</string>
        <string>TextWrangler</string>
    </array>

Optional installs allow administrators to specify packages as available for optional installation, allowing end-users to choose to install and/or remove these items without needing admin privileges themselves.

optional_installs items are checked against the available catalogs and added to the list of optional installs displayed in Managed Software Center.app. Users can then select any of these items for install, or if they are installed, for removal.

managed_installs and managed_uninstalls have higher precedence than optional_installs, so if an item is in either a managed_installs or managed_uninstalls list, it will not be displayed in Managed Software Center.app as an available optional install.

If a user chooses items to install or remove from the list of optional software, the choices are recorded in a locally-generated manifest: “/Library/Managed Installs/manifests/SelfServeManifest”. This manifest inherits its catalogs from the primary manifest (the one pointed to by the ClientIdentifier) and is processed like any other manifest after all of the server-provided manifests have been processed.

15.1.22.6 managed_updates

The value for this key is in the same format as managed_installs. Items in managed_updates are each checked to see if some version of the item is already installed; if so, the item is processed just as if it was in the managed_installs list. You could use managed_updates to tell munki to update software that is not in a managed_installs list; for example, if you have machines that may or may not have Adobe Photoshop CS5 and you do not want to add Adobe Photoshop CS5 to a managed_installs list, but would still like munki to apply any applicable updates, you could add Adobe Photoshop CS5 to the managed_updates list.

An item in a managed_updates list that is scheduled for removal (because it appears in a managed_uninstalls list) will not be processed for updates.

Think of this list as meaning “These items must be kept up-to-date if they happen to be installed”.
This is not the place to put updates for items that are listed in managed_installs. See the update_for key in pkginfo files for how to handle update items.

15.1.22.7 conditional_items

Items can be added to a manifest conditionally. See [[Conditional Items]] for more information.

15.1.22.8 item names

For managed_installs, managed_uninstalls and optional_installs, items are typically referred to by name only, but if you need to specify the install of a specific version, you can append the version number:

    <key>managed_installs</key>
    <array>
        <string>MicrosoftOffice2008</string>
        <string>Firefox-3.0.9</string>
        <string>Thunderbird</string>
    </array>

In the above example, the catalog(s) will be searched for the latest version of MicrosoftOffice2008, version 3.0.9 of Firefox, and the latest version of Thunderbird.

Note that munki generally will not downgrade an existing install from a newer version to an older version, so specifying an older version in the managed_installs list will not downgrade existing installations.

managed_updates should list the item only without a version number.

For managed_installs, managed_uninstalls, optional_installs, and managed_updates, the name used in the manifest will be matched against the “name” field in each item in each catalog listed in the catalogs attribute of the manifest.

15.1.22.9 See Also

https://groob.io/posts/manifest-guide/

15.1.23 Important note

This is a new feature requires Munki version 2.7.0 or greater!

15.1.24 Introduction

This optional feature allows a Munki admin to use third party code, or create their own code to manipulate Munki’s HTTP requests. The primary use case for this feature is to provide interaction with APIs, although it is not limited to that. Middleware is activated by the presence of a Python file. If it’s there it gets called, if it’s not it won’t, it’s as simple as that.

15.1.25 Details

Middleware gets imported at runtime as a Python module so the middleware file must be written in Python. Nothing is stopping you from then calling another executable from Python, so in that sense, you’re not limited to Python.
At the beginning of the Munki run, Munki searches for “middleware*.py“, it then tries to import it then looks for the function,”process_request_options“. The options are then sent through, examined, changed, or not, before heading to the server.

You may only use one middleware file. If you have more then one of middleware file you will have unpredictable results.

15.1.25.1 Requirements

For the middleware to work, you will need the following:

15.1.25.1.1 Filename

Munki is looking for files the start with “middleware” and end with “.py”.
Examples of good and bad middleware filenames:

  • middleware.py👍
  • middleware👎
  • my_middleware.py👎
  • middleware_cloudfoo.py👍
15.1.25.1.2 Location

The middleware file must live in the root of the munkitools folder (/usr/local/munki).

15.1.25.1.3 Permissions

Root must be the owner of the file and be able to read it. Since its imported by python, the executable part isn’t necessary. It’s important to note that if you plan on storing sensitive information inside you should restrict access.

sudo chown root /usr/local/munki/middleware*.py
sudo chmod 600 /usr/local/munki/middleware*.py
15.1.25.1.4 The “process_request_options” function

This is the function that Munki is looking for. Think of it as the “main” fuction for the middleware. If Munki doesn’t find this function it will abandon the middleware, and continue on as if it wasn’t there.

Example function
python def process_request_options(options): print '***Requesting: %s' % options.get('url') return options
This is a basic example: Munki sends the request options, we print the requested url and then return the options unchanged.
process_request_options has a single input parameter: the options dictionary (described in detail below). It must return the options dictionary (possibly modified).

15.1.25.2 Middleware examples

15.1.25.2.1 Query Parameters

Query Params Example

from urllib import urlencode

QUERY_PARAMS={'username': 'apiuser', 'password': 'secret password'}

def encode_params(data):
    """Encode parameters in a piece of data.
    Will successfully encode parameters when passed as a dict or a list of
    2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
    if parameters are supplied as a dict.
    """
    result = []

    for k, vs in QUERY_PARAMS.items():
        if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
            vs = [vs]
        for v in vs:
            if v is not None:
                result.append(
                    (k.encode('utf-8') if isinstance(k, str) else k,
                     v.encode('utf-8') if isinstance(v, str) else v))
    return urlencode(result, doseq=True)


def process_request_options(options):
    url = options.get('url')
    if 'swscan.apple.com' not in url:
        print 'URL Before: %s' % options.get('url')
        #concat url and query string
        options['url'] = options['url'] + '?' + encode_params(QUERY_PARAMS)
        print 'URL After: %s' % options.get('url')
    return options

In the example above we are joining the URL from Munki and query string together.

15.1.25.2.1.1 Before:

http://munki.example.com/catalogs/production

15.1.25.2.1.2 After:

http://munki.example.com/catalogs/production?username=apiuser&password=secret+password

15.1.25.2.2 Headers

Headers Example

HEADERS = {'api_key': '123_IAM_A_KEY', 'api_secret': 'SECRETKEY'}


def process_request_options(options):
    url = options.get('url')
    if 'swscan.apple.com' not in url:
        print 'Headers before: %s' % options['additional_headers']
        # Merge headers with Munki
        options['additional_headers'].update(HEADERS)
        print 'Headers after: %s' % options['additional_headers']
    return options

Since the ‘additional_headers’ key is a dictionary it is easy for us to update retaining the User-Agent and Authorization headers.

15.1.25.2.2.1 Before:

{u'Authorization': u'Basic bXVua2k6WUhuUXhWWFFh==', 'User-Agent': u'managedsoftwareupdate/2.6.1 Darwin/15.4.0'}

15.1.25.2.2.2 After:

{'api_secret': 'SECRETKEY', 'api_key': '123_IAM_A_KEY', u'Authorization': u'Basic bXVua2k6WUhuUXhWWFFh==', 'User-Agent': u'managedsoftwareupdate/2.6.1 Darwin/15.4.0'}

15.1.25.2.3 Available options

These are all the options that can be changed with the middleware. Most of the time you’ll only be interested in the url and the additional_headers

Key Type Description Default Value
url String The ‘url’ you are requesting.
additional_headers Dictionary These are the HTTP headers that are going in the get request. List of HTTP header fields {'User-Agent': u'managedsoftwareupdate/%MUNKI_VER% Darwin/%OS_VER%'}
follow_redirects String Explained here None
resume Boolean If True, Gurl will attempt to resume an interrupted download. _**You should probably leave this alone._ | False |
| download_only_if_changed| Boolean | If destinationpath already exists, you can set ‘onlyifnewer’ to true to indicate you only want to download the file only if it’s newer on the server. _**You should probably leave this alone._ | False |
| cache_data | NSObject | _**Don’t touch this._ ||
| logging_function | Function | The logging function in use. _**You should probably leave this alone._ ||

15.1.26 Middleware modules

Here are some middleware modules to try:

Munki repo on S3 storage: https://github.com/waderobson/s3-auth
Munki repo on Google Cloud storage: https://github.com/waderobson/gcs-auth
Munki repo on CloudFront storage: https://github.com/AaronBurchfield/CloudFront-Middleware
Links and tools of interest to Munki admins

15.1.27 Introduction

Here you’ll find additional links and tools of interest to Munki admins.

<table>
<tr><td>[[Munki Auto-Builds|https://munkibuilds.org]]</td><td>Automatically-generated package builds of current Munki git repo</td></tr>
<tr><td>[[AutoPkg|https://autopkg.github.io/autopkg/]]</td><td>Recipes for downloading and preparing updates for your Munki repo</td></tr>
<tr><td>[[AutoPkgr|https://github.com/lindegroup/autopkgr]]</td><td>AutoPkgr is a free Mac app that makes it easy to install and configure AutoPkg.</td></tr>
<tr><td>[[Reposado|https://github.com/wdas/reposado]]</td><td>Replacement for Apple’s Software Update service; runs on virtually any host OS or hardware</td></tr>
<tr><td>[[MunkiAdmin|https://github.com/hjuutilainen/munkiadmin]]</td><td>Cocoa GUI app for managing a Munki repo</td></tr>
<tr><td>[[munki-in-a-box|https://github.com/tbridge/munki-in-a-box]]</td><td>Script to quickly setup a Munki server, complete with AutoPkg and MunkiAdmin on OS X Server</td></tr>
</table>

15.1.29 Reporting/Web consoles

<table>
<tr><td>[[MunkiReport-PHP|https://github.com/munkireport/munkireport-php]]</td><td>PHP-based reporting console for Munki clients</td></tr>
<tr><td>[[Sal|https://github.com/salopensource/sal]]</td><td>Python-based multi-organization reporting console for Munki clients</td></tr>
<tr><td>[[MunkiWebAdmin2|https://github.com/munki/mwa2]]</td><td>Web-based management interface for Munki. Written in Django (which itself is Python)</td></tr>
<tr><td>[[Moscargo|https://github.com/arubdesu/Moscargo]]</td><td>Helps techs and other savvy folk find the most current version of the software you curate, and makes them available for ad-hoc download.</td></tr>
</table>

15.1.30 Alternate Servers/Backends

<table>
<tr><td>[[Simian|https://github.com/google/simian]]</td><td>Google App Engine-based server for Munki</td></tr>
<tr><td>[[MunkiServer|https://github.com/munkiserver/munkiserver]]</td><td>Ruby-on-Rails Server for Munki</td></tr>
</table>

15.1.31 Discussion Groups/Maillists/IRC/Slack

<table>
<tr><td>[[munki-dev|https://groups.google.com/forum/#!forum/munki-dev]]</td></tr>
<tr><td>[[munki-discuss|https://groups.google.com/forum/#!forum/munki-discuss]]</td></tr>
<tr><td>[[MunkiWebAdmin|https://groups.google.com/forum/#!forum/munki-web-admin]]</td></tr>
<tr><td>[[autopkg-discuss|https://groups.google.com/forum/#!forum/autopkg-discuss]]</td></tr>
<tr><td>[[MacEnterprise|http://lists.psu.edu/archives/macenterprise.html]]</td></tr>
<tr><td>[[MacEnterprise|https://groups.google.com/forum/#!forum/macenterprise]] (read-only archives)</td></tr>
<tr><td>[[##osx-server|http://webchat.freenode.net/?randomnick=1&channels=%23%23osx-server]]</td></tr>
<tr><td>[[#munki on MacAdmins Slack|https://macadmins.herokuapp.com]]</td></tr>
</table>

15.1.32 Additional documentation

<table>
<tr><td>[[Intro to Munki Part 1|http://www.mactech.com/articles/mactech/Vol.26/26.10/2610MacEnterprise-ManagingSoftwareInstallswithMunki/index.html]]</td></tr>
<tr><td>[[Intro to Munki Part 2|http://www.mactech.com/articles/mactech/Vol.26/26.11/2611MacEnterprise-ManagingSoftwareInstallswithMunki-Part2/index.html]]</td></tr>
<tr><td>[[Intro to Munki Part 3|http://www.mactech.com/articles/mactech/Vol.26/26.12/2612MacEnterprise-ManagingSoftwareInstallswithMunki-Part3/index.html]]</td></tr>
<tr><td>[[Intro to Munki Part 4|http://www.mactech.com/articles/mactech/Vol.27/27.01/2701MacEnterprise-ManagingSoftwareInstallswithMunki-Part4/index.html]]</td></tr>
</table>

15.1.33 Mac Admin Conferences

A few conferences are frequented by members of the Munki community
<table>
<tr><td>[[PSU MacAdmins|http://macadmins.psu.edu/]]</td><td>State College, PA</td></tr>
<tr><td>[[MacTech Conference|http://www.mactech.com/conference/about]]</td><td>Los Angeles, CA</td></tr>
<tr><td>[[MacSysAdmin.se|http://macsysadmin.se/]]</td><td>Göteborg, Sweden</td></tr>
<tr><td>[[Mac Admins and Developers UK|http://www.macad.uk]]</td><td>London, England</td></tr>
</table>

15.1.34 Video Resources

Most of the Mac Admin conferences publish their sessions online. These sessions can be a great resource for learning Munki and other tools.
Below are a few relevant munki talks:
<table>
<tr><td>[[Getting Started with Munki|http://cdn.macdevops.ca/MDO2015/greg/NewStandardPlayer.html?plugin=HTML5]]</td><td>Greg Neagle, MacDevOps:YVR 2015</td></tr>
<tr><td>[[What’s New with Munki|https://www.youtube.com/watch?v=kRmWO52i-4Q]]</td><td>Greg Neagle, Penn State MacAdmins 2015</td></tr>
<tr><td>[[Going MAD: From closed-in-box to ready to rock, using Munki, AutoPkg and DeployStudio |https://www.youtube.com/watch?v=UG84nedo4ag&list=UUiRYn1OSRv2bvU3enNwoZxg]]</td><td> Steve Yuroff, Penn State MacAdmins 2013</td></tr>
<tr><td>[[Thin OS X Deployment with Munki |http://youtu.be/uABzxX2KrVw]]</td><td> Matt Willmore & Clarence Helm, Penn State MacAdmins 2013</td></tr>

</table>

15.1.35 Mac Admin Community Groups

<table>
<tr><td>[[Mac Meetups|https://macmeetups.com/]]</td><td>Independent List of Macadmin Meetup Groups</td></tr>
</table>
Suppressing Self-Heal for Acrobat 9 Pro installs.

15.1.36 Introduction

Adding this key to the end of your pkginfo file for Acrobat 9 Pro updates will prevent self-heal from occuring. This is desirable when your end-users are not admins or in a lab environment.

Ideally, this would only run after the most recent Adobe update is installed, but it would be acceptable for it to be included in each and every update.

15.1.36.1 postinstall_script

    <key>postinstall_script</key>
    <string>#!/bin/bash
sed -i .bak 's/\&lt;string\&gt;AcroEFGPro90SelfHeal\.xml\&lt;\/string\&gt;//g' /Applications/Adobe\ Acrobat\ 9\ Pro/Adobe\ Acrobat\ Pro.app/Contents/MacOS/SHInit.xml
sed -i .bak 's/\&lt;string\&gt;AcroEFGDist90SelfHeal\.xml\&lt;\/string\&gt;//g' /Applications/Adobe\ Acrobat\ 9\ Pro/Acrobat\ Distiller.app/Contents/MacOS/SHInit.xml
    </string>

Notes on installing/removing Adobe CS3 apps with Munki

15.1.37 Details

As of the 0.4.7 release of the munki tools, munki now supports installation and removal of Adobe CS3 applications using disk image copies of the CS3 install media and prepared according to Adobe’s documentation here:

http://www.adobe.com/support/deployment/cs3_deployment.pdf

You’ll need to follow Adobe’s instructions for creating the install.xml, uninstall.xml and application.xml.override files.

One possible variation from the Adobe instructions: the install.xml and uninstall.xml files must be saved at the root of the DMG.

Once you’ve created a disk image of the install media and added the xml files, test the install and removal – if they don’t work manually, they won’t work with munki. Testing the silent install is described as Perform a silent install or uninstall in the Adobe CS3 Deployment documentation.

You may optionally create an uninstaller dmg for the product - this is just a copy of the installer dmg minus all of the embedded dmg files in the payloads directory. Be sure to leave the Bootstrapper.dmg alone! An advantage of creating an uninstaller dmg is that is is much smaller (it can be 10% the size of the installer dmg).

makepkginfo can create the needed pkg info for an Adobe CS3 installer dmg. Be aware that since Adobe installer dmgs don’t use the Apple pkg format, there are no receipts. This is important to note since munki needs a way to determine if an item is already installed. With standard Apple packages, munki can just look for the receipts. With Adobe installers, you must add “installs” items to the pkg info, like so:

<key>installs</key>
<array>
    <dict>
        <key>CFBundleIdentifier</key>
        <string>com.adobe.Photoshop</string>
        <key>CFBundleName</key>
        <string>Photoshop</string>
        <key>CFBundleShortVersionString</key>
        <string>10.0</string>
        <key>path</key>
        <string>/Applications/Adobe Photoshop CS3/Adobe Photoshop CS3.app</string>
        <key>type</key>
        <string>application</string>
    </dict>
</array>

These can be generated either when creating the original pkginfo, or later, like so:

makepkginfo -f /Applications/Adobe\ Photoshop\ CS3/Adobe\ Photoshop\ CS3.app

munki can then check for the existence of the “installs” items to tell if the item has been installed.

See [[Munki And Adobe CS4]] for related info.
Notes on using munki with the Adobe CS4 apps

15.1.38 Introduction

Notes and examples on how to use munki to install Adobe CS4 apps without repackaging into Apple installer format.

15.1.39 Details

Using munki with Adobe installer packages requires release 0.4.3 or later of the munki tools.

This is not meant to be a tutorial on the Adobe CS4 Deployment Toolkit; see Adobe’s documentation for more on how to get and use the Toolkit to create deployment ‘packages’.

Note that an Adobe deployment ‘package’ is really closer to an Installer ChoiceChangesXML file, or an !InstallShield “answer file”, in that it tells the installer what to do in an unattended install. You still need to provide the actual installation payloads. Adobe suggests hosting these on an AFP server, or pre-copying them to the target machine. But for use with munki, you’ll want to wrap up the deployment package/packages and the installation payloads into a single disk image.

15.1.39.1 Installing and Uninstalling Adobe CS4 apps

  • Use the CS4 Deployment Toolkit to create your deployment ‘package’:
  • Output is:
    • AdobeUberInstaller
    • AdobeUberInstaller.xml
    • AdobeUberUninstaller
    • AdobeUberInstaller.xml
  • Make note of the total installed size reported by the Toolkit; you’ll probably want to add this to the pkginfo file later.

  • Bundle the deployment package and installation files into a disk image following a very strict format (this is due to a a bug in Adobe’s tools when dealing with disk images).

  • Here is an example disk layout:

  • Adobe Photoshop CS4/ <- top level of DMG; same name as original install DMG volume.
  • AdobeUberInstaller
  • AdobeUberInstaller.xml <- four files output from CS4 Deployment Toolkit
  • AdobeUberUninstaller
  • AdobeUberInstaller.xml
  • Adobe Photoshop CS4/ <- Install media folder from original disk image (or maybe DVD)
    • resources/
    • payloads/
    • extensions/
    • Deployment/
    • Setup.app
    • Bootstrapper.dmg
  • The key is the path to the Setup.app and the installation payloads must be exactly the same as on the original media (disk or disk image) – the volume name must match and the folder(s) containing the payloads must be at the same relative paths.

  • The four AdobeUber files should be either at the root level of the disk image, or one folder down. This allows you to have a single disk image that supports multiple install combinations. You can have multiple Adobe “packages”, each in its own root-level directory.

  • Test the DMG. If it doesn’t do the right thing manually, it’s not going to work via munki.
  • Copy to test machine
  • Mount the disk image. It should appear under /Volumes with the same name as original media.
  • sudo /Volumes/Adobe\ Product\ Name/AdobeUberInstaller
  • Make sure the install succeeds.
  • sudo /Volumes/Adobe\ Product\ Name/AdobeUberUninstaller
  • Make sure the uninstall is successful.

  • Optionally create an uninstaller disk image.
  • This is not strictly necessary. munki can use the installer disk image to do the uninstall. But consider:
    • munki will need to download the disk image, and may require a GB or several GBs of space to cache the image.
    • You can create a slimmed-down diskimage that supports uninstall only; these can be a fraction of the size of the full disk image needed for install.
  • To create a uninstaller disk image, simply create a read/write copy of the installer disk image and delete all the .dmg files in the payloads and extensions directories. Be sure to leave the Bootstrapper.dmg in place, though. Convert the trimmed-down image back to read-only compressed and you should find it takes up less than 10 percent of the space of the intstaller disk image.

  • Upload the installer DMG and uninstaller DMG (if applicable) to munki server.
  • Use /usr/bin/munki/makepkginfo to create a skeleton pkginfo file; manual post-editing will certainly be required. Specifically, you will need to add “installs” items, which you can generate like so:
  • makepkginfo -f /Applications/Adobe\ Photoshop\ CS4/Adobe\ Photoshop\ CS4.app
  • munki needs these “installs” items since Adobe “packages” don’t leave receipts like standard Apple packages.
  • Treat like any other packages managed with munki.

15.1.39.2 Deploying CS4 updates

  • Download the update from Adobe’s web site. This should be a DMG containing a Setup.app that does the actual update install.
  • Upload the DMG to your munki server.
  • Use /usr/bin/munki/makepkginfo to create a skeleton pkginfo file; manual post-editing will certainly be required. Specifically, you will need to add “installs” items, which you can generate like so:
  • makepkginfo -f /Applications/Adobe\ Photoshop\ CS4/Adobe\ Photoshop\ CS4.app
  • munki needs these “installs” items since Adobe “packages” don’t leave receipts like standard Apple packages.
  • You’ll almost certainly need to add “update_for” items as well so munki knows what items can be updated with this updater.
  • Treat like any other packages managed with munki.

15.1.39.3 Other resources

Get the CS4 Deployment Toolkit and related documentation here:

http://www.adobe.com/devnet/creativesuite/

More info on the issues with Adobe installers and disk images:

http://managingosx.wordpress.com/2009/10/06/adobe-enterprise-deployment-toolkit-versus-disk-images/
How to deploy Microsoft Office 2008 using Munki.

15.1.39.4 Fix invalid values in original Office 2008 installer

Microsoft used a non-integer value for some integer-only keys, which the built-in python plist parser can’t handle. Before Munki can work with this installer, these values must be corrected.

  1. Create a read-write disk image of the Office 2008 Installer media called “Office2008.dmg”
  2. Mount disk image
  3. Replace all instances of:

    <key>IFMajorVersion</key>
    <integer>071201.1</integer>

    found in any plist on the disk image with

    <key>IFMajorVersion</key>
    <integer>071201</integer>

    I dragged the “Office Installer” from the disk image to TextMate, and used “Find in Project” to change all of the files at once.

15.1.39.5 Create pkginfo file

  1. Copy disk image to your munki pkgs folder
  2. Run makepkginfo to create a pkginfo file called Office2008-12.0.0.pkginfo
  3. Set the “name” key to “Office2008”
  4. Add this installs key to the Office2008-12.0.0.pkginfo:

    <key>installs</key>
    <array>
        <dict>
                <key>type</key>
                <string>plist</string>
                <key>path</key>
                <string>/Applications/Microsoft Office 2008/Office/MicrosoftComponentPlugin.framework/Resources/Info.plist</string>
                <key>CFBundleShortVersionString</key>
                <string>12.0.0</string>
        </dict>
    </array>

    This Info.plist file contains the most accurate version information for Office 2008, and allows munki to quickly determine what version of Office is installed. You should now be able to add “Office2008” to a manifest, update your catalogs and deploy Office 2008 via Munki.

15.1.39.6 Deploy Office 2008 12.1.0 update

  1. Download the Office 2008 12.1.0 update from Microsoft (Office2008-1210UpdateEN.dmg)
  2. Copy the dmg to your munki pkgs folder
  3. Run makepkginfo to create a pkginfo file called Office2008-12.1.0.pkginfo
  4. Set the “name” key to “Office2008_update”
  5. Add the “installs” key from above to the Office2008-12.1.0.pkginfo file and set the “CFBundleShortVersionString” key to “12.1.0”. This tells Munki what version the update installs. (If a previous version exists on the machine, the update will be applied, while if 12.1.0 or later is found, the update will not be run.)
  6. Add these keys to the Office2008-12.1.0.pkginfo file

    <key>update_for</key>
    <array>
        <string>Office2008</string>
    </array>
    <key>requires</key>
    <array>
      <string>Office2008-12.0.0.0.0</string>
    </array>

    The “update_for” key tells Munki that this installer is for Office 2008, which cause it to be automatically installed on any client that has “Office2008” listed in its manifest. The “requires” key tells Munki that this installer requires Office2008-12.0.0.0.0 to be already installed, which will cause Munki to make sure that Office2008-12.0.0.0.0 is installed before this update is applied.

15.1.39.7 Deploy other Office 2008 Updates

  1. Download the other Office 2008 updates from Microsoft (12.2.0. 12.2.3, 12.2.4, etc.)
  2. Copy the installers to your munki pkgs folder
  3. Run makepkgino to create a pkginfo file for each update (Office2008-12.2.0.pkginfo, Office2008-12.2.3.pkginfo, etc.)
  4. Set the “name” keys to “Office2008_update”
  5. Add the “installs” key from above to each pkginfo file and set the “CFBundleShortVersionString” key to the correct version (12.2.0, 12.2.3, 12.2.4, etc.)
  6. Add the same “update_for” key from above to each pkginfo file
  7. Add a “requires” key for to each pkginfo file, but set it to list the previous update. (12.2.0 requires “Office2008_Update-12.1.0.0.0”, 12.2.3 requires “Office2008_Update-12.2.0.0.0”, etc. That way, Munki will know what order to install the updates.)

Once everything is working, Munki will be able to install a fully patched version of Microsoft Office. For a new install, it will first run the original Office 2008 installer, followed by each update, in the order defined by the “require” keys.

15.1.40 Addendum

Microsoft has an updated Office 2008 installer available, which installs Office 2008 SP2 (The version I was able to obtain installed Office 12.2.2). The updated installer disk image doesn’t need any special tricks to work with makepkginfo. You’ll still need to deploy the subsequent updates.

Will Polley also pointed out that the Office 2008 12.2.5 update contains all the updates after 12.1.0. So if you can get the updated installer from Microsoft that includes Office 2008 SP2, that plus the 12.2.5 update is all you need.

15.1.41 Introduction

Munki has support for a boolean ‘autoremove’ key, to specify items that should be automatically removed if they are not listed in ‘managed_installs’ in the client’s manifest (or included manifests).

15.1.42 Details

An example:

    <key>autoremove</key>
    <true/>
    <key>name</key>
    <string>FinalCutPro7</string>

This means that if FinalCutPro7 is not listed in the “managed_installs” for a given client, it will be automatically removed. Think of it as a virtual entry in the “removals” list.

15.1.42.1 Issues:

  • If you added this key to every package, the installcheck phase might take a very long time as it checked the installation status of everything in your repo. So you probably want to add this only to items in which you need to tightly control the installed base - like items with limited numbers of available license seats.

  • There’s a problem when you have overlapping items. For example, let’s say you have these two items:
  • AdobePhotoshopCS4
  • AdobeCS4DesignStandard
  • If you mark these both for autoremoval (a logical thing to do), on a client that has AdobeCS4DesignStandard installed, installcheck will see that Photoshop CS4 is installed, note that AdobePhotoshopCS4 is NOT in the managed_installs list, and schedule AdobePhotoshopCS4 for removal – which is not what you want. So for now you’ll need to NOT mark these sorts of items for autoremoval.

  • munki 0.5.0 has an attempt to work around the above issue. If an item has an “installs” key, listing items that are installed, the code that considers an item for possible removal will not consider the item installed unless ALL items in the “installs” array are installed.
  • So - in the case of overlapping installable items like PhotoshopCS4 and AdobeCS4DesignStandard, you must ensure the “installs” list is unique for each item in an overlapping group. This allows the code that considers items for removal to distinquish between an install of just PhotoshopCS4 and one of a CS4 Suite, for example.
  • The flipside is that if something is installed and then partially deleted, munki won’t be able to confirm that the item is actually installed, and will not attempt to remove it.

    15.1.42.1 Munki 3

15.1.43 Munki 3 new features:

  • “Native” support for macOS installation applications (Like “Install macOS Sierra.app”). See [[macOS Installer Application support]].

  • Support for authorized restarts.
    This requires some launchd changes that will require a restart when upgrading from Munki 2.x to 3.x. See [[Authorized Restarts]].

  • Notification Manager notification support.
    This requires some launchd changes that will require a restart when upgrading from Munki 2.x to 3.x.
    See [[Notification Center Support]].

  • Repo plugin support contributed by Centrify.
    Allows the creation of plugins to enable the Munki command-line tools to work with cloud-based repos, or repos not available via traditional file paths, or to add additional capabilities/actions when working with a file-based repo.
    There are a couple of sample/demonstration plugins included: a GitFileRepo plugin for better integration with Git repos, and a MWA2APIPlugin as an example of working with a repo that doesn’t have direct filesystem access.
    See [[Repo Plugins]].

  • Auto-removal of optionally-installed applications that have not been used in an admin-specified time period.
    See [[Removal of Unused Software]].

  • Support for a new “Featured” psuedo-category to be used with Managed Software Center. Items can be added to a list of “featured_items” in a manifest. If there are optional installs that are also in the list of “featured_items”, the display of All optional installs in MSC app will be replaced by a display of Featured items.
    See Featured Items.

  • Support for allowing the install of packages signed with untrusted or expired certificates.
    See [[Allowing Untrusted Packages]].

  • A major refactoring of the code base, which should make it easier to add additional features in the future, but also risks introducing some regressions.

15.1.44 Removed in Munki 3:

  • Support for 10.6 and 10.7.

15.1.45 Previously-discussed changes that are not part of Munki 3:

  • Removing support for http (and enforcing https only)
  • Enforcing Apple Transport Security by default
  • Removing the ‘http://munki’ bootstrapping default
  • Support for code signing catalogs and manifests
  • Certificate pinning
  • Changing bundle and launchd identifiers from com.googlecode.munki.* to anything else
  • Bundling Python and PyObjC
  • Merging in the functionality of munki-facts
  • Moving the Munki command-line tools out of /usr/local/munki and to some other location.

    15.1.45 Managed Software Update Localizable.strings

Password dialog for FileVault authorized restarts

    /* Password prompt title */
        da: Managed Software Center skal låse startdisken op efter genstart for at færdiggøre alle ventende opdateringer.
        de: Die geführte Softwareaktualisierung möchte nach einem Neustart das Startvolume entsperren, um alle anstehenden Aktualisierungen abzuschließen.
        en: Managed Software Center wants to unlock the startup disk after restarting to complete all pending updates.
        es: Centro de Aplicaciones quiere desbloquear el disco de inicio tras el reinicio para completar todas las actualizaciones pendientes.
        fi: Managed Software Center haluaa avata käynnistyslevyn lukituksen seuraavalla käynnistyskerralla jatkaakseen päivitysten asentamista.
        fr: Le Centre de gestion des logiciels doit déverrouiller votre disque de démarrage au prochain redémarrage afin de terminer les mises à jour en attente.
        it: Centro Gestione Applicazioni vuole sbloccare il disco di avvio dopo il riavvio per completare gli aggiornamenti in sospeso.
        ja: Managed Software Centerは、すべての保留中のアップデートを完了させるため、再起動後、スタートアップディスクをアンロックします。
        nb: Managed Software Center vil låse startdisken opp etter omstart får å ferdigjøre alle ventende oppdateringer.
        nl: Managed Software Center wil de opstartschijf ontgrendelen na herstart zodat alle nog wachtende updates uitgevoerd kunnen worden.
        pt_BR: O Centro de Aplicativos Gerenciado quer desbloquear o disco de início depois de reiniciar para completar todos as atualizações pendentes.
        ru: Центр Управления ПО хочет разблокировать загрузочный диск после перезапуска, чтобы завершить все ожидающие обновления.
        sv: Managed Software Center behöver låsa upp startskivan efter omstart för att slutföra alla uppdateringar.
        
    /* Password explanation */
        da: For at tillade dette, skal du skrive din log ind-adgangskode.
        de: Bitte geben Sie Ihr Anmeldekennwort ein, um dies zu ermöglichen.
        en: To allow this, enter your login password.
        es: Para permitir esto, introduzca su contraseña de usuario.
        fi: Salli lukituksen avaaminen syöttämällä salasana.
        fr: Pour autoriser cette opération, veuillez entrer votre mot de passe.
        it: Per permettere questo, inserire la password di login.
        ja: これを許可する為、ログインパスワードを入力して下さい。
        nb: For å tillate dette, må du skrive inn ditt påloggingspassord.
        nl: Om dit toe te staan, vul je loginwachtwoord in.
        pt_BR: Para permitir isso, insira sua senha de login.
        ru: Для разрешения  введите свой пароль для входа в систему.
        sv: Ange ditt inloggningslösenord för att tillåta detta.

    /* Password label */ (ja and ru only)
        en: Password:
        it: Password:
        ja: パスワード:
        pt_BR: Senha:
        ru: Пароль:
        
    /* Allow button text */ (ja and ru only)
        en: Allow
        it: Consenti
        ja: 許可
        pt_BR: Permitir
        ru: Разрешить

    /* Deny button text */ (ja and ru only)
        en: Deny
        it: Rifiuta
        ja: 不許可
        pt_BR: Rejeitar
        ru: Не разрешать

15.1.46 MunkiStatus Localizable.strings

Status messages for macOS upgrade installs

    /* managedsoftwareupdate message */
        da: Starter macOS-opgradering...
        de: macOS Upgrade wird gestartet...
        en: Starting macOS upgrade...
        es: Comenzando actualización de macOS...
        fi: Aloitetaan macOS-päivitystä...
        fr: La mise à jour de macOS démarre...
        it: Inizio aggiornamento macOS...
        ja: macOSアップグレードの開始...
        nb: Starter macOS-oppgradering...
        nl: Beginnen met macOS upgrade...
        pt_BR: Iniciando atualização do macOS...
        ru: Запуск обновление для macOS...
        sv: Påbörjar macOS-uppgradering...

    /* managedsoftwareupdate message */
        da: Forbereder afvikling af macOS-installeringsprogrammet...
        de: Das Ausführen der macOS Installation wird vorbereitet...
        en: Preparing to run macOS Installer...
        es: Preparando la ejecución del instalador de macOS...
        fi: Valmistaudutaan käynnistämään macOS-asentaja...
        fr: Installation de macOS en cours de préparation...
        it: Preparazione all'avvio di macOS Installer...
        ja: macOSインストーラーの実行を準備中...
        nb: Forbereder å kjøre macOS-installeringsprogrammet...
        nl: MacOS installatieprogramma voorbereiden...
        pt_BR: Preparando para executar a instalação do macOS...
        ru: Пoдготовка запуска Программы Установки macOS...
        sv: Förbereder macOS-installeraren...

    /* managedsoftwareupdate message */
        da: Systemet vil genstarte og begynde opgradering af macOS.
        de: Das System wird neu gestartet und die Aktualisierung von macOS begonnen.
        en: System will restart and begin upgrade of macOS.
        es: El sistema se reiniciará y comenzará la actualización de macOS.
        fi: Tietokone käynnistyy uudelleen ja aloittaa macOS-päivityksen.
        fr: Le système va redémarrer et commencer la mise à jour de macOS.
        it: Il sistema si riavvierà e inizierà l'aggiornamento di macOS.
        ja: システムを再起動し、macOSアップグレードを開始します。
        nb: Systemet vil gjøre en omstart og begynne oppgraderingen av macOS.
        nl: Systeem zal herstarten en de upgrade van macOS starten.
        pt_BR: O sistema irá reiniciar e começar a atualização do macOS.
        ru: Система перегрузится и начнет обновление macOS.
        sv: Datorn kommer att starta om och börja uppgradera macOS.

No remaining needs at the current time!

16 Introduction

Info on installing and removing Adobe Creative Cloud products with Munki.

17 Process

Munki can install Adobe CC deployment packages generated with Adobe’s Creative Cloud Packager tool. The workflow is similar to that for CS5 and CS6 applications packaged with AAMEE.

17.1 Overview:

  1. Use Adobe’s Creative Cloud Packager to package your Adobe CC product.
  2. Import the Creative Cloud Packager’s Install package and the Uninstall package for each product.

  3. Make specific changes to some pkginfo files to accommodate problematic Adobe package behavior.

17.2 Importing into Munki:

As of March 2015, Adobe Creative Cloud Packager lists 23 separate products. You can use Creative Cloud Packager to create an installer package for each separate product, or any groups of products. If you plan to include updates in the main packages, you should first read the note on including updates in the main CCP install packages in the aamporter section towards the bottom.

You can import a specific package into Munki using munkiimport:

munkiimport /path/to/Build/AdobeCCProduct_Install.pkg --uninstallpkg /path/to/Build/AdobeCCProduct_Uninstall.pkg

However, this will be quite tedious to do 23 times. Thankfully, Tim Sutton wrote a helpful script to automate importing the packages into Munki:
https://github.com/timsutton/aamporter/blob/master/scripts/munkiimport_cc_installers.py

You can make any organization-specific changes by editing lines 41-44 in the script to set your preferred location, category, and developer.

Execute the script on your CC Packages directory:

./munkiimport_cc_installers.py /path/to/CCPackages

17.3 Fixing Broken Packages

note: several of these issues were fixed with the release of Creative Cloud 2015.

Test Test Test

Using munkiimport above with the correct --uninstallpkg switch will produce a working Munki install (and removal) for most of the products. However, some of the Creative Cloud packages don’t contain useful information inside that can generate a sane version number, and some of them don’t generate the typical Adobe installs key, due to the way Creative Cloud Packager packages them.

Specifically, Adobe Acrobat Pro DC, Edge Code, Edge Reflow, GamingSDK, Lightroom 5, and Scout do not generate useful data about their install, which will cause Munki to loop these installs endlessly. They also don’t provide useful version numbers - munkiimport will automatically pick “1.0.0.0 - Please edit me!” because it can’t find a better option.

Thus, these products need installs arrays. These examples below may vary as version numbers are updated, but the process will generally be the same.

Acrobat Pro DC:
Acrobat Pro DC installs two applications, “Adobe Acrobat.app” and “Acrobat Distiller.app” (and a shortcut to its uninstaller, contained inside the “Adobe Acrobat.app”). Use makepkginfo -f /Applications/Adobe\ Acrobat\ DC/Adobe\ Acrobat.app and makepkginfo -f /Applications/Adobe\ Acrobat\ DC/Acrobat\ Distiller.app to get the installs arrays and useful version number:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.Acrobat.Pro</string>
            <key>CFBundleName</key>
            <string>Acrobat Pro</string>
            <key>CFBundleShortVersionString</key>
            <string>15.007.20033</string>
            <key>CFBundleVersion</key>
            <string>15.007.20033</string>
            <key>minosversion</key>
            <string>10 . 4 . 3</string>
            <key>path</key>
            <string>/Applications/Adobe Acrobat DC/Adobe Acrobat.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Notice that Adobe did something stupid, which is to put a series of extraneous spaces inside the minosversion for the app bundle - “10 . 4 . 3.” Same thing happens with Acrobat Distiller.app:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.distiller</string>
            <key>CFBundleName</key>
            <string>Distiller</string>
            <key>CFBundleShortVersionString</key>
            <string>15.007.20033</string>
            <key>CFBundleVersion</key>
            <string>15.007.20033</string>
            <key>minosversion</key>
            <string>10 . 4 . 3</string>
            <key>path</key>
            <string>/Applications/Adobe Acrobat DC/Acrobat Distiller.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

At least now there’s a useful version number, which can replace the “1.0.0.0 - please edit me!” version that munkiimport tried to guess.

Despite Creative Cloud Packager helpfully providing an uninstaller package, it doesn’t actually function properly - it won’t actually remove Acrobat Acrobat Pro DC. However, Acrobat DC does install a number of receipts which list all of the files it brings along for the ride (all 10696 of them!). You can see this using pkgutil --pkgs | grep -i com.adobe.acrobat. These receipts can be put into a receipts array, which can be used for the “removepackages” uninstall method:

    <key>receipts</key>
    <array>
        <dict>
            <key>packageid</key>
            <string>com.adobe.acrobat.DC.viewer.app.pkg.MUI</string>
            <key>version</key>
            <string>15.007.20033</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.adobe.acrobat.DC.viewer.appsupport.pkg.MUI</string>
            <key>version</key>
            <string>15.007.20033</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.adobe.acrobat.DC.viewer.browser.pkg.MUI</string>
            <key>version</key>
            <string>15.007.20033</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.adobe.acrobat.DC.viewer.print_automator.pkg.MUI</string>
            <key>version</key>
            <string>15.007.20033</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.adobe.acrobat.DC.viewer.print_pdf_services.pkg.MUI</string>
            <key>version</key>
            <string>15.007.20033</string>
        </dict>
    </array>
    <key>uninstall_method</key>
    <string>removepackages</string>
    <key>uninstallable</key>
    <true/>

Since an installs array is present, the receipts won’t be used to determine if the program is installed - but can be used to remove it on demand.

Acrobat DC also installs a linkCreation.dotm template into the Office 2011 Startup directory for Word. So Microsoft Word should be in the blocking applications:

        <key>blocking_applications</key>
        <array>
            <string>Microsoft Word</string>
        </array>

Unfortunately, the last thing left is that it creates an alias to the Uninstaller application, and this is not installed by package. Thus, despite removing the packages, /Applications/Adobe Acrobat DC/ is still present, and contains a broken alias. It can be removed, along with the Word template, using a postuninstall_script:

    <key>postuninstall_script</key>
    <string>#!/bin/sh
/bin/rm -rf /Applications/Adobe\ Acrobat\ DC/
/bin/rm -f /Applications/Microsoft\ Office\ 2011/Office/Startup/Word/linkCreation.dotm
    </string>

Note about Acrobat DC and Acrobat Pro 11: Acrobat Pro 11 uses a similar installs key in its pkginfo:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.Acrobat.Pro</string>
            <key>CFBundleName</key>
            <string>Acrobat</string>
            ...

If your pkginfo for Acrobat Pro 11 has an installs array that contains these two elements, Acrobat Pro 11 will also (erroneously) report that it is installed and can be removed if Acrobat Pro DC is installed. To address this issue (if you offer optional installs of both Acrobat Pro 11 and Acrobat Pro DC), remove the two keys above from the Acrobat Pro 11 installs array, to force Munki to verify based entirely on path.

Edge Code CC:
Edge Code installs only a single application, which makes it easy to generate an installs array. Use makepkginfo -f /Applications/Adobe\ Edge\ Code\ CC.app:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.EdgeCode</string>
            <key>CFBundleName</key>
            <string>Edge Code</string>
            <key>CFBundleShortVersionString</key>
            <string>0.98.0-359086275</string>
            <key>CFBundleVersion</key>
            <string>0.98.0-359086275</string>
            <key>path</key>
            <string>/Applications/Adobe Edge Code CC.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Additionally, despite Creative Cloud Packager helpfully providing an uninstaller package, it doesn’t actually function properly - running it with Installer.app fails, and removing the package with Munki doesn’t remove the installed software. Instead of relying on it, instead use an uninstall_script to delete the folder from /Applications and remove the package receipt:

    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh
/bin/rm -rf "/Applications/Adobe Edge Code CC.app"
/usr/sbin/pkgutil --forget com.adobe.EdgeCode
    </string>
    <key>uninstallable</key>
    <true/>

Edge Reflow CC:
Edge Reflow has the same problems as Edge Code, but also the same solutions. Generate the installs array with makepkginfo -f /Applications/Adobe\ Edge\ Reflow\ CC.app:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.EdgeReflow</string>
            <key>CFBundleName</key>
            <string>Edge Reflow</string>
            <key>CFBundleShortVersionString</key>
            <string>0.51</string>
            <key>CFBundleVersion</key>
            <string>0.51</string>
            <key>path</key>
            <string>/Applications/Adobe Edge Reflow CC.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Similarly, create an uninstall_script:

    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh
/bin/rm -rf "/Applications/Adobe Edge Reflow CC.app"
/usr/sbin/pkgutil --forget com.adobe.pkg.Reflow
    </string>
    <key>uninstallable</key>
    <true/> 

GamingSDK:
This doesn’t install an application that you can query for a version, but instead includes a text file called VersionInfo.txt, which contains the version number in plain text. As of writing time, the content of that file is “1.4.394”, which gives an easy value to use in our pkginfo.
Use makepkginfo -f /Applications/Adobe\ Gaming\ SDK\ 1.4/VersionInfo.txt to generate a simple md5 hash of it:

    <key>installs</key>
    <array>
        <dict>
            <key>md5checksum</key>
            <string>34ef3b5ada1541c9f997835ead3127a5</string>
            <key>path</key>
            <string>/Applications/Adobe Gaming SDK 1.4/VersionInfo.txt</string>
            <key>type</key>
            <string>file</string>
        </dict>
    </array>

As with Edge Code & Edge Reflow, use an uninstall_script to delete the folder from /Applications and remove the package receipt:

    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh
/bin/rm -rf "/Applications/Adobe Gaming SDK 1.4"
/usr/sbin/pkgutil --forget com.adobe.AdobeGamingSDK1.4.pkg
    </string>
    <key>uninstallable</key>
    <true/>

Scout:
Scout requires an installs key as well, but also installs an application with sane version info contained inside the Info.plist, which makes makepkginfo -f /Applications/Adobe\ Scout\ CC.app helpful:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.Scout.application</string>
            <key>CFBundleName</key>
            <string>Scout</string>
            <key>CFBundleShortVersionString</key>
            <string>1.1.3</string>
            <key>CFBundleVersion</key>
            <string>1.1.3.354121</string>
            <key>path</key>
            <string>/Applications/Adobe Scout CC.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Again, the uninstaller package won’t do the right thing, so an uninstall_script is necessary:

    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh
/bin/rm -rf "/Applications/Adobe Scout CC.app"
/usr/sbin/pkgutil --forget com.adobe.pkg.Scout
    </string>
    <key>uninstallable</key>
    <true/>

17.4 Updating Adobe CC Products

Adobe CC is in the middle of transition of their installer tools, and so the methods available to add updates to Munki depend on exactly which applications and versions. aamporter was a convenient additional tool for automatically adding Adobe’s “patch” installers but is of little relevance in early 2017, with most applications having been moved over to the newer installer tools. The old aamporter content in this wiki is preserved in the “2015 and earlier” section below, but if one is packaging current (as of 2017) applications, only a few applications still using the legacy “RIBS” installer remain (Lightroom 2015 being one).

17.4.1 2015.5 and later

All CC 2017 releases and the 2015 “.5” releases from June 2016 ship using a new installer technology known by Adobe as HyperDrive. This supports completely self-contained “update” installers which, to use Adobe’s description, can be “installed without a base version.”

To add these updates, package new versions using CCP and add them as previous versions were added. Any related updates like Camera Raw may be either included in the new packages or added separately as their own Munki items using update_for relationships.

17.4.2 2015 and earlier

Creative Cloud Packager is an important tool for creating standard Apple packages for Adobe’s Creative Cloud products, and it helpfully bundles in updates with it. You could use it to deploy updates for Adobe’s CC products by repackaging them each time an update comes out, but doing this for each of the 23 separate products quickly becomes tedious.

Thankfully, Tim Sutton has provided a helpful tool to solve this problem - enter aamporter. aamporter is a command line utility that will search for updates for your specified products, download them, and import them into Munki. It’s important to read through the documentation in the README first before continuing.

17.4.3 Note on including updates in the main CCP install packages

Munki includes built-in support for Adobe patch updaters imported separately from the CCP install package, and so if you plan to use aamporter to automate these updates, it’s preferable if the CCP packages include no additional updates, just the “base” product. In the days of AAMEE (CCP’s predecessor), there were issues applying the Adobe patch updates to installs where the base installer included additional updates downloaded from AAMEE. With the arrival of Creative Cloud it’s no longer possible to obtain these patch updates via Adobe’s website to import manually, but aamporter is still able to download these updates from Adobe’s feed and Munki still supports installing them “natively.”

17.4.4 Build the product plists

The first step is to create the product plist for each of your CC packages by pointing aamporter at each of the .ccp files inside your CC package folders:

./aamporter.py --build-product-plist /path/to/CCPackages/AfterEffectsCC/AfterEffectsCC.ccp

Doing this to all of your CCP packages will give you a bunch of plists. That’s what aamporter needs in order to cache the downloads, but there’s some manual editing required in order to import these into Munki. The Munki-specific features need to be added, either in each individual product plist, or in a generic “aamporter.plist” file (or a combination of both).

Create your “aamporter.plist” file to contain generic information:

<?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>munkiimport_options</key>
    <array>
        <string>--category=AdobeUpdates</string>
        <string>--developer=Adobe</string>
    </array>
</dict>
</plist>

More can be specified (see the documentation for details), but remember that options set in the aamporter.plist file will apply to every update. If you want to sort your updates by product, you’ll want to add the Munki-specific options to each product plist.

Here’s an example product plist for Adobe AfterEffects CC, with the Munki-specific features added:

<?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>channels</key>
    <array>
        <...snipped...>
    </array>
    <key>munki_update_for</key>
    <array>
        <string>AdobeAfterEffectsCC</string>
    </array>
    <key>munki_repo_destination_path</key>
    <string>updates/adobe/CC/AfterEffectsCC</string>
</dict>
</plist>

The munki_update_for option specifies that any updates from the channels listed will be imported to Munki with as an update_for an item named “AdobeAfterEffectsCC”. munki_repo_destination_path specifies where the files will be located in the Munki repo. If you don’t want specific locations for each update, this option can be placed in aamporter.plist instead.

17.4.5 Importing the updates

With the product plists created and edited with your desired Munki configurations, it’s time to begin the import process. Here’s an example command using a few of the CC products:

./aamporter.py --munkiimport AfterEffectsCC.ccp.plist AuditionCC.ccp.plist BridgeCC.ccp.plist DreamweaverCC.ccp.plist --make-catalogs

If you want to get fancy something like the following will work as well:

./aamporter.py --munkiimport /some/path/to/all/my/Adobe/packages/*/*.plist

As the documentation explains, the --munkiimport switch imports the packages into Munki with the information specified in aamporter.plist and the individual product plists.

Check the repo to make sure the relationships for update_for are as expected.

Please read the Caveats for aamporter carefully, and test the updates thoroughly.

17.4.6 Introduction

Information on using munki with Adobe CS5 updates

17.4.7 Details

Starting with version 0.5.2.553.0 of the munki tools, munki can handle Adobe CS5 updates, which have an application named “AdobePatchInstaller.app” at the root of the disk image.

Dealing with CS5 updates is very similar to dealing with CS3/CS4 updates.

Important note #1: Do not repackage CS5 updates using AAMEE. Simply use munkiimport to import the diskimage as downloaded from Adobe.

Important note #2: Some CS5 updates might refuse to install when there is no user logged in via the GUI. I have not been able to verify this conclusively, but it appears that if you’ve installed a CS5 product using a package generated with the pre-release version of Adobe Application Manager, Enterprise Edition (AAMEE) instead of the “final” 1.0 version of AAMEE, that any updates installed for this product will exhibit the issue of not being able to be installed when there is not logged-in user. If the “base” product was installed using a package generated with AAMEE 1.0 (final), updates will install successfully with no logged-in user.

Updates verified to work:

  • Flash Professional CS5 Update 11.0.2
  • After Effects CS5 10.0.1 Update
  • Adobe Player for Embedding 3.1 – Requires copy_local = “True” in pkginfo. See below.
  • Adobe Premiere Pro CS5 5.0.2 Update
  • Adobe Dreamweaver CS5 11.0.3 Updater
  • Adobe Camera Raw 6.2 Update
  • Adobe Community Help 3.3 – Must be repackaged. See https://managingosx.wordpress.com/2010/09/03/updating-adobe-help-for-cs5/
  • Adobe CSXS Infrastructure CS5 2.0.1 Update (CS Live)
  • Adobe Pixel Bender Plug-in for Adobe Photoshop CS5: Must be packaged with AAMEE.
  • Adobe IllustratorCS5 15.0.1 Update
  • Adobe InDesign CS5 7.0.2 Update
  • Adobe XMP Panels CS5 update (July 22, 2010) – Requires copy_local = “True” in pkginfo. See below.
  • Adobe DeviceCentral CS5 3.0.1 Update
  • Adobe Flash Builder 4 4.0.1 Update
  • Adobe Photoshop CS5 12.0.1 update
  • Adobe Bridge CS5 4.0.3 update
  • Adobe Flash Professional CS5 Update 11.0.1
  • Adobe OnLocation CS5 5.0.1

Older updates that work – these have been superceded by later cumulative updates:

  • Adobe Dreamweaver 11.0.2 update
  • Adobe Camera Raw 6.1 update

copy_local workaround: These updates fail with “Exit Code: 7 - Unable to complete Silent workflow” whether or not a user is logged in:

  • Adobe XMP Panel CS5 - Jul 22, 2010
  • Adobe Player for Embedding 3.1

    Errors in the log are:

  • ERROR: No media information provided for removable source location
  • ERROR: Cannot iniliatize payload session

When the contents of the disk image are copied locally, the update succeeds, so this is a variation of the problem with installs from disk images.

Workaround: using munki tools 0.6.0.633.0 or later, add the following key to the pkginfo:

    <key>copy_local</key>
    <true/>

This causes munki to copy the disk image contents to the local disk before installing them. Currently, this key works only with Adobe CS5 updates.

17.4.7.1 makepkginfo and Adobe CS5 updates

Run makepkginfo against an update disk image to generate a basic pkginfo file. munki will generate a (hopefully) functional “installs” key based on the AdobeCodes for the installed payloads. You can manually add additional “installs” items, and must manually add an “update_for” entry. Here’s an 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>catalogs</key>
        <array>
                <string>testing</string>
        </array>
        <key>description</key>
        <string></string>
        <key>display_name</key>
        <string>Adobe Bridge CS5</string>
        <key>installed_size</key>
        <integer>177358</integer>
        <key>installer_item_location</key>
        <string>AdobeBridge_4.0.2_mul_AdobeUpdate.dmg</string>
        <key>installer_item_size</key>
        <integer>8952</integer>
        <key>installer_type</key>
        <string>AdobeCS5PatchInstaller</string>
        <key>installs</key>
        <array>
                <dict>
                        <key>CFBundleIdentifier</key>
                        <string>com.adobe.bridge4</string>
                        <key>CFBundleName</key>
                        <string>Adobe Bridge CS5</string>
                        <key>CFBundleShortVersionString</key>
                        <string>4.0.2.1</string>
                        <key>path</key>
                        <string>/Applications/Adobe Bridge CS5/Adobe Bridge CS5.app</string>
                        <key>type</key>
                        <string>application</string>
                </dict>
        </array>
        <key>minimum_os_version</key>
        <string>10.4.0</string>
        <key>name</key>
        <string>AdobeBridgeCS5</string>
        <key>payloads</key>
        <array>
                <dict>
                        <key>AdobeCode</key>
                        <string>{2C8FBE83-2D3E-4CE6-A912-4BED85BCAC06}</string>
                        <key>display_name</key>
                        <string>Adobe Bridge CS5</string>
                        <key>installed_size</key>
                        <integer>177358</integer>
                        <key>version</key>
                        <string>4.0.2.0.0</string>
                </dict>
        </array>
        <key>uninstallable</key>
        <false/>
        <key>update_for</key>
        <array>
                <string>AdobeDesignStandardCS5</string>
                <string>AdobeMasterCollectionCS5</string>
                <string>AdobeProductionPremiumCS5</string>
                <string>AdobePhotoshopCS5</string>
        </array>
        <key>version</key>
        <string>4.0.2.0.0</string>
</dict>
</plist>

17.4.8 Introduction

Version 0.6.0.640.0 of the munki tools supports deployment of Adobe CS5 products packaged using the Adobe Application Manager, Enterprise Edition (AAMEE). munki attempts to work around some of the outstanding issues with AAMEE 1.0-generated packages.

17.4.9 Summary

To deploy an Adobe CS5 or CS5.5 product with Munki, package the product using AAMEE 2.1, available here. You should not need to disable Adobe Air components. Do not add any Adobe updates to the package.

Use munkiimport to import the generated CS5Product_Install.pkg. You do not need to import the CS5Product_Uninstall.pkg.

Adobe CS5/5.5 updates downloaded from adobe.com can be directly imported into Munki – do not repackage them with AAMEE.

17.4.10 Details

With the release of the Adobe CS5 products, Adobe has also introduced a new Enterprise Deployment Toolkit, which they’ve named “AAMEE” (Adobe Application Manager, Enterprise Edition). This new toolkit allows administrators to create Apple package installers from Adobe CS5 media. While this works, and the resulting packages can be used with munki, there are a few outstanding issues:

  1. The packages cannot be installed when there is no user logged into the GUI; the install hangs while attempting to install Adobe Help or Adobe Media Player, both Adobe AIR-based applications. This is an issue Adobe is working on.
  2. The “package” is actually a payload-free package with a preinstall/preupgrade script that is a wrapper around updated versions of the same Adobe install tools that shipped with CS3 and CS4. As a result of this design, Apple’s Installer has no way to give useful or accurate installation progress feedback. The Installer will display “About a minute remaining…” for many, many minutes - up to an hour in some cases.
  3. AAMEE-generated packages will fail when you attempt to install them from a mounted disk image. This is a problem because munki requires all bundle-style packages to be wrapped in a disk image so they can be stored and retrieved as a single file from the munki web server.
    munki 0.6.0.640.0 has workarounds for all of these issues.

For the first issue, munki calls the Adobe installer using launchctl bsexec <PID_of_loginwindow> if the install is does in the loginwindow context, and monitors the install. If the install hangs on an Adobe AIR or Adobe Help install, that part of the install is killed, allowing the larger install to progress. In practice, it appears that using launchctl bsexec <PID_of_loginwindow> results in successful installation of Adobe AIR/Adobe Help in most cases.

The second issue is worked around by monitoring the install log and using that to provide percent-done feedback. An identical technique is used by munki for CS3/CS4 installs. This technique is not 100% accurate, but at least provides approximate progress feedback.

Finally, the third issue is addressed by creating some symlinks on the local disk pointing back to resources on the mounted disk image. This fools the Adobe installer into thinking the installation payloads are on a non-removable disk, and it proceeds with installation.

To use an AAMEE-1.0-generated installer package with munki, create the pacakge using the “final” 1.0 release of AAMEE, or a later release. Do not use the “preview” release or any pre-release version of the AAMEE tool.

Use munkiimport to import the AAMEE-generated install package into your Munki server.

Alternately, wrap the installation package in a disk image. Copy it to your munki web server as you would any other package, and run makepkginfo on it like any other package. makepkginfo will also encapsulate the info needed for an uninstall, so there is no need to wrap or upload the uninstall package.

AAMEE 2.0 notes

AAMEE 2.0, released to support Adobe Creative Suite 5.5, adds support for including product updates in the installer package. Munki does nor currently handle AAMEE packages with included updates correctly. Do not include product updates in packages built with AAMEE 2.0. You may instead manage product updates separately in Munki.

17.4.11 Introduction

Info on installing and removing Adobe CS6 products with Munki.

17.4.12 Details

Munki can treat Adobe CS6 deployment packages generated with AAMEE 3 exactly the same as CS5/5.5 deployment packages.

See Adobe CS5 for details.

Abbreviated version:

  1. Use AAMEE 3 (available here) to package your Adobe CS6 product. You should not need to disable Adobe AIR components.
  2. Use munkiimport to import the CS6Product_Install.pkg. You do not need the CS6Product_Uninstall.pkg.

17.4.12.1 CS6 Updates

Do not repackage CS6 updates using AAMEE. Simply use munkiimport to import the diskimage as downloaded from Adobe.

18 Notes on munki and Adobe CS5 updates

19 Introduction

Information on using munki with Adobe CS5 updates

20 Details

Starting with version 0.5.2.553.0 of the munki tools, munki can handle Adobe CS5 updates, which have an application named “!AdobePatchInstaller.app” at the root of the disk image.

Dealing with CS5 updates is very similar to dealing with CS3/CS4 updates.

Important note #1: Do not repackage CS5 updates using AAMEE. Simply use munkiimport to import the diskimage as downloaded from Adobe.

Important note #2: Some CS5 updates might refuse to install when there is no user logged in via the GUI. I have not been able to verify this conclusively, but it appears that if you’ve installed a CS5 product using a package generated with the pre-release version of Adobe Application Manager, Enterprise Edition (AAMEE) instead of the “final” 1.0 version of AAMEE, that any updates installed for this product will exhibit the issue of not being able to be installed when there is not logged-in user. If the “base” product was installed using a package generated with AAMEE 1.0 (final), updates will install successfully with no logged-in user.

Updates verified to work:

  • Flash Professional CS5 Update 11.0.2
  • After Effects CS5 10.0.1 Update
  • Adobe Player for Embedding 3.1 – Requires copy_local = “True” in pkginfo. See below.
  • Adobe Premiere Pro CS5 5.0.2 Update
  • Adobe Dreamweaver CS5 11.0.3 Updater
  • Adobe Camera Raw 6.2 Update
  • Adobe Community Help 3.3 – Must be repackaged. See http://managingosx.wordpress.com/2010/09/03/updating-adobe-help-for-cs5/
  • Adobe CSXS Infrastructure CS5 2.0.1 Update (CS Live)
  • Adobe Pixel Bender Plug-in for Adobe Photoshop CS5: Must be packaged with AAMEE.
  • Adobe IllustratorCS5 15.0.1 Update
  • Adobe !InDesign CS5 7.0.2 Update
  • Adobe XMP Panels CS5 update (July 22, 2010) – Requires copy_local = “True” in pkginfo. See below.
  • Adobe !DeviceCentral CS5 3.0.1 Update
  • Adobe Flash Builder 4 4.0.1 Update
  • Adobe Photoshop CS5 12.0.1 update
  • Adobe Bridge CS5 4.0.3 update
  • Adobe Flash Professional CS5 Update 11.0.1
  • Adobe !OnLocation CS5 5.0.1

Older updates that work – these have been superceded by later cumulative updates:

  • Adobe Dreamweaver 11.0.2 update
  • Adobe Camera Raw 6.1 update

copy_local workaround:
These updates fail with “Exit Code: 7 - Unable to complete Silent workflow” whether or not a user is logged in:

  • Adobe XMP Panel CS5 - Jul 22, 2010
  • Adobe Player for Embedding 3.1

Errors in the log are:

  • ERROR: No media information provided for removable source location
  • ERROR: Cannot iniliatize payload session

When the contents of the disk image are copied locally, the update succeeds, so this is a variation of the problem with installs from disk images.

Workaround: using munki tools 0.6.0.633.0 or later, add the following key to the pkginfo:
<key>copy_local</key>
<true/>
This causes munki to copy the disk image contents to the local disk before installing them. Currently, this key works only with Adobe CS5 updates.

20.0.1 makepkginfo and Adobe CS5 updates

Run makepkginfo against an update disk image to generate a basic pkginfo file. munki will generate a (hopefully) functional “installs” key based on the !AdobeCodes for the installed payloads. You can manually add additional “installs” items, and must manually add an “update_for” entry. Here’s an 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>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>description</key>
    <string></string>
    <key>display_name</key>
    <string>Adobe Bridge CS5</string>
    <key>installed_size</key>
    <integer>177358</integer>
    <key>installer_item_location</key>
    <string>AdobeBridge_4.0.2_mul_AdobeUpdate.dmg</string>
    <key>installer_item_size</key>
    <integer>8952</integer>
    <key>installer_type</key>
    <string>AdobeCS5PatchInstaller</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.adobe.bridge4</string>
            <key>CFBundleName</key>
            <string>Adobe Bridge CS5</string>
            <key>CFBundleShortVersionString</key>
            <string>4.0.2.1</string>
            <key>path</key>
            <string>/Applications/Adobe Bridge CS5/Adobe Bridge CS5.app</string>
            <key>type</key>
            <string>application</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>AdobeBridgeCS5</string>
    <key>payloads</key>
    <array>
        <dict>
            <key>AdobeCode</key>
            <string>{2C8FBE83-2D3E-4CE6-A912-4BED85BCAC06}</string>
            <key>display_name</key>
            <string>Adobe Bridge CS5</string>
            <key>installed_size</key>
            <integer>177358</integer>
            <key>version</key>
            <string>4.0.2.0.0</string>
        </dict>
    </array>
    <key>uninstallable</key>
    <false/>
    <key>update_for</key>
    <array>
        <string>AdobeDesignStandardCS5</string>
        <string>AdobeMasterCollectionCS5</string>
        <string>AdobeProductionPremiumCS5</string>
                <string>AdobePhotoshopCS5</string>
    </array>
    <key>version</key>
    <string>4.0.2.0.0</string>
</dict>
</plist>

21 Notes on Adobe CS5 installers and munki

22 Introduction

Version 0.6.0.640.0 of the munki tools supports deployment of Adobe CS5 products packaged using the Adobe Application Manager, Enterprise Edition (AAMEE). munki attempts to work around some of the outstanding issues with AAMEE 1.0-generated packages.

23 Summary

To deploy an Adobe CS5 or CS5.5 product with Munki, package the product using AAMEE 2.1, available here. You should not need to disable Adobe Air components. Do not add any Adobe updates to the package.

Use munkiimport to import the generated CS5Product_Install.pkg. You do not need to import the CS5Product_Uninstall.pkg.

Adobe CS5/5.5 updates downloaded from adobe.com can be directly imported into Munki – do not repackage them with AAMEE.

24 Details

With the release of the Adobe CS5 products, Adobe has also introduced a new Enterprise Deployment Toolkit, which they’ve named “AAMEE” (Adobe Application Manager, Enterprise Edition). This new toolkit allows administrators to create Apple package installers from Adobe CS5 media. While this works, and the resulting packages can be used with munki, there are a few outstanding issues:

  1. The packages cannot be installed when there is no user logged into the GUI; the install hangs while attempting to install Adobe Help or Adobe Media Player, both Adobe AIR-based applications. This is an issue Adobe is working on.
  2. The “package” is actually a payload-free package with a preinstall/preupgrade script that is a wrapper around updated versions of the same Adobe install tools that shipped with CS3 and CS4. As a result of this design, Apple’s Installer has no way to give useful or accurate installation progress feedback. The Installer will display “About a minute remaining…” for many, many minutes - up to an hour in some cases.
  3. AAMEE-generated packages will fail when you attempt to install them from a mounted disk image. This is a problem because munki requires all bundle-style packages to be wrapped in a disk image so they can be stored and retrieved as a single file from the munki web server.

munki 0.6.0.640.0 has workarounds for all of these issues.

For the first issue, munki calls the Adobe installer using launchctl bsexec <PID_of_loginwindow> if the install is does in the loginwindow context, and monitors the install. If the install hangs on an Adobe AIR or Adobe Help install, that part of the install is killed, allowing the larger install to progress. In practice, it appears that using launchctl bsexec <PID_of_loginwindow> results in successful installation of Adobe AIR/Adobe Help in most cases.

The second issue is worked around by monitoring the install log and using that to provide percent-done feedback. An identical technique is used by munki for CS3/CS4 installs. This technique is not 100% accurate, but at least provides approximate progress feedback.

Finally, the third issue is addressed by creating some symlinks on the local disk pointing back to resources on the mounted disk image. This fools the Adobe installer into thinking the installation payloads are on a non-removable disk, and it proceeds with installation.

To use an AAMEE-1.0-generated installer package with munki, create the pacakge using the “final” 1.0 release of AAMEE, or a later release. Do not use the “preview” release or any pre-release version of the AAMEE tool.

Use munkiimport to import the AAMEE-generated install package into your Munki server.

Alternately, wrap the installation package in a disk image. Copy it to your munki web server as you would any other package, and run makepkginfo on it like any other package. makepkginfo will also encapsulate the info needed for an uninstall, so there is no need to wrap or upload the uninstall package.

AAMEE 2.0 notes

AAMEE 2.0, released to support Adobe Creative Suite 5.5, adds support for including product updates in the installer package. Munki does nor currently handle AAMEE packages with included updates correctly. Do not include product updates in packages built with AAMEE 2.0. You may instead manage product updates separately in Munki.

25 Adobe CS6 products

26 Introduction

Info on installing and removing Adobe CS6 products with Munki.

27 Details

Munki can treat Adobe CS6 deployment packages generated with AAMEE 3 exactly the same as CS5/5.5 deployment packages.

See Adobe CS5 for details.

Abbreviated version:

1) Use AAMEE 3 (available here) to package your Adobe CS6 product. You should not need to disable Adobe AIR components.

2) Use munkiimport to import the CS6Product_Install.pkg. You do not need the CS6Product_Uninstall.pkg.

27.1 CS6 Updates

Do not repackage CS6 updates using AAMEE. Simply use munkiimport to import the diskimage as downloaded from Adobe.
Munki and Office 2011 updates

27.1.1 Introduction

Like Office 2008, Office 2011 must be updated by installing additional update packages, some of which require previous updates to be installed. See [[Munki And Office 2008]] to understand how to use update_for and requires to cause the correct updates to be installed in the correct order. The concepts are the same for Office 2011.

27.1.2 Current Recommendation

Use AutoPkg.

The MSOffice2011Updates.munki recipe finds the latest Office 2011 update, downloads it, extracts the embedded package, and imports it into your Munki repo.

27.1.3 Additional notes

27.1.3.1 Office 2011 14.1.2 and 14.1.3 Updates

Office 2011 updates typically work with little modification as downloaded from Microsoft. Unfortunately, the Office 14.1.2 update brought a new issue where it will hang while trying to install at the login window. This same issue affects the Office 2011 14.1.3 update as well; the workaround is the same.

In order to prevent this problem, simply add the following installer_choice_xml entry to your Office 14.1.2 or 14.1.3 update pkginfo file:

<key>installer_choices_xml</key>
<array>
    <dict>
        <key>attributeSetting</key>
        <integer>0</integer>
        <key>choiceAttribute</key>
        <string>selected</string>
        <key>choiceIdentifier</key>
        <string>quit</string>
    </dict>
</array>

This installer_choices_xml section tells the installer to NOT install the “quit” subpackage in the update; this payload-free package attempts to quit open Microsoft applications before doing the update. It’s written in a way that hangs when executed while at the login window. We work around the problem by telling the installer to skip the install of this specific subpackage.

You can learn more about Munki’s support for installer choice changes XML here: [[ChoiceChangesXML]]

27.1.4 Office 2011 14.1.4 Update

With prior Office 2011 updates, it was recommended to use an installer_choices_xml file to disable the installation of the package that quit open apps.

The corresponding package in the 14.1.4 update has a new preflight script:

#!/bin/bash

/usr/bin/w | /usr/bin/grep -e "console" | /usr/bin/grep -v grep > /dev/null
if [ $? == 1 ]
then
    exit 0
fi

RESOURCES_DIRECTORY=`/usr/bin/dirname "$0"`
QUIT_APPS_PATH="${RESOURCES_DIRECTORY}/QuitApps.app/Contents/MacOS/QuitApps"

if [ "${COMMAND_LINE_INSTALL}" == "" ]; then
    USERNAME=$USER
    MODE="GUI_INSTALLATION"
else
    USERNAME="root"
    MODE="COMMAND_LINE_INSTALLATION"
fi

/usr/bin/su "${USERNAME}" -c "\"${QUIT_APPS_PATH}\" $MODE"

Some brief testing shows that the modified QuitApps binary, when run as root with a COMMAND_LINE_INSTALLATION parameter, causes open web browsers and Office apps to be quit without warning. This makes the installation of the update more effective, but isn’t great user experience if you are doing this while a GUI user is logged in.

Therefore, if you deploy this update with Munki, I’d recommend either marking it as requiring a logout, or adding a blocking_applications key with a list of all the applications that !QuitApps might quit.

“What are those apps?” you might ask. QuitApps.app/Contents/Resources/MSApplicationSignatures.plist seems to contain that list:

<string>Alerts Daemon</string>
<string>Database Utility</string>
<string>Equation Editor</string>
<string>Handheld Sync Installer</string>
<string>MSMLServer</string>
<string>MSN Messenger</string>
<string>MSN Messenger Daemon</string>
<string>Microsoft AU Daemon</string>
<string>Microsoft AutoUpdate</string>
<string>Microsoft Cert Manager</string>
<string>Microsoft Chart Converter</string>
<string>Microsoft Clip Gallery</string>
<string>Microsoft Database Daemon</string>
<string>Microsoft Database Utility</string>
<string>Microsoft Entourage</string>
<string>Microsoft Outlook</string>
<string>Microsoft Error Reporting</string>
<string>Microsoft Excel</string>
<string>Microsoft Graph</string>
<string>Microsoft Help Viewer</string>
<string>Microsoft Language Register</string>
<string>Microsoft Communicator</string>
<string>Microsoft Messenger Daemon</string>
<string>Microsoft Messenger</string>
<string>Microsoft Office Notifications</string>
<string>Microsoft Office Reminders</string>
<string>Microsoft Office Setup Assistant</string>
<string>Microsoft PowerPoint</string>
<string>Microsoft Sync Services</string>
<string>SyncServicesAgent</string>
<string>Microsoft Query</string>
<string>Microsoft Word</string>
<string>My Day</string>
<string>Organization Chart</string>
<string>Project Gallery Launcher</string>
<string>Remove Office</string>
<string>AssertMonitor</string>
<string>MacBU Monitor</string>
<string>Microsoft Ship Asserts</string>
<string>MicrosoftMouseHelper</string>
<string>MicrosoftKeyboardHelper</string>
<string>Windows Live Sync</string>
<string>Windows Live Mesh</string>
<string>LiveAgent</string>
<string>Expression Media</string>
<string>Remote Desktop Connection</string>
<string>eXClient</string>
<string>MacDiff</string>
<string>ImageDiff</string>
<string>Opera</string>
<string>Google Chrome</string>
<string>Firefox</string>
<string>Safari</string>
<string>Microsoft SkyDrive</string>
<string>Microsoft SkyDrive Setup</string>

It’s a bad idea to put applications that have no UI into the blocking_applications list, since users have no way to quit them directly; besides, QuitApps will quit them if needed. So I’d suggest pruning this list to something like:

<string>MSN Messenger</string>
<string>Microsoft Cert Manager</string>
<string>Microsoft Chart Converter</string>
<string>Microsoft Clip Gallery</string>
<string>Microsoft Entourage</string>
<string>Microsoft Outlook</string>
<string>Microsoft Error Reporting</string>
<string>Microsoft Excel</string>
<string>Microsoft Graph</string>
<string>Microsoft Help Viewer</string>
<string>Microsoft Language Register</string>
<string>Microsoft Communicator</string>
<string>Microsoft Messenger</string>
<string>Microsoft PowerPoint</string>
<string>Microsoft Query</string>
<string>Microsoft Word</string>
<string>My Day</string>
<string>Organization Chart</string>
<string>Windows Live Sync</string>
<string>Windows Live Mesh</string>
<string>LiveAgent</string>
<string>Expression Media</string>
<string>Remote Desktop Connection</string>
<string>Opera</string>
<string>Google Chrome</string>
<string>Firefox</string>
<string>Safari</string>

27.1.5 Office 2011 14.2.0 Update

This update, released in mid-April 2012, has deployment issues with JAMF Casper and Munki. In Munki’s case, the installation hangs for a very long time at the end. Munki’s supervisor module will eventually kill the process, but that only happens after two hours. This hang is due to a script that is launched at the beginning of the install process. This script waits until the installer exits, then does some temp file cleanup. Unfortunately, in many circumstances, the script fails to detect that the install is complete and hangs indefinitely.

Microsoft has acknowledged the issue, and currently suggests this workaround:

Attempts to do a command line install on Lion are failing due to the script to clean up the temporary folder used to hold the bits during installation. This issue can also occur on any OS if multiple command line installs are being done at the same time.

Microsoft is aware of the issue and looking to remedy it, but in the meantime, the following steps will allow you to edit the offending script and carry on with your deployment.

  1. Open the 14.2.0 updater DMG
  2. Drag the Office 2011 14.2.0 Update.pkg to your desktop
  3. CTRL+Click on the Office 2011 14.2.0 Update.pkg and choose Show Package Contents from the contextual menu
  4. Navigate to the Resource folder from within the Contents folder.
  5. Open the clean_path script with any text editor
  6. On the second line (a blank line) add this text exit 0
  7. Save the script and then run your installation with this modified pkg

Your final code should look like this:

#!/bin/sh

exit 0

We recommend that you restart after this installation to remove the temporary folder from the machine and
avoid potential update problems in the future if the temporary folder still existed.

I am sorry for any inconvenience this has caused you.

David Pelton
Release Test Lead, Microsoft Macintosh group.

Munki tools version 0.8.3 Build 1564 makes changes to how /usr/sbin/installer is called that avoids the issue in this update.
An example script to configure Munki

27.1.6 Overview

Below you will find a script to configure Munki. While this script can be used in a “thin imaging” environment, pay attention to the context in which the script is running or it will fail.

#!/bin/bash
 
# Munki Configuration Script
# Last Date Modified:
# November 25th, 2014
# Uncomment what you need.
 
##################################################   Munki 1/2   ##################################################
 
# AppleSoftwareUpdatesOnly
## boolean
## default = false
### If true, only install updates from an Apple Software Update server.
### No munki repository is needed or used.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls AppleSoftwareUpdatesOnly -bool false
 
# InstallAppleSoftwareUpdates
## boolean
## default - false
### If true, install updates from an Apple Software Update server, in addition to "regular" munki updates.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls InstallAppleSoftwareUpdates -bool false
 
# SoftwareUpdateServerURL - WARNING! NOT RECOMMENDED
## string
## default - NONE
### Catalog URL for Apple Software Updates.
### If undefined or empty, Munki will use the same catalog that the OS uses when you run Apple's Software Update application or call /usr/sbin/softwareupdate. THIS IS NOT RECOMMENDED as of 10.11+, see https://github.com/munki/munki/issues/511
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SoftwareUpdateServerURL -string "http(s)://FDDQN"
 
# SoftwareRepoURL
## string
## default - "http://munki/repo"
### Base URL for munki repository
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SoftwareRepoURL -string "http://munki/repo"
 
# PackageURL
## string
## default - "<SoftwareRepoURL>/pkgs"
### Base URL for munki pkgs.
### Useful if your packages are served from a different server than your catalogs or manifests.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls PackageURL -string "http(s)://FDDQN/pkgs"
 
# CatalogURL
## string
## default - "<SoftwareRepoURL>/catalogs"
### Base URL for munki catalogs.
### Useful if your catalogs are served from a different server than your packages or manifests.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls CatalogURL -string "http(s)://FDDQN/catalogs"
 
# ManifestURL
## string
## default - "<SoftwareRepoURL>/manifests"
### Base URL for munki manifests.
### Useful if your manifests are served from a different server than your catalogs or manifests.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ManifestURL -string "http(s)://FDDQN/manifests"
 
# ClientIdentifier
## string
## default - NONE
### Identifier for munki client.
### Usually is the same as a manifest name on the munki server.
### If this is empty or undefined, Munki will attempt the following identifiers, in order: fully-qualified hostname, "short" hostname, serial number and finally, "site_default"
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ClientIdentifier -string "MachineName"
 
# ManagedInstallDir
## string
## default - "/Library/Managed Installs"
### Folder where munki keeps its data on the client.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ManagedInstallDir -string "/Library/Managed Installs"
 
# LogFile
## string
## default - "/Library/Managed Installs/Logs/ManagedSoftwareUpdate.log"
### Primary log is written to this file.
### Other logs are written into the same directory as this file.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls LogFile -string "/Library/Managed Installs/Logs/ManagedSoftwareUpdate.log"
 
# LogToSyslog
## boolean
## default - false
### If true, log to /var/log/system.log in addition to ManagedSoftwareUpdate.log.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls LogToSyslog -bool false
 
# LoggingLevel
## integer
## default - 1
### Higher values cause more detail to be written to the primary log.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls LoggingLevel -int 1
 
# DaysBetweenNotifications
## integer
## default - 1
### Number of days between user notifications from Managed Software Update.
### Set to 0 to have Managed Software Update notify every time a background check runs if there are available updates.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls DaysBetweenNotifications -int 1
 
# UseClientCertificate
## boolean
## default - false
### If true, use an SSL client certificate when communicating with the munki server.
### Requires an https:// URL for the munki repo.
### See ClientCertificatePath for details.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls UseClientCertificate -bool false
 
# UseClientCertificateCNAsClientIdentifier
## boolean
## default - false
### If true, use the CN of the client certificate as the Client Identifier.
### Used in combination with the UseClientCertificate key.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls UseClientCertificateCNAsClientIdentifier -bool false
 
# SoftwareRepoCAPath
## string
## default - (empty)
### Path to the directory that stores your CA certificate(s).
### See the curl man page for more details on this parameter.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SoftwareRepoCAPath -string "http(s)://FQDN"
 
# SoftwareRepoCACertificate
## string
## default - "/Library/Managed Installs/certs/ca.pem"
### Absolute path to your CA Certificate.
####  /usr/bin/defaults write /Library/Preferences/ManagedInstalls SoftwareRepoCACertificate -string "/Library/Managed Installs/certs/ca.pem"
 
# ClientCertificatePath
## string
## default - "/Library/Managed Installs/certs/[munki.pem|client.pem|cert.pem]"
### Absolute path to a client certificate.
### There are 3 defaults for this key. Concatenated cert/key PEM file accepted.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ClientCertificatePath -string "/Library/Managed Installs/certs/[munki.pem|client.pem|cert.pem]"
 
# ClientKeyPath
## string
## default - (empty)
### Absolute path to a client private key.
### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ClientKeyPath -string "/Library/Managed Installs/certs/private/munki.key"
 
# AdditionalHttpHeaders
## array
## default - (empty)
### This key provides the ability to specify custom HTTP headers to be sent with all curl() HTTP requests.
### AdditionalHttpHeaders must be an array of strings with valid HTTP header format.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls AdditionalHttpHeaders -array-add '{"http";}'
 
# PackageVerificationMode
## string
## default - "hash"
### Controls how munki verifies the integrity of downloaded packages.
### Possible values are:
###     none: No integrity check is performed.
###     hash: Integrity check is performed if package info contains checksum information.
###     hash_strict: Integrity check is performed, and fails if package info does not contain checksum information.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls PackageVerificationMode -string "hash"
 
# SuppressUserNotification
## boolean
## default - false
### If true, Managed Software Update will never notify the user of available updates.
### Managed Software Update can still be manually invoked to discover and install updates.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SuppressUserNotification -bool false
 
# SuppressAutoInstall
## boolean
## default - false
### If true, munki will not automatically install or remove items.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SuppressAutoInstall -bool false
 
# SuppressLoginwindowInstall
## boolean
## default - false
### Added in version 0.8.4.1696.0.
### If true, Munki will not install items while idle at the loginwindow except for those marked for unattended_install or unattended_uninstall.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SuppressLoginwindowInstall -bool false
 
# SuppressStopButtonOnInstall
## boolean
## default - false
### If true, Managed Software Update will hide the stop button while installing or removing software, preventing users from interrupting the install.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls SuppressStopButtonOnInstall -bool false
 
# InstallRequiresLogout
## boolean
## default - false
### If true, Managed Software Update will require a logout for all installs or removals.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls InstallRequiresLogout -bool false
 
# ShowRemovalDetail
## boolean
## default - false
### If true, Managed Software Update will display detail for scheduled removals.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ShowRemovalDetail -bool false
 
 
################################################## Munki 2 Only ##################################################
 
# IconURL
## string
## default - "<SoftwareRepoURL>/icons"
### Base URL for product icons.
### Useful if your icons are served from a different server or different directory than the default.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls IconURL -string "http(s)://FDDQN/icons"
 
# ClientResourceURL
## string
## default - "<SoftwareRepoURL>/client_resources"
### Base URL for custom client resources for Managed Software Update.
### Useful if your resources are served from a different server or different directory than the default.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ClientResourceURL -string "http(s)://FDDQN/client_resources"
 
# ClientResourceFilename
## string
## default - "manifest name.zip or site_default.zip"
### Specific filename to use when requesting custom client resources.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls ClientResourceFileName -string "site_default.zip"
 
# HelpURL
## string
## default - "none"
### If defined, a URL to open/display when the user selects "Managed Software Center Help" from Managed Software Center's Help menu.
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls HelpURL -string "http(s)://FQDN"

# LocalOnlyManifest
## string
## default - "none"
### Specific manifest placed in /Library/Managed\ Installs/manifests/
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls LocalOnlyManifest -string "extra_packages"

# FollowHTTPRedirects
## string
## default - "none"
### Allows Munki to follow HTTP/S redirects
### none - This is the default and is the same as the present behaviour. No redirects are followed. https - Only redirects to URLs using HTTPS are followed. Redirects to HTTP URLs are not followed. all - Redirects to both HTTP and HTTPS URLs are followed
#### /usr/bin/defaults write /Library/Preferences/ManagedInstalls FollowHTTPRedirects -string "none"

List of People that provide support on the munki-dev mailing list.

27.2 Munki-Dev Helpers

  • Nate Walck @natewalck
  • Nick McSpadden @Nick_GodIsADJ
    Documentation on munki:// links

27.2.1 Details

Managed Software Center supports a custom protocol: munki://

You can use this to link to specific pages and items within Managed Software Center, perhaps from an internal documentation page.

Some possibly useful links:

munki://category-all

Opens the main Software page:

munki://developer-google

Opens Managed Software Center to a page listing all the items with developer “Google”:

munki://updates

Opens the application to the Updates view:

munki://detail-Firefox

Displays the detail page for Firefox.

The link format is munki://detail-[item name], where ‘name’ is the pkginfo ‘name’ key (and not the ‘display_name’).
Detail links are case sensitive.

27.2.1.1 Caveats

Like any URL, some characters may need to be URL-encoded. For example, replace spaces in links with %20.

Except for detail links, links aren’t case sensitive. They will however bring up a page with the same case as in the link. Thus, linking to munki://developer-graham%20gilbert rather than munki://developer-Graham%20Gilbert will work but be visually inconsistent with what Managed Software Center will show if just browsing to items developed by Graham Gilbert (with capital Gs).

(This wiki doesn’t allow these munki:// protocol links to be clickable. Copy them and paste them into your browser’s URL field or use the open command from your shell, ie. open munki://detail-Firefox)
Munki repository with Git version control

27.2.2 Introduction

This document is not intended as a git tutorial (you can find plenty of them online) but as a guide to setting up a version controlled munki repository with larger organizations in mind. Managing a munki repository with git version control provides some advantages over the traditional way of editing files in place. Just to name a few:

  • You can go back in time
  • Changes to the repo get documented through commits
  • Many administrators can work on the repo at the same time
  • A change in the repo is not immediately available to clients
  • With distributed version control, you can easily checkout copies of the repository to different web servers or admin machines

One thing that I’d like to point out before even starting: Version control is not an alternative for backups. And backing up is not an alternative for version control. Use both.

27.2.2.1 Requirements

  • Mac OS X admin computer(s) with munkitools and git installed
  • Web server that hosts the munki repository and has git installed
  • Optional, a second server to host the git repository

Suggested additions:

  • Public-key authentication for SSH connections. This will definitely speed things up

In the following examples we are using a single Red Hat Enterprise Linux server for serving both the munki repository and the central git repository. Munki is served over HTTP and write access to git repositories is only done over SSH connections.

27.2.2.2 Installing git

OS X doesn’t include git by default. To fix this, there are two easy methods:

  1. If you are running 10.9 or later, just open Terminal.app and run git. You will get prompted to install the command line developer tools if they are not installed.
  2. Download a pre-built installer package from the Git website

After installing, configure your environment by telling git a bit about yourself (these are used in commits):

git config --global user.email john.doe@company.com
git config --global user.name "John Doe"

27.2.3 Setting things up

First of all, decide where to host git repositories. This can be a directory on the munki server itself or a directory on a completely different server. In this document we are using the following:

  • Server name: munki
  • Central git repository: munki:/var/git-repos/munki-test.git/
  • Munki virtual host: munki:/var/www/virtual.hosts/munki/

27.2.3.1 Central git repository

Create a new empty shared git repository with the following commands:

mkdir /var/git-repos/munki-test.git/
chown root:your_admin_group /var/git-repos/munki-test.git/
chmod g+swx /var/git-repos/munki-test.git/
cd /var/git-repos/munki-test.git
git --bare init --shared=group

A bare git repository means that there is no working copy checked out. Also notice that when we used the --shared=group option when initializing the repo, our admin group was given a read/write access to the repository. This is what the newly created repository should look like:

$ ls -la
total 40
drwxrwsr-x 7 root your_admin_group 4096 Jan 13 12:49 .
drwxr-xr-x 5 root root             4096 Jan 13 12:47 ..
-rw-rw-r-- 1 root your_admin_group   23 Jan 13 12:49 HEAD
drwxrwsr-x 2 root your_admin_group 4096 Jan 13 12:49 branches
-rw-rw-r-- 1 root your_admin_group  126 Jan 13 12:49 config
-rw-rw-r-- 1 root your_admin_group   58 Jan 13 12:49 description
drwxrwsr-x 2 root your_admin_group 4096 Jan 13 12:49 hooks
drwxrwsr-x 2 root your_admin_group 4096 Jan 13 12:49 info
drwxrwsr-x 4 root your_admin_group 4096 Jan 13 12:49 objects
drwxrwsr-x 4 root your_admin_group 4096 Jan 13 12:49 refs

27.2.3.2 Munki virtual host

Next we’re going to prepare some things for a second repository under /var/www/virtual.hosts/munki/repo/. This will be the munki repository that clients access with HTTP/HTTPS. We’re choosing not to include the pkgs directory in git version control because of it’s possibly large size. That means that you have to use some other means to copy the .dmg/.pkg files to your server (munki-import, rsync, scp or something else). Everything except the packages are kept under version control. The actual exclusion with .gitignore file is done on next step during the initial import.

Create the repo and repo/pkgs directories and give your admin group the ability to copy new packages.

mkdir /var/www/virtual.hosts/munki/repo/
cd /var/www/virtual.hosts/munki/repo/
mkdir pkgs
chown root:your_admin_group pkgs/
chmod g+w pkgs/

27.2.3.3 Adding content

Now, on your local admin mac, either create a new munki repository or go to an existing one and make an initial import with git.

  1. Create an empty Git repository:

cd /Users/Shared/munki/testrepo/ git init

  1. Create a .gitignore file to exclude a set of specific files. In this case disk images and packages are excluded. This ignore file will automatically go to our central repository so this is a “one-time” configuration.

# Skip directories catalogs pkgs

or

# Skip all dmg files *.dmg # Skip all packages *.pkg *.mpkg

  1. At this point you should add some content to the repo. Create pkginfo files, manifests and run makecatalogs…

  2. Get a glimpse of what git sees in your repo

git status

  1. Import everything

git add .

  1. Create your first commit

git commit -m "Initial import"

  1. Push the contents of your local repo to the central git repository

git push munki:/var/git-repos/munki-test.git --all

  1. Clone the central repository to your virtual host

ssh user@munki cd /var/www/virtual.hosts/munki/ git clone /var/git-repos/munki-test.git repo

27.2.3.4 Providing access to other administrators

When you have a working central git repository, other administrators can simply do a git clone operation to get everything up and running.

git clone user@munki:/var/git-repos/munki-test.git

27.2.4 Everyday workflow

When everything is set up correctly, working with munki+git should be something like this:

  1. Check the central repository for any changes made by other administrators:

git pull

  1. Make your changes to manifests, pkginfos, catalogs, etc. and run makecatalogs if needed. Some useful commands for git:

```
# Get the status of your local repo
git status

# Show commit history
git log

# What changes have I made?
git diff
git diff <file>
```

  1. Commit your changes to your local repository:

```
# Add a specific file
git add <file>

# or add everything
git add .

# Do a commit. This will open a commit message in your default $EDITOR. Write it, save and you’re done.
git commit -a
```

  1. Push your changes to the central repository:

git push

  1. Finally, when you’re ready to make the changes available to clients:

ssh user@munki cd /var/www/virtual.hosts/munki/repo/ git pull

27.2.5 Tips & Tricks

27.2.5.1 Email notifications

You can configure your central git repository to send email notifications whenever someone makes a commit. This is usually a must-have when working with multiple administrators. The default git install includes a post-receive hook for this but you have to enable and configure it. Note that these changes are made on server side (your central git repository).

First, locate the post-receive-email script included with git. Usually it can be found from: /usr/share/doc/git-core/contrib/hooks/post-receive-email

The script can also be found online from :
git.kernel.org / git.git / contrib / hooks / post-receive-email

The following instructions are actually from the file itself.

Move to that folder and give the script execute rights (if it doesn’t have them).

cd /usr/share/doc/git-core/contrib/hooks/
chmod a+x post-receive-email

Go to your central git repository and enable the post-receive hook.

cd /path/to/your/repository.git
ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive

Configure your repository to send emails

cd /path/to/your/repository.git
echo "Name of Your Repository" > description
git config --add hooks.mailinglist yourmailinglist@example.com
git config --add hooks.emailprefix "[Munki] "
git config --add hooks.envelopesender sender@example.com

Now, if all went well. You should get an email every time someone does a “git push” from their local machines to the central repository.

27.2.5.2 Hiding the .git directory from clients

Because of git’s distributed model, every git repository always includes the whole history. This is usually a good thing but if you don’t want this to be freely readable by your clients over HTTP, you can deny access to it by using standard directory overrides in either .htaccess files or your main httpd.conf.

Add something like this:

<Directory "/var/www/virtual.hosts/munki/repo/.git">
    Order deny,allow
    Deny from all
</Directory>

Now, if someone tries to access http://munki/repo/.git/, all they get is “403 Forbidden”.


Here is very in-depth information that may supersede some of the information below:
https://clburlison.com/demystify-office2016/ (Published 04 Jan 2016)

Microsoft had significant issues early in their release process for 2016, but have been responsive and addressed many of the common ones. This page may change to reflect updates in the future.

With Office 2016, Microsoft has made significant changes to how Office is packaged and deployed. The individual apps are now sandboxed and can be deployed individually. Additionally, there are now 2 ways you can purchase/license Office 2016:

  • Traditional Volume-licensed model
  • Office 365 Subscription

27.3 Volume-licensed customers

As done previously, Office 2016 is available as a traditional volume-licensed installer. This is downloadable as an ISO image from Microsoft’s Volume-license portal. The volume-license installer is suitable for deployment via Munki as of version 15.13.4 without changes, otherwise you’d need to use a custom ChoiceChangesXML to exclude the specific volume licensing package from it. Some are also excluding the Microsoft AutoUpdate installer so there isn’t a first-launch prompt asking to also launch the associated daemon, since Munki will be handling those updates.

Some have found that they prefer to install AND update Office 2016 via Munki by using AutoPkg and the collection of Office 2016 recipes available in the main autopkg recipes repo subdirectory. These recipes package and import the individual Office apps by pulling the “updates” directly from Microsoft. (As of 15.19.1 ‘deltas’ are also available, but there are ‘internal’ tracks that Microsoft would like you to test by manually running MAU - more info here:.) Minus some shared fonts that could be left out for languages you may not need, the only component definitely needed from the volume-license installer was your actual volume license file (which would be present at /Library/Preferences/com.microsoft.office.licensingV2.plist). As of the 15.17.1 version of the volume license, the download includes a package that can serialize a disk, which should be used instead of other methods, and works with either the SKU-Less or ‘Standalone’ installer versions. The Office 2016 recipes are:

  • MSExcel2016.munki
  • MSWord2016.munki
  • MSPowerpoint2016.munki
  • MSOneNote2016.munki
  • MSOutlook2016.munki

27.4 Office 365 customers

If the Office updates (detailed above) are deployed to a system without installing the licensing file, the first Office 2016 app opened will prompt the user to log in to Office 365. Each additional app launched may prompt the end user to access the credentials in the keychain set by the first licensed app, but in any case Munki has no additional work to perform.

27.5 SKU-Less

Additionally, SKU-less versions of the suite (which can be used with either flavor of licensing), can be found (along with other helpful info) at macadmins.software
Support for Notification Center notifications of pending software updates

27.6 About Notification Center Support

Notification Center is a new feature in Munki 3.

27.6.1 Background/History

If you’ve been using Munki for some time, you might be wondering about this:

https://github.com/munki/munki/wiki/FAQ#q-does-munki-support-notification-center-notifications
Q: Does Munki support Notification Center notifications?

A: No. Much work was done to add Notification Center support, until we discovered a fundamental issue: Notification Center notifications are completely under user control, and users can turn them off. Worse, the software posting the notifications doesn’t even know/can’t find out that the user has turned them off. One assumes that you, the admin, think it is important to notify users of pending updates and would like to ensure your users are notified. If so, Notification Center notifications are not a good mechanism to accomplish that. So rather than have two notification methods (Notification Center, which we can’t rely upon, and Munki’s current method of launching/activating Managed Software Center) we decided to just have the one, reasonably reliable notification method.

So what changed?

It occurred to me that if Munki started tracking the dates updates first became available, that we could change the notification behavior if one or more updates had been pending for “too long”. We could use Notification Center to notify about pending updates, but if the user had turned off notifications or is ignoring the notifications, after a few days we can “escalate” the notification by returning to the previous behavior of launching Managed Software Center.app.

27.6.2 Implemented behavior

When Munki decides to notify the user of pending updates, instead of launching Managed Software Center.app, it launches munki-notifier.app, a new Cocoa application you can find inside MSC.app/Contents/Resources. This app then either posts a Notification Center notification or launches MSC.app as appropriate.

The default “escalation period” is three days. In other words, if any pending update has been available for over three days, munki-notifier will skip posting a Notification Center notification, and will instead launch MSC.app. Admins can customize this grace period by setting the ManagedInstalls preference “UseNotificationCenterDays” to the number of days Notification Center notifications should be attempted before switching to launching MSC.app.

27.6.3 ManagedInstalls preferences

Key Type Default Description
UseNotificationCenterDays integer 3 Number of days Notification Center notifications should be used before switching to launching Managed Software Center

27.6.4 Localized notifications

Notifications have been (possibly poorly) localized into all the languages supported by Managed Software Center.app. If you notice a poor localization, let me know or (better) file a PR. Localized strings are in the *.lproj folders here:
https://github.com/munki/munki/tree/master/code/apps/munki-notifier/munki-notifier

There are currently only five strings to be localized. Some of these phrases were already localized for MSC.app, so I borrowed those. “Details” is commonly localized in several apps, so I borrowed those localizations. “”Software updates available" went through Google Translate, so I would not be shocked if some of those localizations are not great.

27.6.4.1 Examples:

English:

/* Multiple Updates message */
"%@ pending updates" = "%@ pending updates";

/* One Update message */
"1 pending update" = "1 pending update";

/* Details label */
"Details" = "Details";

/* Forced Install Date summary */
"One or more items must be installed by %@" = "One or more items must be installed by %@";

/* Software updates available message */
"Software updates available" = "Software updates available";

Swedish:

/* Multiple Update message */
"%@ pending updates" = "%@ uppdateringar väntar";

/* One Update message */
"1 pending update" = "1 uppdatering väntar";

/* Details label */
"Details" = "Detaljer";

/* Forced Install Date summary */
"One or more items must be installed by %@" = "Ett eller flera objekt måste installeras senast %@";

/* Software updates available message */
"Software updates available" = "Programuppdateringar finns";

As of version 2.3, Munki has support for on-demand user installation/execution of certain self-service items. When an item marked as supporting “OnDemand” install is included in the list of optional_installs, an end-user can install/execute this item whenever they wish, and as often as they’d like – in other words, installing/running such an item does not cause the item to be classified as “installed”. This can be useful to allow users to run scripts that perform maintenance tasks that normally require elevated privileges, or would otherwise be desirable to pre-program as a workflow that guides the end user through.

To illustrate one possible workflow around adding an OnDemand item, please see the use case documented by Shea Craig:
https://sheagcraig.github.io/configuring-and-reconfiguring-the-default-mail-reader-self-service-through-munki-and-a-tale-of-woe/

27.6.5 What Munki Does

Munki consists of client-side tools written largely in Python, and is available as open-source under the Apache 2 license. The client tools run on Leopard and above. They require a minimum Python 2.5, and so will not run on Tiger or earlier versions of Mac OS X. Munki 2 drops support for Leopard; it runs on Snow Leopard and above. Munki 3 supports OS X Mountain Lion and above.

On the server side, Munki can use any web server. You can use any available modern web server on any platform. (I say “modern” because some software packages can be over 2GB in size and older web servers have problems serving files of that size.) You do not need to install any Munki-specific software on the web server, but you must be able to create directories and files on the web server.

Munki can install software delivered as standard Apple packages - the same kind of packages, that when double-clicked, open in Apple’s Installer.app. Munki can also install software from disk images - for example, an application delivered on a disk image that is supposed to be dragged to the Applications folder. These “drag-n-drop disk images” are easily installed by Munki. Munki also knows how to install many Adobe products - specifically, it can install the Adobe CS3, CS4, CS5, CS6 and CC products and their updates. In many cases, Munki can also remove the software it has installed.

Munki also supports “Optional Software”. These are items that are made available to the users of machines you manage, who can decide for themselves whether or not they’d like any of these items installed. If they choose to install an optional software item, they can also later remove it. This feature does not require admin rights for the user, and is similar in concept to “Self Service” installs offered by the Casper Suite from JAMF Software.

Additionally, Munki can update software it did not install itself. You can specify that certain software should be updated only if some version is found already installed on a user’s machine.

Finally, Munki can be configured to install Apple Software Updates. This allows users without admin rights to be able to install available Apple updates. See here for more information.

27.6.6 What Munki Doesn’t Do

Many of the commercial solutions for software deployment also provide solutions for other facets of Mac management. Munki does not. Munki focuses only on software deployment. You’ll need to turn to other tools for imaging, inventory, remote assistance, and preference management.

See here for some Web consoles that do inventory and reporting and integrate nicely with Munki.

27.6.7 Munki Pieces

Most of the data munki needs to function is stored on a web server. Munki uses three types of data:

Installer items: these are packages or disk images containing the software to be installed. In many cases, you can use a package or disk image provided by the software vendor without having to repackage or convert the installer package in any way. For example, munki can install Firefox from the disk image that you download from http://www.mozilla.com. Sometimes these are just referred to as “packages”, but in actuality Munki can install from things that aren’t strictly Apple Installer packages.

Catalogs: these are lists of available software, containing metadata about the installer items. You, as the Munki administrator, build these catalogs using tools provided with Munki. Catalogs are usually built from individual files, called “pkginfo” files, that describe the metadata for a single installer item. Learn more about pkginfo files here. The makecatalogs tool is used to build catalogs from pkginfo files. Learn more about makecatalogs here.

Manifests: A manifest is essentially a list of what software should be installed on or removed from a given machine. You could have a different manifest for every machine, or one manifest for all of your machines. Manifests can include the contents of other manifests, allowing you to group software for easy addition to client manifests. For example, you could create a manifest listing all of the software every machine in your organization must have. The manifest for a client could then include the common-software manifest, and additionally have software unique to that client. Learn more about manifests here.

Manifests and catalogs are stored on the web server as standard Apple plist files in text format. pkginfo files are also plist-formatted files. If you’ve administered Mac OS X machines, you’ve almost certainly encountered plist files. They are a well-understood way to store structured data in a text format.

27.6.8 Munki Behaviors

Since a Munki server is just a web server serving static files, all of the “smarts” of Munki reside in the client software on each machine.

By default, when installed and configured, the managedsoftwareupdate process runs in the background approximately once an hour. It looks for changes on the server, downloading new or changed manifests and catalogs. It then uses the manifests and catalogs to determine what is supposed to be installed or removed from the user’s machine. If anything needs to be installed, it is downloaded in the background. All of this is done in the background without involving the user. If there are any changes that need to be made, what Munki does next depends on whether or not there is a user logged in.

If there is no user logged in, by default, Munki proceeds to install or remove the required software without asking. It displays a status window over the loginwindow, effectively preventing users from logging in until the updates are complete. If any of the updates require a restart, Munki will restart the machine at the end of its session.

If there is a user logged in, Munki will launch Managed Software Center to notify the user of available updates. (Munki won’t notify the user of the same updates more than once a day, however.) The user is then in control - he or she can elect to perform the updates right away, or defer them until later.

If the user chooses to perform the updates, there are a couple of possibilities. If any of the updates require a logout or restart, the only choice available will be to logout and update. If none of the updates require a logout or restart, the user can install the updates immediately.

Administrators can customize these behaviors, configuring Munki to never bother the user with available updates (therefore waiting to install all updates when no user is logged in), or the inverse - telling Munki to never automatically install software when at the loginwindow, and instead always requiring user consent for all updates.

Administrators can also mark some updates as safe to install without user confirmation; these usually include a list of “blocking_applications” so that Munki won’t try to automatically update software that is in use. See here for additional information on Munki’s support for unattended installs and removals.

It’s sometimes necessary for Munki to be more aggressive: there may be reasons that a given piece of software or an update must be installed by some deadline. See here for more information about Munki’s ability to “force” some installs.
Details on the format of pkginfo files

27.6.9 Introduction

Much (most?) of the stuff munki can do is because of the package metadata made available through the catalogs, which are in turn made from data in pkginfo files. Pkginfo files can be generated with the [[makepkginfo]] tool, though they are more commonly created as a side-effect of running [[munkiimport|munkiimport]].

It’s important to remember that Munki clients never use pkginfo files directly – they only query catalogs. Catalogs are constructed from pkginfo files. Therefore, any changes to pkginfo files (adding a new one, deleting one, or editing one) require rebuilding the catalogs using the tool.

Though some of the information in a pkginfo file can be gleaned from the packages themselves, admins can and should add additional information (and sometimes correct the autogenerated info!).

See [[Supported Pkginfo Keys]] for an exhaustive list of valid pkginfo keys.

27.6.10 Details

Here’s an example pkginfo file:

<?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>name</key>
    <string>ServerAdministrationSoftware</string>
    <key>version</key>
    <string>10.5.5</string>
    <key>description</key>
    <string>Administration tools for OS X Server</string>
    <key>display_name</key>
    <string>Server Administration Software</string>
    <key>installs</key>
    <array>
        <dict>
            <key>type</key>
            <string>application</string>
            <key>path</key>
            <string>/Applications/Server/Server Admin.app</string>
            <key>CFBundleIdentifier</key>
            <string>com.apple.ServerAdmin</string>
            <key>CFBundleName</key>
            <string>Server Admin</string>
            <key>CFBundleShortVersionString</key>
            <string>10.5.3</string>
        </dict>
        <dict>
            <key>type</key>
            <string>application</string>
            <key>path</key>
            <string>/Applications/Server/Workgroup Manager.app</string>
            <key>CFBundleIdentifier</key>
            <string>com.apple.WorkgroupManager</string>
            <key>CFBundleName</key>
            <string>Workgroup Manager</string>
            <key>CFBundleShortVersionString</key>
            <string>10.5.5</string>
        </dict>
    </array>
    <key>receipts</key>
    <array>
        <dict>
            <key>packageid</key>
            <string>com.apple.pkg.ServerAdminTools</string>
            <key>version</key>
            <string>10.5.3.0</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.apple.pkg.ServerSetup</string>
            <key>version</key>
            <string>10.5.3.0</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.5.0</string>
    <key>installer_item_location</key>
    <string>apps/ServerAdminToold1055.dmg</string>
    <key>uninstallable</key>
    <true/>
    <key>uninstall_method</key>
    <string>removepackages</string>
</dict>
</plist>

Let’s tear it apart:

27.6.10.1 Basic keys

<dict>
    <key>name</key>
    <string>ServerAdministrationSoftware</string>
    <key>version</key>
    <string>10.5.5</string>
    <key>description</key>
    <string>Administration tools for OS X Server</string>
    <key>display_name</key>
    <string>Server Administration Software</string>

name, version, and description should be easy to understand. display_name is an optional key, used to provide a “pretty” display name in the ManagedSoftwareUpdate app.

27.6.10.1.1 installs array
<key>installs</key>
<array>
    <dict>
        <key>type</key>
        <string>application</string>
        <key>path</key>
        <string>/Applications/Server/Server Admin.app</string>
        <key>CFBundleIdentifier</key>
        <string>com.apple.ServerAdmin</string>
        <key>CFBundleName</key>
        <string>Server Admin</string>
        <key>CFBundleShortVersionString</key>
        <string>10.5.3</string>
    </dict>
    <dict>
         <key>type</key>
         <string>application</string>
         <key>path</key>
         <string>/Applications/Server/Workgroup Manager.app</string>
         <key>CFBundleIdentifier</key>
         <string>com.apple.WorkgroupManager</string>
         <key>CFBundleName</key>
         <string>Workgroup Manager</string>
         <key>CFBundleShortVersionString</key>
         <string>10.5.5</string>
     </dict>
</array>

The (optional) installs key is interesting. This must be created by the administrator. It is a list of dictionaries; each dictionary item describes something that is installed by the installation package. Currently supported items:

27.6.10.1.2 installs array item: application
<dict>
    <key>type</key>
    <string>application</string>
    <key>path</key>
    <string>/Applications/Server/Workgroup Manager.app</string>
    <key>CFBundleName</key>
    <string>Workgroup Manager</string>
    <key>CFBundleIdentifier</key>
    <string>com.apple.WorkgroupManager</string>
    <key>CFBundleShortVersionString</key>
    <string>10.5.5</string>
    <key>minimum_update_version</key>
    <string>10.0</string>
</dict>

First, installcheck looks for the application at the specified path. If it doesn’t find it there, system_profiler is used to look for an application matching the CFBundleName or CFBundleIdentifier. Once found, the application’s version is compared to CFBundleShortVersionString. All of these values can be found in an application’s Contents/Info.plist.

If (optional) minimum_update_version is supplied, only installed versions of the app of version # >= minimum_update_version will be matched.

27.6.10.1.3 installs array item: bundle
<dict>
    <key>type</key>
    <string>bundle</string>
    <key>path</key>
    <string>/Applications/Server/Server Assistant.app/Contents/Plug-ins/BackupServer.bundle</string>
    <key>CFBundleShortVersionString</key>
    <string>10.5.1</string>
    <key>minimum_update_version</key>
    <string>10.0</string>
</dict>

A more generic bundle comparison, this time found by path. If the bundle is found at the given path, the CFBundleShortVersionString is compared with the CFBundleShortVersionString in bundle’s Contents/Info.plist.

Once again, if (optional) minimum_update_version is supplied, only installed versions of the bundle of version # >= minimum_update_version will be matched.

27.6.10.1.4 installs array item: plist
<dict>
    <key>type</key>
    <string>plist</string>
    <key>path</key>
    <string>/Applications/Server/Server Admin.app/Contents/Info.plist</string>
    <key>CFBundleShortVersionString</key>
    <string>10.5.3</string>
    <key>minimum_update_version</key>
    <string>10.0</string>
</dict>

A generic plist comparison which might be useful for Info.plists or version.plists in odd locations.

Once again, if (optional) minimum_update_version is supplied, only installed versions of the plist of version # >= minimum_update_version will be matched.

27.6.10.1.5 installs array item: file
<dict>
    <key>type</key>
    <string>file</string>
    <key>path</key>
    <string>/var/db/b.receiptdb</string>
    <key>md5checksum</key>
    <string>375bb4dca4624474019338a5c1246f82</string>
</dict>

The attribute path is checked for existence. If the key md5checksum exists, the checksum of the file on disk is compared with the provided checksum.

The easiest way to create the installs item keys is using the makepkginfo tool, and providing paths to the items:

makepkginfo /path/to/TextWrangler.pkg.dmg -f /Applications/TextWrangler.app

27.6.10.2 receipts array

Back to the original catalogitem:

<key>receipts</key>
<array>
    <dict>
        <key>packageid</key>
        <string>com.apple.pkg.ServerAdminTools</string>
        <key>version</key>
        <string>10.5.3.0</string>
    </dict>
    <dict>
        <key>packageid</key>
        <string>com.apple.pkg.ServerSetup</string>
        <key>version</key>
        <string>10.5.3.0</string>
    </dict>
</array>

receipts is a list of packageids installed by the installer item. The tool does its best to figure out what packageids are in a given installer item.

receipts are used two ways:

  1. If there is no installs key, catalogcheck uses the receipts list to determine if a given item is installed or not.
  2. If the package is marked as uninstallable and the uninstall method is removepackages, this is the list of packages to remove.

Returning to the catalogitem:

    <key>minimum_os_version</key>
    <string>10.5.0</string>

When managedsoftwareupdate is looking for valid items to install, it checks the OS version of the current machine against this key. installitems that require a later OS version than the OS on the current machine are skipped. Note this can cause errors in the log if a manifest refers to “MyGreatApp” for a machine, but all the pkginfo items for various versions of “MyGreatApp” require a later version of the OS than the current machine. managedsoftwareinstall will complain that it cannot find info for MyGreatApp.

maximum_os_version can also be specified, using the same format as minimum_os_version.

    <key>installer_item_location</key>
    <string>apps/ServerAdminToold1055.dmg</string>

This is the relative path to the installer item on the repo web server.

27.6.10.3 uninstallable/uninstall_method

    <key>uninstallable</key>
    <true/>
    <key>uninstall_method</key>
    <string>removepackages</string>
</dict>
</plist>

These optional keys determine if ManagedInstaller can attempt to uninstall this item. Supported uninstall_methods include removepackages and a full path to an executable script that does the uninstall, for example from the catalogitem for XcodeTools:

    <key>uninstallable</key>
    <true/>
    <key>uninstall_method</key>
    <string>/Developer/Library/uninstall-devtools</string>

You may also specify “uninstall_script” as the uninstall_method; in that case you must supply the uninstall_script as the value of the “uninstall_script” key.

27.6.11 Additional keys not shown in the example

27.6.11.1 Optional dependencies/relationship keys

There are two kinds of dependency/relationship keys, which define how various install items are related to each other.

27.6.11.2 requires

requires are prerequisites: package B requires package A be installed first.
if package B is removed, package A is unaffected.

The requires key has an array as its value, as a given item could require multiple items to be installed first.

<key>requires</key>
<array>
    <string>XcodeTools</string>
</array>

With requires, if you remove an item A that is required by an item B, both A and B will be removed, since presumably B will be broken without A. An example: let’s say you have a Photoshop plugin. It requires that Photoshop be installed in order to operate, so it specifies Photoshop in its requires attribute. Later you remove Photoshop, managedsoftwareupdate sees that there is a plugin installed that requires Photoshop, so it removes the plugin as well.

No checking is done for circular dependencies - so don’t make any.

<key>requires</key>
<array>
    <string>XcodeTools</string>
</array>

If the above dependencies key was included in the pkginfo for ServerAdminTools, it would ensure that XcodeTools was installed before installing ServerAdminTools. On removal, if you tried to remove XcodeTools, ServerAdminTools would also be removed.

27.6.12 update_for

This is also a list of other pkginfo items.
When processing managed_installs, munki looks at each item in turn. When considering item ‘A’, if it is installed, or scheduled to be installed, munki looks through the available catalogs, looking for other items that declare that they are updates for ‘A’. If it finds any, and they are not currently installed, it adds them to the install list.

This provides a mechanism for munki to automatically discover new updates for items without the admin having to edit existing manifest files. Items that declare (via update_for) they are updates for other items generally are not added to a manifest; Munki finds and applies them “automatically”.

Some examples:

    <key>name</key>
    <string>PhotoshopCameraRaw</string>
    <key>version</key>
    <string>5.5.0.0.0</string>
    <key>update_for</key>
    <array>
         <string>PhotoshopCS4</string>
         <string>AdobeCS4DesignStandard</string>
    </array>

and

        <key>name</key>
        <string>iWork09_Update</string>
        <key>version</key>
        <string>4.0.3.0.0</string>
        <key>requires</key>
        <array>
          <string>iWork09_Update-4.0.2.0.0</string>
        </array>
        <key>update_for</key>
        <array>
          <string>iWork09</string>
        </array>

Note that you would not use this for new versions of a package - these would simply have the same name as the older package, but a higher version number. But some (much?) commercial software packages its updates as updaters or “patches”, in which the new package is added to the existing package, instead of replacing it. The update_for key identifies these and provides the “parent” packages they update.

Note also this construction:

    <string>iWork09_Update-4.0.2.0.0</string>

This tells munki to look for a specific version (in this case ‘4.0.2.0.0’) of ‘iWork09_Update’. Without the version extension, munki always uses the most recent (or “highest”) version it can find in the catalogs that are available. You can use this construction anywhere you’d refer to a package, including in the managed_installs key of a manifest.

When processing removals, if item ‘A’ is scheduled to be removed, any item that declares it is an update for ‘A’ is also scheduled for removal if it is installed.

27.7 More optional keys

        <key>installed_size</key>
        <integer>198356</integer>
        <key>installer_item_size</key>
        <integer>588922</integer>

updatecheck uses these to determine if there is enough free space to download the installer item and install it.

27.7.1 supported_architectures

You can specify which architectures a pkg is compatible with:

PowerPC only:

        <key>supported_architectures</key>
        <array>
                <string>Power Macintosh</string>
        </array>

Intel Only (Both 32bit and 64bit) :

        <key>supported_architectures</key>
        <array>
            <string>i386</string>
            <string>x86_64</string>
        </array>

27.7.2 RestartAction

You may specify which type of Restart you would prefer for a given package:

Shutdown

    <key>RestartAction</key>
    <string>RequireShutdown</string>

Restart

    <key>RestartAction</key>
    <string>RequireRestart</string>

Logout

    <key>RestartAction</key>
    <string>RequireLogout</string>

27.7.3 Embedded uninstall scripts

You may embed uninstall scripts directly into the pkginfo item:

        <key>uninstall_method</key>
        <string>uninstall_script</string>
        <key>uninstall_script</key>
        <string>#!/bin/sh
    
    rm -rf "/Applications/Adobe Reader.app"
    rm -rf "/Library/Internet Plug-ins/AdobePDFViewer.plugin"
    rm -f "/Library/Application Support/Adobe/HelpCfg/en_US/Reader_10.0.helpcfg"
    
    pkgutil --forget com.adobe.acrobat.reader.10.reader.app.pkg.en_US
    pkgutil --forget com.adobe.acrobat.reader.10.reader.browser.pkg.en_US
    pkgutil --forget com.adobe.acrobat.reader.10.reader.appsupport.pkg.en_US
        </string>
        <key>uninstallable</key>
        <true/>

27.7.4 preinstall_script/postinstall_script

pkginfo items can optionally contain a preinstall_script and/or a postinstall_script. These are embedded shell scripts that are similar to the optional embedded uninstall_script.

These are executed as root. Assume nothing about the environment, including command paths.

Failure of the preinstall_script will abort the installation attempt.
Failure of the postinstall_script will log errors, but the install will be considered complete.

27.7.5 preuninstall_script/postuninstall_script

pkginfo items can optionally contain a preuninstall_script and/or a postuninstall_script. These are embedded shell scripts that are similar to the optional embedded uninstall_script.

These are executed as root. Assume nothing about the environment, including command paths.

Failure of the preuninstall_script will abort the removal attempt.
Failure of the postuninstall_script will log errors, but the removal will be considered complete.

27.7.6 preinstall_alert/preuninstall_alert

pkginfo files can optionally contain preinstall_alert and preuninstall_alert keys. This allows an admin to prompt the user with a message from which the user can confirm or cancel after they click Install or Remove on an optional install. Confirming will continue the install/uninstall action, cancelling will cancel the install/uninstall action. The default action on the alert is Cancel

These are intended for use with Optional Installs – if a user clicks Install on an optional item, if a preinstall_alert is present it will be displayed. If they attempt to remove the optional item and a postinstall_alert is present, it will be displayed.

Uses for this would be where a software package has extra detail a user needs to be aware of before installing, e.g.

  • performing an OS upgrade or package install that may take some time
  • software that has a brief condition of use (provided, but unsupported).
  • install or uninstall of software that may have repercussions (uninstalling this package means you will no longer be able to access foo)

The format for the keys is the same for both and contains a dictionary of items, all of which are optional

    <key>preinstall_alert</key> 
    <dict>
        <key>alert_title</key>
        <string></string>
        <key>alert_detail</key>
        <string></string>
        <key>ok_label</key>
        <string></string>
        <key>cancel_label</key>
        <string></string>
    </dict>
<key>preuninstall_alert</key> 
    <dict>
        <key>alert_title</key>
        <string></string>
        <key>alert_detail</key>
        <string></string>
        <key>ok_label</key>
        <string></string>
        <key>cancel_label</key>
        <string></string>
    </dict>
Key Type Notes Default Value
alert_title string the main alert message text Attention
alert_detail string informative text to explain the alert further Some conditions apply to this software. Please contact your administrator for more details
ok_label string label text of the confirmation button OK
cancel_label string label text of the cancel button Cancel

All keys are optional and will use the default text if not specified. This is explicit so if you include a key but leave it blank, it will replace the default value with blank text. For example, if you only wanted to specify alert_detail you would only specify the alert_detail key and string pair in the dictionary item like so:

    <key>preinstall_alert</key> 
    <dict>
        <key>alert_detail</key>
        <string>Some important information regarding this package</string>
    </dict>

27.7.7 Unattended Installs and Uninstalls

Using an additional key in the pkginfo file, admins can designate installs/updates or uninstalls to occur silently and unattended before the user is notified of any remaining installs/updates/removals. This feature should be used with care. Installs may occur while the user is running the application being updated or removed. (Use blocking_applications to make this less likely.) Unattended installs/uninstalls are attempted in the background during automatic background runs. If Munki cannot install/remove an item in an unattended manner (because a blocking_application is running), it will try during future runs, and will also display the update in Managed Software Update if the update is still available at the time Managed Software Update is invoked.

unattended_install takes effect for managed_installs and managed_updates [[Manifests]] install types, and unattended_uninstalls for managed_uninstalls.

Below is an example of the unattended pkginfo keys, where the install would not be unattended (the user will be notified as normal), and the uninstall is unattended (package will be uninstalled in the background).

        <key>unattended_install</key>
        <false/>
        <key>unattended_uninstall</key>
        <true/>

Note: this is an optional key, setting it to false is the same as omitting the key altogether.

27.7.8 Force Install After Date

Using an additional key in the pkginfo file, admins can designate installs/updates to forcefully logout and/or restart a machine in order to install a package requiring such. Given that this feature has the potential to forcefully restart a machine while a user is performing work or has unsaved work open, it should be used wisely and and admins should provide sufficient notice to their users. We recommend setting force datetimes at least 2 weeks in the future.

27.7.8.1 Package Info Key

The pkginfo key, force_install_after_date, is a date value expressed in the following format: yyyy-mm-ddThh:mm:ssZ. For example, August 3rd 2017 at 1PM would be set like this:

<key>force_install_after_date</key>
<date>2017-08-03T13:00:00Z</date>

The date specified here is evaluated in local time, so all timezone specific information is stripped and ignored. In the example above, clients will forcefully logout and perform the install at 1PM based on whatever the local time of the client machine is.

If you need an install/update requiring a logout/reboot to be forced as soon as possible, specify a date in the past. Do note that this may be highly disruptive to your users, though.

27.7.8.2 Notifications

When there are one or more items with force_install_after_date set in the list of pending updates, Managed Software Center will display additional informational text and alerts.

If the “deadline” for a forced install is more than a day away, MSC update notifications still only display based on the ManagedInstalls DaysBetweenNotifications setting, which defaults to once per day.

Starting at 240 minutes (4 hours) before the force datetime, the MSC GUI will be displayed with a more intrusive warning notification. This notification will be displayed at 240, 180, 120, 90, 60, 45, 30, 15, 10, and 5 minutes. A final notification will also be displayed roughly 1 minute before force logout/restart.

27.7.8.3 Minimum Notification

If a machine is powered off or asleep while a force install is due to take place, it will start at 60 minutes worth of notifications. If the machine then is put asleep until that new 60 minute counter has been started, the machine will perform the force install within minutes of waking up.

27.7.9 installer_environment

This key allows the admin to specify arbitrary environment variables for use by /usr/sbin/installer.

Some (broken) packages and pre/post script that only do the right thing if /usr/bin/installer’s environment is that of the current console user. Since Munki runs as root, this is not the case when Munki installs items.

You may be able to work around broken pre/postinstall scripts that reference the current username or user home by specifying the correct values in an installer_environment dictionary.

Here’s the most common implementation:

    <key>installer_environment</key> 
    <dict> 
        <key>USER</key> 
        <string>CURRENT_CONSOLE_USER</string> 
    </dict>

Which causes Munki to substitute the current console user name (or root if there is none). Alternately, you could specify a known-to-exist local user:

    <key>installer_environment</key> 
    <dict> 
        <key>USER</key> 
        <string>localstudentuser</string> 
    </dict>

27.7.10 installable_condition

This key takes a string in the NSPredicate format, and is an expression that must evaluate true for the package to be considered “installable” on the host. It can be used to support more sophisticated OS X version requirements than can be provided by the minimum/maximum_os_version keys, but can take advantage of any built-in conditions provided by Munki (machine_type, machine_model, etc.) or admin-provided conditions.

A couple scenarios where this may be useful:

  • you want to specify specific hardware/software requirements for a package to prevent it being installed on systems that are incompatible
  • you have a support package that has at least two versions for different configurations (for example, one for desktops and one for laptops), and you want to be able to give them the same name to simplify your manifests

This is only a filtering mechanism; Munki does not use this expression to determine whether an item is installed or should be installed. If an installable_condition evaluates as false, a warning will be logged on the client in similar fashion to a minimum_os_version that’s not satisfied.

For more examples on conditional items in the context of manifests, see [[Conditional Items]].

Here’s an example that specifies that a package requires a minimum OS X version of 10.7.5 or 10.8.2:

    <key>installable_condition</key>
    <string>(os_vers BEGINSWITH "10.7" AND os_vers_patch &gt;= 5) OR (os_vers BEGINSWITH "10.8" AND os_vers_patch &gt;= 2)</string>

…or a more succinct version that would evaluate true as long as the version is between 10.7.5-10.7.9 or 10.8.2-10.8.9 inclusively:

    <key>installable_condition</key>
    <string>os_vers MATCHES '10\.(7\.[5-9]|8\.[2-9])'</string>

Adding additional metadata for use with Apple Software Updates

27.7.11 Introduction

Munki supports admin-provided additional metadata for Apple Software Updates.

By specifying additional metadata, admins can allow an Apple Software Update to be installed in an unattended manner, force an install after a given date, or override the display_name, description, RestartAction and/or array of blocking_applications.

27.7.12 Details

Read more about Munki’s support for installing Apple software updates here: Apple Software Updates With Munki

This additional metadata does not and can not influence what updates are offered by Apple Software Update – it can only provide additional information for Munki to use when displaying and installing available updates.

Pkginfo items created for this purpose (providing additional Apple software update metadata) should never be added to any manifest. Think instead of the list of available Apple software updates as a dynamically generated manifest. If an update is offered by Apple Software Update (and therefore in this virtual Apple update manifest), Munki will check for an apple_update_metadata item with the same name as the update’s ProductKey.

27.7.12.1 Identifying Updates

Apple Software Update items are uniquely identified by their ProductKey. You can find the ProductKey in a Reposado product listing, or by getting detail on an update using Apple’s Software Update Service.

Some recent versions of OS X/macOS also record the product keys for pending updates in /Library/Preferences/com.apple.SoftwareUpdate.plist under ‘RecommendedUpdates’.

You may also browse the contents of /Library/Updates.

Finally, you might find this tool useful: https://github.com/hjuutilainen/sus-inspector

Here’s an example of using Reposado to find ProductKeys for iTunes:

% ./repoutil --products | grep iTunes
061-3453        iTunes Producer                                    1.6        2007-11-29  (Deprecated)
041-5144        iTunes Producer                                    2.6.0      2012-03-28  (Deprecated)
zzzz041-6245    iTunes                                             10.6.3     2012-10-11  
041-8613        iTunes Producer                                    2.8.0      2012-11-05  (Deprecated)
zzzz041-9793    iTunes                                             11.0.2     2013-02-21  
zzzz041-9792    iTunes                                             11.0.2     2013-02-21  
041-8900        iTunes Producer                                    2.9.0      2013-03-06  

The ProductKey is displayed in the first column of the Product listing.

Munki uses the ProductKey as the “name” of the update.

27.7.12.2 Supported additional metadata keys:

  blocking_applications
  description
  display_name
  force_install_after_date
  unattended_install
  RestartAction

27.7.12.3 Creating Apple Update Metadata pkginfo:

Both makepkginfo and munkiimport can use a new option: --apple-update, which is intended to accept an Apple update productKey. Let’s use the recent iTunes 11.0.2 update as an example:

$ makepkginfo --apple-update zzzz041-9597 --unattended_install --catalog=testing
<?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>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>installer_type</key>
    <string>apple_update_metadata</string>
    <key>name</key>
    <string>zzzz041-9597</string>
    <key>unattended_install</key>
    <true/>
    <key>version</key>
    <string>1.0</string>
</dict>
</plist>

You may also use munkiimport; munkiimport will then upload the created pkginfo into your repo.

Again, you should never add the name of an apple_update_metadata to any Munki manifest.
Using pre and postinstall_scripts to avoid repackaging

27.7.13 Introduction

A common reason to repackage software is to perform additional configuration tasks or install additional items. You can often avoid repackaging by creating a separate package with your changes or additions and marking that package as an update_for the original package.

Another technique to avoid repackaging is to add a preinstall_script and/or a postinstall_script to the pkginfo for an item. These scripts can take care of some of the tasks you may have previously needed to resort to repackaging to implement.

27.7.14 Details

TextWrangler, a popular text editor, is distributed as a “drag-n-drop” disk image containing the TextWrangler application. But on first launch of the TextWrangler application, the user is prompted for admin credentials so some command-line tools can be installed. One approach to avoid this prompt is to repackage TextWrangler so that the applications and command-line tools are installed up front. But this can quickly become tedious as newer versions of TextWrangler are released.

An alternative is to implement a postinstall_script that copies the command-line tools from the TextWrangler bundle to their intended locations. Here’s an example of such a postinstall_script embedded into the pkginfo for TextWrangler 3.5.3:

<?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>production</string>
    </array>
    <key>description</key>
    <string>Free text editor from the makers of BBEdit</string>
    <key>display_name</key>
    <string>TextWrangler</string>
    <key>installer_item_hash</key>
    <string>4102747e33d6af3bfe19a1d4eaf9792d65bdf98952cefa9afcf1a008e5fda965</string>
    <key>installer_item_location</key>
    <string>apps/TextWrangler_3.5.3.dmg</string>
    <key>installer_item_size</key>
    <integer>12675</integer>
    <key>installer_type</key>
    <string>copy_from_dmg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.barebones.textwrangler</string>
            <key>CFBundleName</key>
            <string>TextWrangler</string>
            <key>CFBundleShortVersionString</key>
            <string>3.5.3</string>
            <key>minosversion</key>
            <string>10.5</string>
            <key>path</key>
            <string>/Applications/TextWrangler.app</string>
            <key>type</key>
            <string>application</string>
        </dict>
    </array>
    <key>items_to_copy</key>
    <array>
        <dict>
            <key>destination_path</key>
            <string>/Applications</string>
            <key>source_item</key>
            <string>TextWrangler.app</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>TextWrangler</string>
    <key>postinstall_script</key>
    <string>#!/bin/sh

mkdir -p -m 775 /usr/local/bin
cp /Applications/TextWrangler.app/Contents/MacOS/edit /usr/local/bin/
cp /Applications/TextWrangler.app/Contents/MacOS/twdiff /usr/local/bin/
cp /Applications/TextWrangler.app/Contents/MacOS/twfind /usr/local/bin/

mkdir -p -m 775 /usr/local/share/man/man1
cp /Applications/TextWrangler.app/Contents/Resources/edit.1 /usr/local/share/man/man1/
cp /Applications/TextWrangler.app/Contents/Resources/twdiff.1 /usr/local/share/man/man1/
cp /Applications/TextWrangler.app/Contents/Resources/twfind.1 /usr/local/share/man/man1/

exit 0
    </string>
    <key>uninstall_method</key>
    <string>remove_copied_items</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>3.5.3</string>
</dict>
</plist>

Since these scripts are embedded in XML, you must escape certain characters that are special to the XML parser.
Specifically, the following characters and their corresponding XML entities:

  • & is replaced with &amp;
  • < is replaced with &lt
  • > is replaced with &gt

You may want to use makepkginfo to do the escaping for you.

If your pre- or postinstall_script is in a file, you can generate the embedded version of the script, complete with proper escaping, with makepkginfo like so:

makepkginfo --postinstall_script /path/to/a/script
makepkginfo --preinstall_script /path/to/a/script

Failure of the preinstall_script will abort the installation attempt.
Failure of the postinstall_script will log errors, but the install will be considered complete.

27.7.15 Logging

echo statements will be logged to /Library/Managed Installs/Logs/ManagedSoftwareUpdate.log
Details on Munki’s preferences

27.7.16 Introduction

Munki stores its configuration info in the “ManagedInstalls” preferences domain. By default, this info is stored in /Library/Preferences/ManagedInstalls.plist, but you can also use MCX, configuration profiles, or /private/var/root/Library/Preferences/ManagedInstalls.plist, or a combination of these locations with the normal defaults precedence:

  • MCX/Configuration profiles
  • /private/var/root/Library/Preferences/ByHost/ManagedInstalls.XXXXXX.plist
  • /private/var/root/Library/Preferences/ManagedInstalls.plist
  • /Library/Preferences/ManagedInstalls.plist

Munki 3.1 new feature <p/> managedsoftwareupdate has a new --show-config option, which will print Munki’s current configuration. This can be helpful when troubleshooting the potentially confusing interaction between different preference levels and managed preferences.

27.7.17 Details

Here’s a sample /Library/Preferences/ManagedInstalls.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ClientIdentifier</key>
    <string>arbitrary_name</string>
    <key>SoftwareRepoURL</key>
    <string>http://munkiwebserver/repo</string>
    <key>LoggingLevel</key>
    <integer>1</integer>
    <key>DaysBetweenNotifications</key>
    <integer>1</integer>
</dict>
</plist>

27.7.17.1 Supported ManagedInstalls Keys

(Scroll the table horizontally to see all columns – GitHub’s default view tends to hide the last column, which contains a description of the key.)

Key Type Default Description
AppleSoftwareUpdatesOnly boolean false If true, only install updates from an Apple Software Update server. No Munki repository is needed or used.
InstallAppleSoftwareUpdates boolean false If true, install updates from an Apple Software Update server, in addition to “regular” Munki updates.
UnattendedAppleUpdates boolean false If true, updates that declare no “must-close” applications, or have one or more “must-close” applications, none of which is running, and do not require a logout or restart will be installed as part of a normal periodic background run without notifying the user. (OS X 10.10+, Munki 2.5+)
(SoftwareUpdateServerURL) Deprecated string Catalog URL for Apple Software Updates. If undefined or empty, Munki will use the same catalog that the OS uses when you run Apple’s Software Update application or call /usr/sbin/softwareupdate.
SoftwareRepoURL string http://munki/repo Base URL for Munki repository
PackageURL string <SoftwareRepoURL>/pkgs Base URL for Munki pkgs. Useful if your packages are served from a different server than your catalogs or manifests.
CatalogURL string <SoftwareRepoURL>/catalogs Base URL for Munki catalogs. Useful if your catalogs are served from a different server than your packages or manifests.
ManifestURL string <SoftwareRepoURL>/manifests Base URL for Munki manifests. Useful if your manifests are served from a different server than your catalogs or manifests.
IconURL string <SoftwareRepoURL>/icons Base URL for product icons. Useful if your icons are served from a different server or different directory than the default.
ClientResourceURL string <SoftwareRepoURL>/client_resources Base URL for custom client resources for Managed Software Center. Useful if your resources are served from a different server or different directory than the default.
ClientResourcesFilename string manifest name.zip or site_default.zip Specific filename to use when requesting custom client resources.
HelpURL string none If defined, a URL to open/display when the user selects “Managed Software Center Help” from Managed Software Center’s Help menu.
ClientIdentifier string Identifier for Munki client. Usually is the same as a manifest name on the Munki server. If this is empty or undefined, Munki will attempt the following identifiers, in order: fully-qualified hostname, “short” hostname, serial number and finally, “site_default”
ManagedInstallDir string /Library/Managed Installs Folder where Munki keeps its data on the client.
LogFile string /Library/Managed Installs/Logs/ManagedSoftwareUpdate.log Primary log is written to this file. Other logs are written into the same directory as this file.
LogToSyslog boolean false If true, log to syslog in addition to ManagedSoftwareUpdate.log.
LoggingLevel integer 1 Higher values cause more detail to be written to the primary log.
DaysBetweenNotifications integer 1 Number of days between user notifications from Managed Software Center. Set to 0 to have Managed Software Center notify every time a background check runs if there are available updates.
UseNotificationCenterDays integer 3 (New in Munki 3) Number of days Notification Center notifications should be used before switching to launching Managed Software Center. See [[Notification Center Support]].
UseClientCertificate boolean false If true, use an SSL client certificate when communicating with the Munki server. Requires an https:// URL for the Munki repo. See ClientCertificatePath for details.
UseClientCertificateCNAsClientIdentifier boolean false If true, use the CN of the client certificate as the Client Identifier.Used in combination with the UseClientCertificate key.
SoftwareRepoCAPath string (empty) Path to the directory that stores your CA certificate(s). See the curl man page for more details on this parameter.
SoftwareRepoCACertificate string /Library/Managed Installs/certs/ca.pem Absolute path to your CA Certificate.
ClientCertificatePath string /Library/Managed Installs/certs/[munki.pem\|client.pem\|cert.pem] Absolute path to a client certificate. There are 3 defaults for this key. Concatenated cert/key PEM file accepted.
ClientKeyPath string (empty) Absolute path to a client private key.
AdditionalHttpHeaders array (empty) This key provides the ability to specify custom HTTP headers to be sent with all curl() HTTP requests. AdditionalHttpHeaders must be an array of strings with valid HTTP header format.
PackageVerificationMode string hash Controls how Munki verifies the integrity of downloaded packages. Possible values are: none: No integrity check is performed. hash: Integrity check is performed if package info contains checksum information. hash_strict: Integrity check is performed, and fails if package info does not contain checksum information.
SuppressUserNotification boolean false If true, Managed Software Center will never notify the user of available updates. Managed Software Center can still be manually invoked to discover and install updates.
SuppressAutoInstall boolean false If true, Munki will not automatically install or remove items.
SuppressLoginwindowInstall boolean false If true, Munki will not install items while idle at the loginwindow except for those marked for unattended_install or unattended_uninstall.
SuppressStopButtonOnInstall boolean false If true, Managed Software Center will hide the stop button while installing or removing software, preventing users from interrupting the install.
InstallRequiresLogout boolean false If true, Managed Software Center will require a logout for all installs or removals.
ShowRemovalDetail boolean false If true, Managed Software Center will display detail for scheduled removals.
MSULogEnabled boolean false Log user actions in the GUI. See [MSU-Logging]
MSUDebugLogEnabled boolean false Debug logging for Managed Software Center. See [MSU-Logging]
LocalOnlyManifest string (empty) Defines the name of your LocalOnlyManifest. Setting this activates the feature. Unsetting it means Munki will remove the file on the next run. See LocalOnlyManifest
FollowHTTPRedirects string none Defines whether Munki will follow all, some or no redirects from the web server. See FollowHTTPRedirects
IgnoreSystemProxies boolean false If true, HTTP and/or HTTPS proxies set system-wide will be ignored, connections will be made directly.
PerformAuthRestarts boolean false (New in Munki 3) If true, Munki will attempt to perform a filevault auth restart. See [[Authorized-Restarts]].
RecoveryKeyFile string none (New in Munki 3) Absolute path to a plist file containing filevault credentials in key/value format. Used to perform auth restarts. See [[Authorized-Restarts]].

27.7.17.2 Additional Notes

27.7.17.2.1 LogFile

Munki normally writes its logs to /Library/Managed Installs/Logs/, with the main log written to ManagedSoftwareUpdate.log in that directory. Other logs are named “Install.log”, “errors.log”, and “warnings.log”. If you’d like the logs to be written somewhere else (for example /var/log or /Library/Logs), set LogFile to the desired pathname of the main log:

sudo defaults write /Library/Preferences/ManagedInstalls LogFile "/var/log/munki/managedsoftwareupdate.log"

The other logs will be written to the same directory.

27.7.17.2.2 InstallAppleSoftwareUpdates

If this key is present and set to True, Munki will call softwareupdate and attempt to install Apple Software Updates.

27.7.17.2.3 SoftwareUpdateServerURL

This key can be used to point to an internal Apple Software Update server.

27.7.17.2.4 SuppressUserNotification

This key (when present and value is set to True) causes Munki to never notify users of available updates. This might be useful in a lab environment, where you’d like updates to be applied only when no-one is logged in and the machine is at the login window.

27.7.17.2.5 SuppressAutoInstall

Normally, Munki automatically installs and removes software if there are changes needed and that machine is at the loginwindow with no users logged in. If you have a need to do updates always and only with the consent of the user, setting SuppressAutoInstall to True prevents Munki from automatically installing updates (and processing removals).

27.7.17.2.6 SuppressLoginwindowInstall

(Added in version 0.8.4.1696.0) If this preference is set to true, Munki will not install updates when idle at the loginwindow, with the exception of updates marked for unattended_install or unattended_uninstall.

27.7.17.2.7 ShowRemovalDetail

By default, Managed Software Update.app suppresses detail on what will be removed, instead showing a simple “Software removals” entry in the list. If you’d like Managed Software Update.app to show specific detail about what will be removed, set ShowRemovalDetail to True. This key has no effect on /usr/local/munki/managedsoftwareupdate, which always shows all detail.

27.7.17.2.8 InstallRequiresLogout

Managed Software Center.app enforces a logout before it installs or removes software only if one or more items to be installed/removed requires a logout or restart. You can force a logout for all updates by setting InstallRequiresLogout to True. This key has no effect on running /usr/local/munki/managedsoftwareupdate from the command-line.

27.7.17.2.9 AdditionalHttpHeaders

This key provides the ability to specify custom HTTP headers to be sent with all HTTP/HTTPS requests. AdditionalHttpHeaders must be an array of strings with valid HTTP header format. For example:

<key>AdditionalHttpHeaders</key>
<array>
    <string>Key-With-Optional-Dashes: Foo Value</string>
    <string>another-custom-header: bar value</string>
</array>

One could use this to obtain a cookie in a preflight script and update ManagedInstalls.plist with the appropriate header. However, it is recommended that you use Secure Config for sensitive data (i.e. cookie) since ManagedInstalls.plist is world-readable.

27.7.17.2.10 LocalOnlyManifest

Defines the name of a locally-installed manifest, typically managed/created/installed by some external management system.

This feature is designed for integrating Munki with a configuration management system like Chef or Puppet, and can be safely ignored by most Munki admins.

Creating a LocalOnlyManifest enables administrators to specify additional managed_installs or managed_uninstalls in a local file that augments those defined on the Munki server.

For example, if your Munki client is inheriting the site_default manifest and you wanted to add a managed_install without editing that server-side manifest, you could define a LocalOnlyManifest and populate it with the selected package …

Define a LocalOnlyManifest:

sudo defaults write /Library/Preferences/ManagedInstalls LocalOnlyManifest extra_packages

Edit the manifest:

<?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>managed_installs</key>
    <array>
        <string>Firefox</string>
    </array>
    <key>managed_uninstalls</key>
    <array>
        <string>GoogleChrome</string>
    </array>
</dict>
</plist>

Save it as: /Library/Managed\ Installs/manifests/extra_packages

This example ensures Firefox remains added to the list of managed_installs, and GoogleChrome remains added to the list of managed_uninstalls. As with any manifests, the admin must be careful not to create contradictions.

NOTE: Adding additional catalogs to your LocalOnlyManifest will have no effect. Packages managed using a LocalOnlyManifest must already be present in the available catalogs.

27.7.17.2.11 FollowHTTPRedirects

By default, Munki will not follow redirects that are returned by the web server. The FollowHTTPRedirects preference defines whether Munki should follow all redirects or only redirect to HTTPS URLs. The possible values for FollowHTTPRedirects are:

  • none - This is the default and is the same as Munki’s original behaviour. No redirects are followed.
  • https - Only redirects to URLs using HTTPS are followed. Redirects to HTTP URLs are not followed.
  • all - Redirects to both HTTP and HTTPS URLs are followed.

27.7.17.3 Secure Configuration

If there are parts of your Munki configuration you consider sensitive information (for example, repo authentication information, special HTTP headers, or even the Munki repo URLs), instead of storing those preferences in the world-readable /Library/Preferences/ManagedInstalls.plist file, you can use a more secure location for some Munki preferences: /var/root/Library/Preferences/ManagedInstalls.plist.

Use of this alternate preferences location is completely optional. If you do decide to use it, make sure you fully understand the implications.

Munki uses Apple’s defaults mechanism to store and access its preferences. Since the core Munki tools run as root, they can access preferences from this file: /private/var/root/Library/Preferences/ManagedInstalls.plist as well as the “normal” /Library/Preferences/ManagedInstalls.plist file.

Non-admin users of machines managed by Munki will not be able to access or read the contents of /private/var/root/Library/Preferences/ManagedInstalls.plist, so this provides some additional security for possibly sensitive preference values.

Note: preferences defined in /var/root/Library/Preferences/ManagedInstalls.plist have a higher precedence than those defined /Library/Preferences/ManagedInstalls.plist, so any preferences set here will override preferences defined in /Library/Preferences/ManagedInstalls.plist! This might confuse you or other admins who think only to look in /Library/Preferences/ManagedInstalls.plist and forget that some preferences are also defined in /private/var/root/Library/Preferences/ManagedInstalls.plist.

VERY IMPORTANT NOTE: the following preferences are required to be defined in /Library/Preferences/ManagedInstalls.plist (or set via MCX), as the GUI portion of Munki runs as the logged in user, not root. Do not place them in /var/root/Library/Preferences/ManagedInstalls.plist, or you may encounter unexpected behavior from Managed Software Center.app, since it can’t read the contents of /var/root/Library/Preferences/ManagedInstalls.plist:

  • ManagedInstallDir
  • InstallAppleSoftwareUpdates
  • AppleSoftwareUpdatesOnly
  • ShowRemovalDetail
  • InstallRequiresLogout
  • HelpURL

27.7.17.4 Using the defaults command

If you use the /usr/bin/defaults command to set values for keys in ManagedInstalls.plist, remember that values default to the “string” type. If you are writing a boolean, integer, or array value, be sure to add the appropriate type flag. For example:

defaults write /Library/Preferences/ManagedInstalls SuppressAutoInstall -bool false

See man defaults for a complete list of type flags.
Information about munki preflight and postflight scripts

27.7.18 Introduction

managedsoftwareupdate supports optional preflight and postflight scripts. A preflight script is executed before managedsoftwareupdate does the bulk of its work. A non-zero exit code causes managedsoftwareupdate to abort its run. A postflight script is executed just before managedsoftwareupdate exits. It’s a good place to analyze the logs and report errors to a central location.

27.7.19 Details

Both the preflight and postflight scripts must reside in the same directory as managedsoftwareupdate.

A preflight script must be named “preflight” and have no extension. It must be marked as executable. A non-zero exit code causes managedsoftwareupdate to exit.

A postflight script must be named “postflight” and have no extension. It must be marked as executable.

Both scripts are passed a single parameter - the “runtype”. This allows the script to distinguish between the various “modes” in which managedsoftwareupdate runs. These runtypes have not yet been formally defined, and may change in the future. Here are the current runtypes:

  • auto - this corresponds to the periodic run of managedsoftwareupdate, currently controlled by /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist

  • logoutinstall - this runtype occurs when a user has chosen to install updates using Managed Software Center.app and is logging out and installing (because the items to be installed require a logout or restart). This always happens at the login window.

  • checkandinstallatstartup - designed for the initial bootstrapping of a machine, this runtype causes munki to do a check (and install if needed) at startup. Triggered by the existence of /Users/Shared/.com.googlecode.munki.checkandinstallatstartup This always happens at the login window.

  • installwithnologout - user has chosen to install updates without logging out.

  • manualcheck - user has launched Managed Software Center.app manually, and it is checking for updates.

  • custom - None of the above.

Note that since the pre and postflight scripts are in the same directory as managedsoftwareupdate, if they are written in python, they can easily import any of the modules in munkilib, including munkistatus, which would allow the scripts to provide user feedback in a manner similar to the other Munki tools.

The postflight script is an ideal place to parse the logs from the current managedsoftwareupdate run and forward errors or warnings to a central location, via email or a web cgi, or perhaps code that adds records to a database.

27.7.20 Reporting consoles

Reporting consoles like Sal and MunkiReport-PHP make use of managedsoftwareupdate preflight and postflight scripts to upload client data to their respective databases.

27.7.21 Examples

Here are two examples uses of preflight scripting with their own documentation on the wiki:

  • [[Dynamic Client Configurations Via Preflight Scripting]]
  • [[WPKG like Dynamic Manifests Without CGI]]

Here’s an example of a script that emails warnings or errors to an administrator:

#!/usr/bin/python
# encoding: utf-8
"""
managedsoftwareupdate postflight
    
Created by Greg Neagle on 2010-06-02.
"""
    
import sys
import os
    
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders
import plistlib
    
# Change the following as needed
mail_from = "root@myorg.org"
mail_to = ["admin@myorg.org"]
smtpserver = "smtp.myorg.org"
managed_installs_dir = "/Library/Managed Installs"
    
def send_mail(send_from, send_to, 
              subject, text, files=[], 
              server="localhost"):
    assert type(send_to)==list
    assert type(files)==list
    
    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = ", ".join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject
    
    msg.attach( MIMEText(text) )
    
    for f in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(f,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 
                        'attachment; filename="%s"' % os.path.basename(f))
        msg.attach(part)
    
    smtp = smtplib.SMTP(server)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()
    
    
def main():    
    report = os.path.join(managed_installs_dir, "ManagedInstallReport.plist")
    if os.path.exists(report):
        pl = plistlib.readPlist(report)
        errors = pl.get("Errors","")
        warnings = pl.get("Warnings","")
        if not (errors or warnings):
            return
    
        subject = ""
        body = "The following issues were reported:\n\n"
        if errors:
            subject = "[Managed Installs errors] on %s" % os.uname()[1]
            body = body + "Errors:\n%s\n\n" % "\n".join(errors)
        if warnings:
            if not subject:
                subject = "[Managed Installs warnings] on %s" % os.uname()[1]
            body = body + "Warnings:\n%s\n\n" % "\n".join(warnings)
    
        body = body + "A full report is attached.\n"
        attachments = [report]
    
        send_mail(mail_from, 
                  mail_to, 
                  subject, 
                  body, 
                  attachments,
                  smtpserver)
    
    
if __name__ == '__main__':
    main()

Basic info on product icons for Munki 2

27.7.22 Introduction

The new Managed Software Center application displays “icons” (or more accurately, artwork) for software items. If you don’t want a boring interface full of generic package icons, you should provide artwork for Managed Software Center to display.

27.7.23 Details

Product artwork is typically stored in a new “icons” directory in your Munki repo. The preferred format is PNG. The preferred resolution is 350x350.

Note: Some web servers are configured to redirect requests for items in a top-level “icons” directory to some other directory. Configure your web server appropriately, or use the IconURL preference in Munki’s preferences to direct the client to use a different URL. See [[here|Preferences#supported-managedinstalls-keys]] for more information on Munki’s preferences. See your web server’s documentation for configuration information for your web server.

managedsoftwareupdate attempts to download product artwork for all optional items and any managed_installs or removals that are currently applicable.

When looking for product artwork, managedsoftwareupdate checks for an ’icon_name" key in the item’s pkginfo. If this exists and has a file extension, the filename is requested. Otherwise, “.png” is appended to the name to be requested. If the pkginfo does not have an ’icon_name" key, the pkginfo “name” key plus “.png” will be requested.

Example:

For a pkginfo item with the name “Firefox” that has no “icon_name” defined, managedsoftwareupdate might request “http://munki/repo/icons/Firefox.png” (Exact URL depends on Munki’s SoftwareRepoURL and IconURL preferences.)

If for some reason you wish to store your icons under an alternative URL, you can set Munki’s IconURL to your desired base URL. This follows the pattern of ManifestURL, CatalogURL and PackageURL as alternate base URLs.

27.7.23.1 Making icons

27.7.23.1.1 iconimporter

There is a rough tool available to assist with the process of generating product icons for an existing repo. It is not available in any of the Munki tools packages, but can be found in the Git repo in the Munki2 branch at code/client/iconimporter.

Direct link: https://github.com/munki/munki/blob/master/code/client/iconimporter
(If you download this tool separately, you must copy it into /usr/local/munki in order for it to work)

./iconimporter /path/to/repo_root

Will find the latest versions of every item in your Munki repo and attempt to extract application icons from each item, convert the icons to png files and save them under repo_root/icons as name.png, where ‘name’ is the value of the name key in the relevant pkginfo.

Some packages will contain multiple application icons. In this case, iconimporter extracts them all, saving them as name_1.png, name_2.png, name_3.png. It’s up to you to look at the icons, rename the one you want to use, and delete the remainder.

iconimporter only attempts to extract icons from copy_from_dmg installers and Apple pkg installers.

There are almost certainly rough edges here. This probably won’t always be a standalone tool. But it should be useful while testing to get a large number of product icons into your repo.

27.7.23.2 munkiimport

munkiimport will now offer to attempt to extract an icon for items that don’t already have an icon in the repo:

% munkiimport GoogleChrome.dmg
This item is similar to an existing item in the repo:
            Item name: GoogleChrome
         Display name: Google Chrome
          Description: Google's web browser.
              Version: 34.0.1847.137
  Installer item path: apps/GoogleChrome-34.0.1847.137.dmg

Use existing item as a template? [y/n] y

<...snip...>

Import this item? [y/n] y
Attempt to create a product icon? [y/n] y
Attempting to extract and upload icon...
Created icon: /Users/Shared/munki_repo/icons/GoogleChrome.png
Copying GoogleChrome.dmg to /Users/Shared/munki_repo/pkgs/apps/GoogleChrome-35.0.1916.114.dmg...
Saving pkginfo to /Users/Shared/munki_repo/pkgsinfo/apps/GoogleChrome-35.0.1916.114.plist...
Rebuild catalogs? [y/n] y
Rebuilding catalogs at /Users/Shared/munki_repo...

27.7.23.3 Behind the scenes

managedsoftwareupdate downloads any available product icons into the Munki data directory (typically /Library/Managed Installs) inside an icons subdirectory. On launch, Managed Software Center.app creates a symlink to that directory in its html directory: ~/Library/Caches/com.googlecode.munki.ManagedSoftwareCenter/html/icons
The following companies provide Munki training, a managed Munki solution, professional support for your own Munki deployment, or some combination of the above.
(These are not recommendations or endorsements, but merely a starting point for your research):

Australia:

Canada:

Finland:

France:

Germany:

Ireland:

Japan:

New Zealand:

Sweden:

UK:

USA:

Russia:

Spain:

Switzerland:

Worldwide:

27.7.23.4 2.0.0 Build 2212 release notes - 17 Sep 2014

Official 2.0 release of the Munki tools.

  • All-new user interface: Managed Software Center. Supports OS X 10.6+. No support for 10.5.

27.7.23.5 1.0.0 Build 1864 release notes - 10 Jan 2014

Official 1.0.0 release of the Munki tools. No code changes from previous release.

27.7.23.6 0.9.2 Build 1863 release notes - 17 Dec 2013

  • Logging changes

  • Yet Another Unicode handling fix

  • supported_architectures change: computers that have an arch of i386 but can run 64bit apps should now allow packages with x86_64 arch to install. Thanks to Jesse Peterson.

See https://code.google.com/p/munki/source/list for more details on recent changes.

27.7.23.7 0.9.2 Build 1856 release notes - 26 Nov 2013

This is a Release Candidate for version 0.9.2 of the Munki tools.

  • bugfix for download speed status messages

27.7.23.8 0.9.2 Build 1855 release notes - 25 Nov 2013

This is a Release Candidate for version 0.9.2 of the Munki tools.

  • Fix for unicode values in CFBundleVersion in Info.plists

  • Changes to improve verbose messages and logging of download progress and speeds

  • Fix for curl buffering headers output in Mavericks, causing progress display not
    to function.

  • Allow changing curl path for 10.9 curl client-side cert workaround

  • Always add catalog info to pkginfo. Fixes issue with –nopkg.

  • makepkginfo now inserts some user/environment metadata into generated pkginfo
    files. It stores the metadata under the *metadata key. makecatalogs now strips
    any key starting with "*" from pkginfo before adding the pkginfo to a catalog.

27.7.23.9 0.9.2 Build 1846 release notes - 22 Oct 2013

This is a testing build – please test throughly before widespread deployment

  • Fix for a bug in the new firmware update warning code.

27.7.23.10 0.9.2 Build 1842 release notes - 14 Oct 2013

This is a testing build – please test throughly before widespread deployment

  • Managed Software Update displays warnings when a firmware update is to be installed.

  • Fixes for Optional Software update installs in Managed Software Update.app when item to be installed cannot be removed.

  • Workarounds/fixes for handling Apple Software Updates in upcoming OS releases.

  • More Unicode handling fixes

  • Munki’s support for Apple updates now ignores updates that have been marked to ignore (either via the Software Update GUI or /usr/sbin/softwareupdate –ignore

  • Changes to munkiimport and makepkginfo to deal with already-mounted disk images.

  • Support for licensed_seat_info for Optional installs.

  • Adobe CC installer fixes

  • Many other bug fixes,

27.7.23.11 0.9.0 Build 1803 release notes - 20 June 2013

  • Addresses an issue with the 10.8.4 update which would cause managedsoftwareupdate to hang for a very long time after installing the update.

  • Fixes for Adobe CCP-created packages. Thanks to Pepijn Bruienne.

  • munkiimport and makepkginfo now properly parse Adobe AAMEE/CCP packages that also include product updates. Thanks to Pepijn Bruienne for assistance.

  • Localization updates and fixes for German, Spanish, and Swedish.

  • Many bug fixes.

27.7.23.12 0.8.4 Build 1770 release notes - 02 April 2013

Changes since the 0.8.3.1679.0 release:

  • If installation fails for an item that is required by another item, Munki now properly defers installation of the dependent item(s). Similar behavior for uninstalls/removals.

  • Some Unicode/UTF-8 fixes for munkiimport.

  • Russian localization for Managed Software Update.app. Thanks to Soldatenko Rostislav.

  • Fixes for IPv6 environments.

  • Support for ‘date’ comparisons in conditional_items. See here for more info.

  • Support for version comparison keys other than CFBundleShortVersion string for installs items.

  • Apple updates and Munki updates can now appear and be installed in the same Munki “run”. An exception to this is if the Munki updates contain Apple items; in this case, Munki will not display or install any Apple Software Update items to prevent conflicts.

  • Support for adding additional metadata for Apple Software Update updates.
    Admins can override blocking_applications and RestartAction, and add “unattended_install” and “force_install_after_date” values for Apple software updates. makepkginfo and munkiimport have been extended to create the needed pkginfo. Apple updates are identified by their ProductKey. An example:

    munkiimport –apple-update zzzz041-9792 –unattended_install

Tells Munki to attempt unattended_installs of iTunes 11.0.2.
Thanks to Heig Gregorian for this implementation.
See http://code.google.com/p/munki/wiki/PkginfoForAppleSoftwareUpdates for more info

  • Many bug fixes.

See http://code.google.com/p/munki/source/list for detailed change log.

27.7.23.13 0.8.3 Build 1679 release notes - 30 Nov 2012

Official release of the 0.8.3 version of Munki tools.

  • Support for new “installable_condition” in pkginfo. See here for more info.

27.7.23.14 0.8.3 Build 1664 release notes - 08 Nov 2012

Preview release for version 0.8.3 of the Munki tools.

This is a development release – though it is believed stable, do not use in a production capacity without testing.

Some included changes since the 0.8.3.1634.0 release:

  • A workaround for problems installing recent Apple software updates under 10.8.x. This issue caused softwareupdate to crash with an NSInvalidArgumentException error.

  • Changes to the softwareupdate caching process to work around issues with Apple’s updates; some recent updates did not have valid .dist files for some languages listed in the sucatalog.

  • Change default Apple Software Update catalogs from .sucatalog.gz versions to .sucatalog versions to work around an issue with Mountain Lion’s softwareupdate.

  • Added Danish localization. Thanks to

  • In MSU.app, if removal detail is suppressed, and a removal item requires a logout, make sure MSU.app also requires a logout.

  • A fix for an issue where Munki would crash if a use clicked “Cancel” in Managed Software Update.app while removals were being processed.

  • Other bug fixes.

27.7.23.15 0.8.3 Build 1634 release notes - 27 Aug 2012

This is a development release – though it is believed stable, do not use in a production capacity without testing.

Some included changes since the 0.8.2.1475.0 release:

  • Fixes/workarounds for cfprefsd issues on Mountain Lion. This caused issues importing some disk images on Mountain Lion. Thanks to Heig Gregorian and Pepijn Bruienne.

  • managedsoftwareupdate now prevents idle sleep while installing/removing items. Thanks to Michael Lynn for the Python bindings to IOKit functions.

  • for copy_from_dmg type installs, if a destination directory does not exist, it will be created (along with any needed intermediate directories). Owner, group and mode for all created directories are based on the existing parent directory.

  • fix Managed Software Update status display over the loginwindow in Leopard

  • New optional “destination_item” key for “items_to_copy” items in “copy_from_dmg” installer_types. Specifies a different name to use for the item when copied; allows you to rename an item on copy.

  • New –destinationitemname option in makepkginfo for copy_from_dmg type installs. Sets the new - “destination_item” key.

  • New “nopkg” installer_type. Allows for pkginfo items that do all their work with embedded scripts; no actual package is installed.

  • Support for installcheck_script and uninstallcheck_script. If present, these will be used by Munki to determine the need to install or uninstall an item. A return code of 0 from the installcheck_script means install is needed; any other return code causes install to be skipped. For uninstall_check scripts, a return code of 0 means uninstall is needed; any other return code causes uninstall to be skipped.

  • New “optional” key for individual receipts. If this key is present and set to “True”, the receipt will not be considered when checking for the need to install an item.

  • Changes to Managed Software Update.app’s behavior and appearance when at the loginwindow in Lion and Mountain Lion.

  • Changes to how /usr/sbin/installer is called when installing packages. Works around an issue with scripts in recent Microsoft Office 2011 updates.

  • makepkginfo now has many, many new options that can create most available key/values for pkginfo files. Thanks to Heig Gregorian.

  • munkiimport now supports all makepkginfo options. Thanks to Heig Gregorian.

  • Previously, if ClientIdentifier is empty or undefined, Munki would ask for manifests in the following order:

1) Fully qualified hostname
2) “Short” hostname
3) “site_default”

This is now:

1) Fully qualified hostname
2) “Short” hostname
3) Machine serial number
4) “site_default”

Thanks to Nate Walck.

  • New “minimum_munki_version” key in pkginfo; setting this prevents attempted installs of a specific package unless the client’s version of munki is equal to or greater than the version defined by this key. Useful if you need an updated version of the Munki tools in place before you attempt to install a certain package.

  • Notes in pkginfo files are removed when pkginfo files are compiled into catalogs; that is, catalogs will not contain any pkginfo notes.

  • Spanish localization. Thanks to Noel Balonso.

  • Dutch localization. Thanks to Pepjin Bruienne.

  • French localization. Thanks to Claude Perrin.

  • Finnish localization. Thanks to Hannes Juutilainen.

27.7.23.16 0.8.3 Build 1564 release notes - 04 June 2012

This is a preview release for Munki 0.8.3. Do not use in a production environment without testing first!

  • Changes to how /usr/sbin/installer is called when installing packages. Works around an issue with scripts in recent Microsoft Office 2011 updates.

  • makepkginfo now has many, many new options that can create most available key/values for pkginfo files. Thanks to Heig Gregorian.

  • munkiimport now supports all makepkginfo options. Thanks to Heig Gregorian.

  • Previously, if ClientIdentifier is empty or undefined, Munki would ask for manifests in the following order:

  1. Fully qualified hostname
  2. “Short” hostname
  3. “site_default”

This is now:

  1. Fully qualified hostname
  2. “Short” hostname
  3. Machine serial number
  4. “site_default”

Thanks to Nate Walck.

  • New “minimum_munki_version” key in pkginfo; setting this prevents attempted installs of a specific package unless the client’s version of munki is equal to or greater than the version defined by this key. Useful if you need an updated version of the Munki tools in place before you attempt to install a certain package.

  • Notes in pkginfo files are removed when pkginfo files are compiled into catalogs; that is, catalogs will not contain any pkginfo notes.

  • French and Finnish localizations. Thanks to Claude Perrin and Hannes Juutilainen.

  • ApplicationInventory.plist now includes non-bundle applications.

  • Miscellaneous bug fixes.

27.7.23.17 0.8.2 Build 1475 Release notes - 20 April 2012

This is the official release for munki tools 0.8.2.

27.7.23.17.1 Known issues in this release
  • munkiimport will fail to rebuild catalogs if the makecatalogs tool is not in the same directory as munkiimport.

  • Munki preferences stored in /var/root/Library/Preferences/ManagedInstalls.plist do not work as expected under Mountain Lion DP.

  • A corrupt LaunchServices database may cause managedsoftwareupdate to throw a FileNotFound exception and exit.

27.7.23.17.2 Change log
  • Fix for installing Apple updates that would cause failures to not be reported as such.

  • Managed Software Update.app: slow down a busy loop that could consume too much CPU when displaying a restart alert.

27.7.23.18 0.8.2 Build 1473 Release notes - 12 April 2012

This is a release candidate for munki tools 0.8.2. Please test in your environment before wide deployment.

  • Managed Software Update.app: Fix for items marked for forced_install_after_date that also require logout or restart.

  • Fix localization issue for Managed Software Update.app on Snow Leopard (and possibly Leopard) when first preferred language is not English and not German.

  • installer.py: Refactor of copyFromDMG() and copyAppFromDMG() to fix some logic errors and share code between the two functions

  • installer.py: Output a deprecation warning if install_type ‘appdmg’ is encountered while installing; display an error instead of just logging if we encounter an install_type we don’t know how to handle.

27.7.23.19 0.8.2 Build 1468 Release notes - 03 April 2012

This is a release candidate for munki tools 0.8.2. Please test in your environment before wide deployment.

  • Fixed a typo in some Managed Software Update output

  • Skip /.MobileBackups directory when scanning for apps

  • make sure all Exceptions are converted to strings before sending to munkicommon.display_error() (Fix for “object has no attribute ‘rstrip’” errors)

27.7.23.20 0.8.2 Build 1466 Release notes - 22 March 2012

Note: this is a preview of the 0.8.2 release. Please use in a testing capacity only.

Changes in this release:

  • Bug fix: Fix a call to updatecheck.lookForUpdatesForVersion() with the wrong number of parameters.

27.7.23.21 0.8.2 Build 1465 Release notes - 20 March 2012

Note: this is a preview of the 0.8.2 release. Please use in a testing capacity only.

Changes in this release:

  • Support for Apple Software Update items that specify applications that must be closed before an update can be safely installed

  • Support for admin-provided scripts to add additional conditions to test against for conditional_items. Contributed by Heig Gregorian. See http://code.google.com/p/munki/wiki/ConditionalItems#Admin_Provided_Conditions for more info.

  • Added ipv4_address as an attribute available for conditional_items testing. This attribute contains an array of active IPv4 addresses on the client. See http://code.google.com/p/munki/wiki/ConditionalItems#Built-in_Conditions

  • Better support for version numbers in “requires” and “update_for” arrays to control specific versions to apply an a update to.

  • munkiimport now accepts –catalogs and –min-os-vers and –max-os-vers options. Useful for scripting munkiimport to avoid interactive specification of these options. Contributed by David Aguilar.

  • makecatalogs can now be called without a path to a repo. If you have defined a repo path vi munkiimport –configure or manifestutil –configure, makecatalogs will use that path by default. You may still specify a repo path, which will take precedence.

  • makepkginfo can now better parse certain Apple metapackages.

  • makecatalogs and manifestutil now ignore all files and subdirectories whose name begins with a period.

  • Managed Software Update.app: changes encoding of update descriptions so they will display properly in an unreleased version of Mac OS X.

27.7.23.22 0.8.2 Build 1430 Release notes - 15 February 2012

Note: this is a preview of the 0.8.2 release. Please use in a testing capacity only.

Changes in this release:

  • When caching the Apple software update catalog, we now follow redirects for compatibility with Lion’s Software Update Service when using a “unified” catalog URL.

27.7.23.23 0.8.2 Build 1425 Release notes - 13 February 2012

Note: this is a preview of the 0.8.2 release. Please use in a testing capacity only.

Changes in this release:

  • managedsoftwareupdate now uses an HTTP user-agent string compatible with Apple’s software update client when requesting software update catalogs. This should allow use of “unified” catalog URLs, which use server-side Apache rewrite rules.

  • Support for a new installer_environment dictionary in pkginfo which contains key/value pairs to set environment variables for use by /usr/sbin/installer (See http://code.google.com/p/munki/wiki/PkginfoFiles#installer_environment)

  • Managed Software Update.app now warns if a user decides to update while on battery power and less than 50% of battery power remains.

  • Changes to Adobe CS4 installs – will attempt to kill stalled Adobe AIR installations at the loginwindow

  • makecatalogs now warns if it would overwrite an existing catalog. This partially addresses an issue with munki server data on a case-insensitive volume and catalog names that differ only by case.

  • managedsoftwareupdate now waits to call Managed Software Update.app to notify the user until after the postflight script has finished executing.

  • Application inventory now written to /Library/Managed Installs/ApplicationInventory.plist for use by reporting scripts.

  • Other miscellaneous tweaks and bug fixes.

27.7.23.24 0.8.1 Build 1363 Release notes - 02 February 2012

This release adds support for conditional_items in manifests.

See http://code.google.com/p/munki/wiki/ConditionalItems for more information.

27.7.23.25 0.8.0 Build 1351 Release notes - 08 November 2011

Some of the new features available in this release:

27.7.23.26 0.7.1 Build 1173 Release notes - 11 May 2011

Some of the new features available in this release:

  • Support for preinstall and postinstall script in pkginfo. See PreAndPostinstallScripts

  • Now distributed as a metapackage. The munki admin can choose which subpackages to deploy; choosing, for example, to not deploy the munkitools_launchd subpackage in favor of a custom site-specific set of launchd files; or choosing not to deploy the munki admin tools on most machines.

  • Managed Software Update.app can now log certain user actions. See [- forced_install/forced_uninstall now are called unattended_install/unattended_uninstall (though the old name will continue to work for at least a while) and are no longer necessarily blocked if they are part of a dependency relationship. This makes unattended_installs more generally useful.

  • And, as always, lots of miscellaneous bug fixes and tweaks.

27.7.23.27 0.7.0 Build 1047 Release notes - 02 March 2011

Some of the new features available in this release:

  • The munki tools can now be used without a munki repo if all you are interested in is allowing users to install Apple Software Updates without needing admin rights. See: AppleSoftwareUpdatesWithMunki

  • A new secure configuration file option to store sensitive munki settings that might be risky to store in /Library/Preferences/ManagedInstalls.plist, which is world-readable. See: http://code.google.com/p/munki/wiki/configuration#Secure_Config

  • Support for “forced” installs and uninstalls. See:
    http://code.google.com/p/munki/wiki/PkginfoFiles#Forced_Installs_and_Uninstalls

  • Support for “Blocking Applications” - if any of these applications are running, munki will not immediately install. See BlockingApplications for more info.

  • New ‘munkiimport’ tool for importing installer items into a munki repo. See: http://code.google.com/p/munki/wiki/munkiimport

  • munki now uses the LaunchServices database and Spotlight to search for applications that are not in their default location; this is faster than the previous System Profiler implementation and finds more apps on Leopard.

  • New method for installing Apple Software Updates that is more reliable than prior methods.

  • German language localization of Managed Software Update.app, and readiness for additional localizations. Thanks to Martin R. Hufsky.

  • MCX support for the preferences normally specified in ManagedInstalls.plist. Thanks to Dan Roque.

  • An MCX manifest in Managed Software Update.app

  • Support for embedded uninstall scripts in pkginfo items. An example:

    <key>uninstall_method</key>
    <string>uninstall_script</string>
    <key>uninstall_script</key>
    <string>#!/bin/sh

    rm -rf “/Applications/Adobe Reader.app”
    rm -rf “/Library/Internet Plug-ins/AdobePDFViewer.plugin”
    rm -f “/Library/Application Support/Adobe/HelpCfg/en_US/Reader_10.0.helpcfg”

    pkgutil –forget com.adobe.acrobat.reader.10.reader.app.pkg.en_US
    pkgutil –forget com.adobe.acrobat.reader.10.reader.browser.pkg.en_US
    pkgutil –forget com.adobe.acrobat.reader.10.reader.appsupport.pkg.en_US
    </string>
    <key>uninstallable</key>
    <true/>

  • Lots of miscellaneous bug fixes and tweaks.

27.7.23.28 0.6.0 Build 759 Release notes - 27 Sep 2010

  • New copy_from_dmg installer type. Supports copying items from a disk image to arbitrary locations on the startup disk. Additionally, supports applying a custom user, group and mode to copied items. See http://code.google.com/p/munki/wiki/CopyFromDMG CopyFromDMG for details. copy_from_dmg can replace appdmg installer types. You can tell makepkginfo to create a pkginfo item using the legacy appdmg installer type by using the –appdmg flag.

  • Support for optional installs. See MunkiOptionalInstalls for details.

  • Support for managed_updates. These are items that munki will manage updates for, even if the item is not in any managed_installs list. Items are listed in a manifest under a “managed_updates” key, using the same format as “managed_installs”.

  • Removed support for “modifies” dependency type. This was deprecated several months ago.

  • Support for SHA-256 checksum to verify downloaded package integrity. makepkginfo now generates this checksum for pkginfo items. The PackageVerificationMode key in ManagedInstalls.plist controls this behavior. Set PackageVerificationMode to “none” to disable package verification. The default is “hash”; the checksum will be verified if it exists; set the PackageVerificationMode to “hash-strict” to require checksums verification on all downloads. Thanks to Justin McWilliams for this submission.

  • preflight and postflight scripts are now checked for security: they must be owned by the user running the managedsoftwareupdate process (this is generally root), the group must match that of the munki process (or be ‘wheel’) and the scripts must not be world-writable. Thanks to Justin McWilliams for this submission.

  • Support for additional HTTP headers to be sent when communicating with the munki server. These headers are specified in /Library/Preferences/ManagedInstalls.plist in the key “AdditionalHttpHeaders”, which is an array of strings, each with an HTTP header:
    <key>AdditionalHttpHeaders</key>
    <array>
    <string>Key-With-Optional-Dashes: Foo Value</string>
    <string>another-custom-header: bar value</string>
    </array>
    One could use this to obtain a cookie in a preflight script and update ManagedInstalls.plist with the appropriate header. Thanks to Justin McWilliams for this submission.

  • Installation of Adobe CS5 products should now install Adobe Help and Adobe Media Player if they are included in the install.

  • Numerous bug fixes and minor enhancements. Some listed here:
  • http://code.google.com/p/munki/issues/detail?id=12
  • http://code.google.com/p/munki/issues/detail?id=22
  • http://code.google.com/p/munki/issues/detail?id=23

27.7.23.29 0.5.2 Build 572 Relase notes -16 Jul 2010

  • Support for Adobe CS5 installers and updaters. This support is still subject to the underlying issues with the Adobe installers. See MunkiAndAdobeCS5

  • Support for preflight and postflight scripts. See PreflightAndPostflightScripts

27.7.23.30 0.5.1 Build 533 Release notes -14 May 2010

Fixed version number returned by managedsoftwareupdate -V

27.7.23.31 0.5.1 Build 532 Release notes -13 May 2010

  • Managed Software Update.app 2.0.2:
  • Now bounces icon in the Dock if it’s in the background and has updates to install.
  • When checking for updates, quits and relaunches before displaying updates to work better with Fast User Switching.

  • updatecheck.py:
  • Now uses /usr/bin/curl to download info and packages from the munki server. This also enables support for:
  • SSL Server verification (https://)
  • Partial download resumption
  • Using E-Tags instead of modification dates to determine if a file has changed on the server

  • Support for using a client certificate CN as the client identifier (defaults write /Library/Preferences/ManagedInstalls UseClientCertificateCNAsClientIdentifier -bool YES)

27.7.23.32 0.5.0 Release notes - 08 March 2010

  • Managed Software Update.app rewritten in Cocoa-Python (PyObjC), replacing the AppleScript Studio application.
  • Managed Software Update.app now launched via a LaunchAgent to follow Apple recommendations on not calling LaunchServices from a daemon context.

  • MunkiStatus.app moved from /Library/Application Support/Managed Installs to inside the Managed Software Update.app application bundle (in /Applications/Utilities/Managed Software Update.app/Contents/Resources/)

  • Some work done to make munki behave better if Fast User Switching is enabled:
  • Managed Software Update.app will warn if there are multiple users logged in and refuse to initiate an update if an update requires a restart.
  • MunkiStatus.app should now properly display in front of the loginwindow when Fast User Switching is active and we’re switched to the loginwindow with (possibly) a user switched out.
  • a new tool (/usr/local/munki/launchapp) is used by the LaunchAgents that launch Managed Software Update.app and MunkiStatus.app to ensure the app is launched only in the context of the current GUI user.
  • /usr/bin/munki/managedsoftwareupdate checks for switched-out GUI users before restarting after an update session that requires a restart.

  • appleupdates.getSoftwareUpdateInfo() now scans a packages in a downloaded distribution for RestartAction info. This addresses a case where the .dist file has no RestartAction info, but one or more of the subpackages does.

  • Running makepkginfo no longer causes a default ManagedInfo.plist file to be written to /Library/Preferences if the file does not already exist.

  • Support for suppressing package relocation for bundle-style packages. Add:
    <key>suppress_bundle_relocation</key>
    <true/>
    to a pkginfo item to enable this.

  • Applications installed from “drag-n-drop” disk images are now ensured they are owned by root.

  • Fix for retrieving main manifest from an https:// URL. Thanks to patrick.mcneal.

27.7.23.33 0.4.9 Release notes - Jan 06 2010

  • Support for Adobe Acrobat Pro 9 updater disk images.
  • MunkiStatus now launched indirectly via a LaunchAgent to follow Apple recommendations on not calling LaunchServices from a daemon context.
  • Various fixes for Adobe edge cases.

27.7.23.34 0.4.8 Release notes - Dec 04 2009

  • Managed Software Update.app has moved to /Applications/Utilities/.

  • Support for CS3 Deployment “packages”. See [MunkiAndAdobeCS3] for details.

  • Changes to logging:
  • Log rolling now implemented so logs do not grow without bounds
  • New Installs.log tracks only the results of attempted installs and removals.
  • New errors.log and warnings.log contain only the most recent errors and warnings

  • Changes to reporting:
  • /Library/Managed Installs/InstallInfo.plist now contains ONLY items that need to be installed or removed.
  • /Library/Managed Installs/ManagedInstallReport.plist is a comphrensive summary of the most recent managedsoftwareupdate session. It contains info on:
  • ManagedInstallVersion
  • AvailableDiskSpace
  • ConsoleUser
  • MachineInfo
  • ManifestName
  • StartTime/EndTime
  • ItemsToInstall/ItemsToRemove
  • InstallResults/RemovalResults
  • ManagedInstalls
  • ManagedRemovals
  • ProblemInstalls
  • ProblemRemovals
  • Errors
  • Warnings

  • Apple Update changes:
  • If munki is configured to handle Apple Software Updates and:
  • There are available munki updates -and-
  • There are available Apple updates, then:
  • munki installs only the munki updates.
  • This change was made to eliminate the confusion and undesired behaviors that occurred when available munki updates duplicated Apple Updates, or made them unneeded. Now the munki updates are done, and a subsequent Apple Software Update check would return more accurate results based on the new configuration.

  • Experimental support for an autoremove boolean key in pkginfo. This would be used to indicate a software item that should be automatically removed from a client if the item is not in the managed_installs section of the client’s manifest (or included manifests). See [[Munki And Auto Remove]] for more info.

  • UI support for packages that recommend restart (instead of require restart) and those that require logout.

  • pkginfo now has an optional “package_path” key, which is a string containing a relative path to the package to be installed on a disk image. This allows munki to install items that aren’t at the root of the disk image, and to install the “correct” item when there are multiple packages at the disk image root.

  • /Library/Preferences/ManagedInstalls.plist now supports explicit URLs for:
  • ManifestURL - example - “http://munki/repo/manifests/
  • CatalogURL - example - “http://munki/repo/catalogs/
  • PackageURL - example - “http://differentserver/pkgs/
  • These allow you to point munki to one server for the munki-specific data, while pointing it at another server for the actual installation packages/disk images.

  • Lots of bug fixes and UI tweaks.

27.7.23.35 0.4.7 Release notes

0.4.7 was an internal release only, and was not made available publicly.

27.7.23.36 0.4.6 Release notes - Nov 02 2009

  • /usr/local/munki/managedsoftwareupdate -V now prints the release version number.
  • Changes to the dependancy model:
  • The ‘modifies’ dependancy type is now deprecated and support will be removed in a future release.
  • New pkginfo key: ‘update_for’
  • This takes an array of strings, each of which refers to another pkginfo item:

An example:
<key>name</key>
<string>PhotoshopCameraRaw</string>
<key>update_for</key>
<array>
<string>PhotoshopCS4</string>
<string>AdobeCS4DesignStandard</string>
<string>AdobeCS4MasterCollection</string>
</array>

The PhotoshopCameraRaw item is an update for PhotoshopCS4, AdobeCS4DesignStandard, and the AdobeCS4MasterCollection.

Whenever munki processes a managed_installs item or removals item, it looks in the currently available catalogs for items that declare they are updates for the current item, and will add them to the list of things to install or remove. You can use the ‘requires’ key to ensure the updates are installed in the correct order.

With this addition, the ‘modifies’ key becomes redundant; you can express the same relationship (and more complex relationships) using the ‘update_for’ and ‘requires’ keys. See the example pkginfo items in the Source code repo for more examples.

27.7.23.37 0.4.5 notes

0.4.5 was an internal release only, and was not made available publicly.

27.7.23.38 0.4.4 Release notes - Oct 22 2009

  • Support for Adobe CS4 Deployment Toolkit “packages” encapsulated into disk images.
  • Support for Adobe CS4 Update installer dmgs.
  • see http://code.google.com/p/munki/wiki/MunkiAndAdobeCS4 for more info.

  • Support for disk images containing a single application that is to be copied to /Applications
  • See http://code.google.com/p/munki/wiki/AppDmgPackageNotes for more info.

  • New version of Managed Software Update.app that fixes some bugs when displaying software removals in the list of available updates.

  • makepkginfo can be called with -f arguments and no installer item to make it easier to post-generate lists of items that a given installer item installs.

  • Example:
    makepkginfo -f /Applications/Remote\ Desktop\ Connection.app
    <?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>installs</key>
    <array>
    <dict>
    <key>CFBundleIdentifier</key>
    <string>com.microsoft.rdc</string>
    <key>CFBundleName</key>
    <string>RDC</string>
    <key>CFBundleShortVersionString</key>
    <string>2.0.0</string>
    <key>path</key>
    <string>/Applications/Remote Desktop Connection.app</string>
    <key>type</key>
    <string>application</string>
    </dict>
    </array>
    </dict>
    </plist>

An admin could now copy and paste the ‘installs’ info into a pkginfo file for Microsoft’s RDC install package if they didn’t add this info when the pkginfo file was originally created.

  • makepkginfo can generate a pkginfo file for disk images containing a single application that is to be copied to /Applications.
  • makepkginfo can generate a basic pkginfo file for Adobe CS4 Deployment disk images and for Adobe CS4 Update installer dmgs.

Note that since the non-Apple installer items types now supported by munki do not have package receipts, it is vital they have entries under the ‘installs’ key in order for munki to be able to determine whether or not they’re already installed.

27.7.23.39 0.4.3 Release notes

There was no public 0.4.3 release.

27.7.23.40 0.4.2 Release notes - Oct 14 2009

The 0.4.2 release of the munki tools features experimental support for handling Apple Software Updates.

By default, handling Apple Software Updates is off.

To turn it on,

defaults write /Library/Preferences/ManagedInstalls InstallAppleSoftwareUpdates -bool YES

Since it’s using Apple’s tools, it should talk to whichever Software Update Server you have configured (via MCX or in /Library/Preferences/com.apple.SoftwareUpdate.plist). If none is configured, it talks to Apple’s SUS.

If you’d like the munkitools to use an alternate SUS URL:

defaults write /Library/Preferences/ManagedInstalls SoftwareUpdateServerURL "<SUS URL>"

Some notes:

  • Most of the code for Apple Updates is in munkilib/appleupdates.py; some is in managedsoftwareupdate.

  • On Leopard, when checking for updates, appleupdates.py uses /System/Library/CoreServices/Software Update.app/Contents/Resources/SoftwareUpdateCheck
  • On Snow Leopard, /usr/sbin/softwareupdate is used.

  • Since I could not get the ‘install-and-restart’ behavior of Software Update.app working consistently to my satlisfaction, I’ve gone back to the approach of using /usr/sbin/installer install the items downloaded by softwareupdate (using existing code in munkilib/installer.py). The last time I tried this, I kept finding downloads /usr/sbin/installer refused to install. I’m trying a slightly different approach this time and have not yet had an issue, but the sample size is small.

  • If munki finds available Apple Updates, and a restart is required for these updates, it installs them, restarts, then installs any available updates from the munki repo, again restarting if needed. This behavior cannot currently be customized.
    Automatic removal of unused/underused optional_installs

27.7.24 Introduction

New for Munki 3: Munki can track application usage and can use this information to automatically remove optional_installs items that have not been used for a period of time.

This can be used to automatically remove expensive software from machines where it is not being actively used.

27.7.25 Overview

To use this feature, you can add a new key and dictionary to a pkginfo item. An example:

<key>unused_software_removal_info</key>
<dict>
    <key>bundleids</key>
    <array>
        <string>com.foo.app1</string>
        <string>com.foo.app2</string>
    </array>
    <key>removal_days</key>
    <integer>90</integer>
</dict>

The unused_software_removal_info dictionary can contain two keys:

  • bundleids This is optional, and must contain a list of strings. Each string is the bundleid of an application that will be checked to see if it was activated in the past removal_days days. If it doesn’t exist, bundledids will be extracted from applications in the installs array if it exists.
  • removal_days This is required, and is an integer. If no application in the list of bundleids has been activated in the past removal_days days, and the item has not been installed in the past removal_days days, the item will be added to the list of things to be removed, and if the item is in the SelfServeManifest list of managed_installs, it will be removed from that list.

27.7.26 How it works

The new version of Munki introduces a new background process (app_usage_monitor) that registers for some notifications.

It registers for the NSWorkspace notifications for app launch, quit and activate, and records these events in a database named “application_usage.sqlite” in Munki’s local data directory (typically /Library/Managed Installs).

The same process also registers for a ‘com.googlecode.munki.managedsoftwareupdate.installrequest’ notification, which is posted by Managed Software Center 4.3.x or later when a user chooses to install an item from optional installs.

During a managedsoftwareupdate run, Munki processes optional_installs from the available manifests. For each optional_installs item, if the item is determined to be currently installed, Munki then checks to see if the item has unused_software_removal_info. If so, it then:

  • Is there application usage data at least as far back as removal_days?
  • If so, was there an install request for this item in the past removal_days?
  • If not, get a list of bundleids of applications to check.
  • Loop through each bundleid; if no application is currently running and has not been activated in the past removal_days, then add this item to the removal list and remove it from the SelfServeManifest’s managed_installs (if it’s there)

27.7.27 Considerations

This functionality works only with optional_installs. Items listed as managed_installs will not be considered for removal due to non-use.

Since this feature works by checking the usage of applications, it cannot be used to remove unused software that does not have an application component: for example, you could not use this mechanism to reliably remove unused fonts, or the Adobe Flash Player plugin due to non-use.

Items must have a functional uninstall method.

Items need not be in the current SelfServeManifest managed_installs to be considered for removal; they need only be in optional_installs in any applicable manifest (and not in managed_installs in any server-based manifest that is applied to the current machine).

unused_software_removal_info is stored in pkginfo items. If you add this information to ExpensiveSoftware-1.0 and later import ExpensiveSoftware-1.1, be sure to copy the unused_software_removal_info to the new pkginfo.

27.7.28 Database schema

The database contains two tables. Here are the SQL statements that create them:

CREATE TABLE application_usage (
    event TEXT,
    bundle_id TEXT,
    app_version TEXT,
    app_path TEXT,
    last_time INTEGER DEFAULT 0,
    number_times INTEGER DEFAULT 0,
    PRIMARY KEY (event, bundle_id)
)

CREATE TABLE install_requests (
    event TEXT,
    item_name TEXT,
    item_version TEXT,
    last_time INTEGER DEFAULT 0,
    number_times INTEGER DEFAULT 0,
    PRIMARY KEY (event, item_name)
)

How to remove the Munki tools and associated files

27.7.29 Introduction

Perhaps you have decided you don’t want to do anything more with Munki. Maybe you intend to explore more, but don’t want to leave the Munki tools in place right now. In any case, if you want to remove the Munki tools, here’s how:

27.7.30 Details

You can remove all the Munki tools and Munki’s configuration and cached data like so:

sudo launchctl unload /Library/LaunchDaemons/com.googlecode.munki.*

sudo rm -rf "/Applications/Utilities/Managed Software Update.app"
sudo rm -rf "/Applications/Managed Software Center.app"

sudo rm -f /Library/LaunchDaemons/com.googlecode.munki.*
sudo rm -f /Library/LaunchAgents/com.googlecode.munki.*
sudo rm -rf "/Library/Managed Installs"
sudo rm -f /Library/Preferences/ManagedInstalls.plist
sudo rm -rf /usr/local/munki
sudo rm /etc/paths.d/munki

sudo pkgutil --forget com.googlecode.munki.admin
sudo pkgutil --forget com.googlecode.munki.app
sudo pkgutil --forget com.googlecode.munki.core
sudo pkgutil --forget com.googlecode.munki.launchd
sudo pkgutil --forget com.googlecode.munki.app_usage

Some pointers on repackaging software

27.7.31 Introduction

Munki can install software distributed in Apple package format, from “drag-n-drop” disk images, and software “packaged” with Adobe CS3/4/5/6/CC Enterprise Deployment tools.

But some software may have to be repackaged in order to be installed by Munki. Some examples of types of software that may need to be packaged or repackaged:

  • Software distributed in InstallVISE or InstallAnywhere format.
  • Software distributed in Apple package format, but the package doesn’t work silently or at the loginwindow.
  • Software you develop yourself that isn’t packaged at all

Generally speaking, you should avoid repackaging software unless there is no choice. If you repackage, you accept responsibility for any issues your non-vendor-supported installer might create.

27.7.32 Details

27.7.32.1 Tools

Here are some useful tools for creating Apple Installer packages. This is not an exhaustive list; there are other tools available. These are either ones I’ve used personally, or can recommend for other reasons.

AutoPkg

https://github.com/autopkg/autopkg

AutoPkg is an automation tool that runs recipes to automate the tasks of finding, downloading and preparing software for mass deployment. Some of the available recipes do repackaging of some problematic software; if you need to repackage, consider first looking for an AutoPkg recipe that does it for you.

Some notes on using AutoPkg as a general-purpose packaging tool:
https://managingosx.wordpress.com/2015/07/30/using-autopkg-for-general-purpose-packaging/

munkipkg

https://github.com/munki/munki-pkg

munkipkg is a simple tool for building packages in a consistent, repeatable manner from source files and scripts in a project directory.

Files, scripts, and metadata are stored in a way that is easy to track and manage using a version control system like git.

pkgbuild and productbuild

Command-line tools for building packages. Installed by default on OS X 10.7 and up. See their man pages for more information.

Pros: universally available. Supported by Apple. Easy to integrate into automated workflows.

Cons: command-line only, so requires some mental work to get started.

Packages

http://s.sudre.free.fr/Software/Packages.html

Modern packaging tool from the creator of Iceberg. Recommended as a GUI tool to build flat packages.

Casper Composer

http://www.jamfsoftware.com/products/composer.php

Composer is a $100 utility from JAMF Software. Part of the Casper Suite of OS X client management tools, Composer is also available separately. Casper Composer can create packages based on filesystem snapshots. When used with the Casper suite, it can create installation packages with extra abilities such as installing default preferences into users’ home directories.

Pros: Easy to use. Good documentation.

Cons: It’s not free. Composer’s special package features work only with other tools in the Casper Suite.

27.7.33 Commandments of (re)packaging

These are old, but still hold some relevance if you do need to re-package someones software, or indeed for Vendors learning how to package their tools for macOS:

https://wiki.afp548.com/index.php/Guidelines_for_Mac_software_packaging#The_Commandments_of_Packaging
Admin tool plug-in support for different types of Munki repos

27.7.34 Introduction

Munki 3 supports repo plugins: adapters that allow the Munki command-line admin tools to work with repos that aren’t local file-based repos, or to add extra capabilities to the tools.

27.7.35 Repo plugins

repo plugins are written in Python and installed the the munkilib/munkirepo directory. Currently Munki ships with these repo plugins:

  • FileRepo - the default plugin and handles both local file repos and repos hosted on fileshares.

  • GitFileRepo - a proof-of-concept/demonstration plugin. It inherits the behavior of FileRepo and does git commits for file changes in the repo (which must be already configured/initialized as a git repo)

  • MWA2APIRepo - a proof-of-concept/demonstration plugin that talks to a remote repo via the MWA2 API. It requires the latest MWA2 code from GitHub.

Additional repo plugins are welcome, however, we currently wish to have those maintained outside of the core Munki code. If you have created a plugin and would like to make it more visible please add it to the following section, Community Plugins.

27.7.36 Command-line tools

These command-line admin tools have been updated to use the new-style repo plugins:

iconimporter
makecatalogs
manifestutil
munkiimport
repoclean

Available options for these tools may have changed; use <toolname> --help to see the usage.

When using the --configure option with manifestutil and munkiimport, there are three major changes to be aware of:

  • You will no longer be prompted for a repo path. The repo_path preference may be deprecated in the future – I’m not sure it’s needed any longer.

  • Repo URL can take several forms:
  • a file: url: file:///Users/Shared/munki\_repo will cause these tools to use a local file-based repo located at /Users/Shared/munki_repo
  • a filesharing url: afp://someserver/sharename or smb://someserver/sharename or nfs://someserver/sharename These tools will attempt to mount these URLs and use whatever mountpoint they mount at (typically under /Volumes)
  • An http/https url: Example: https://mwa2.my.org/api These sorts of repos require a custom plugin that knows how to talk to the repo at the given URL.

  • You will be prompted for a plugin name. For traditional file-based repos (either local or those available via fileshare, the default FileRepo plugin can be used. If plugin is not defined, the FileRepo plugin will be used.)

27.7.37 Workflow changes

The most noticable change to workflows using the modified tools is around editing pkginfo items in a text editor when using munkiimport.

Since we can’t guarantee direct file access to the pkginfo item after it’s been uploaded to the Munki repo, we ask before we upload it if you want to edit it.

If you answer ‘yes’, the pkginfo is opened in your editor of choice.

  • If the editor is command-line based (like vi), once you exit the editor, the munkiimport session will resume and the pkginfo file will be uploded to the repo.
  • If the editor is an application (like SublimeText), munkiimport will wait for you to manually indicate you are done editing the file before proceeding.
  • The pkginfo is saved to a temp file before it is opened in the text editor, so don’t be concerned about the strange path you might see.

27.7.38 Other notes

makecatalogs works with the MWA2APIRepo but is very slow due to all the web calls need to get every icon and pkginfo item. A future version of the code may allow a plugin to tell the repo to makecatalogs itself: so for the MWA2API, it would trigger the MWA2 code to do the catalog rebuild.

iconimporter has to download dmgs and pkgs from the repo in order to process them for possible icons. This is slower and uses more disk than the direct file access possible when only file-based repos were supported. Running iconimporter against an entire repo should be an infrequent operation, so it’s not likely this is worth optimizing in any way.

27.7.39 Plugin developer notes

The “API” of the new-style repo plugins is greatly simplified over the previous style of repo plugins. It’s possible I’ve over-simplfied it and it might need extension to cover things I haven’t thought of. See the munkilib/munkirepo/FileRepo.py, munkilib/munkirepo/GitFileRepo.py and munkilib/munkirepo/MWA2APIRepo.py files for concrete examples of the new-style repo plugins.

Repo subclasses need to implement these methods:


    def __init__(self, baseurl):
        '''Constructor, does initial setup and handles login/mounting'''

    def itemlist(self, kind):
        '''Returns a list of identifiers for each item of kind.
        Kind might be 'catalogs', 'manifests', 'pkgsinfo', 'pkgs', or 'icons'.
        For a file-backed repo this would be a list of pathnames.'''

    def get(self, resource_identifier):
        '''Returns the content of item with given resource_identifier.
        For a file-backed repo, a resource_identifier of
        'pkgsinfo/apps/Firefox-52.0.plist' would return the contents of
        <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.
        Avoid using this method with the 'pkgs' kind as it might return a
        really large blob of data.'''

    def get_to_local_file(self, resource_identifier, local_file_path):
        '''Gets the contents of item with given resource_identifier and saves
        it to local_file_path.
        For a file-backed repo, a resource_identifier
        of 'pkgsinfo/apps/Firefox-52.0.plist' would copy the contents of
        <repo_root>/pkgsinfo/apps/Firefox-52.0.plist to a local file given by
        local_file_path.'''

    def put(self, resource_identifier, content):
        '''Stores content on the repo based on resource_identifier.
        For a file-backed repo, a resource_identifier of
        'pkgsinfo/apps/Firefox-52.0.plist' would result in the content being
        saved to <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''

    def put_from_local_file(self, resource_identifier, local_file_path):
        '''Copies the content of local_file_path to the repo based on
        resource_identifier. For a file-backed repo, a resource_identifier
        of 'pkgsinfo/apps/Firefox-52.0.plist' would result in the content
        being saved to <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''

    def delete(self, resource_identifier):
        '''Deletes a repo object located by resource_identifier.
        For a file-backed repo, a resource_identifier of
        'pkgsinfo/apps/Firefox-52.0.plist' would result in the deletion of
        <repo_root>/pkgsinfo/apps/Firefox-52.0.plist.'''

27.7.40 Interaction examples

bash-3.2$ ./munkiimport --configure
Repo URL (example: afp://munki.example.com/repo): http://localhost:8080/api
pkginfo extension (Example: .plist): .plist
pkginfo editor (examples: /usr/bin/vi or TextMate.app; leave empty to not open an editor after import): /usr/bin/vi
Default catalog to use (example: testing): testing
Repo access plugin (defaults to FileRepo): MWA2APIRepo
bash-3.2$ ./munkiimport ~/Downloads/AutoDMG-1.7.3.dmg 
Please provide credentials for http://localhost:8080/api:
Username: gneagle
Password: 
This item is similar to an existing item in the repo:
            Item name: AutoDMG
         Display name: AutoDMG
          Description: Create deployable system images from OS X installer.
              Version: 1.7
  Installer item path: apps/AutoDMG-1.7__1.dmg

Use existing item as a template? [y/n] y
Copying unattended_install: True
Copying unattended_uninstall: False
Copying category: Admin Tools
Copying developer: Per Olofsson
Copying featured: False
           Item name: AutoDMG
        Display name: AutoDMG
         Description: Create deployable system images from OS X installer.
             Version: 1.7.3
            Category: Admin Tools
           Developer: Per Olofsson
            Featured: False
  Unattended install: True
Unattended uninstall: False
            Catalogs: testing

Import this item? [y/n] y
No existing product icon found.
Attempt to create a product icon? [y/n] y
Attempting to extract and upload icon...
Created icon: icons/AutoDMG.png
Copying AutoDMG-1.7.3.dmg to pkgs/apps/AutoDMG-1.7.3.dmg...
Edit pkginfo before upload? [y/n]: n
Saving pkginfo to pkgsinfo/apps/AutoDMG-1.7.3.plist...
Rebuild catalogs? [y/n] y
Rebuilding catalogs at http://localhost:8080/api...
bash-3.2$ ./manifestutil --configure
Repo URL (example: afp://munki.example.com/repo): file:///Users/Shared/munki_repo
Munki repo plugin (defaults to FileRepo): GitFileRepo
bash-3.2$ ./manifestutil 
Entering interactive mode... (type "help" for commands)
> display-manifest site_default
 catalogs:
     testing
     production
 included_manifests:
     groups/StandardApps
     groups/AllOptionalInstalls
 managed_installs:
     Firefox
 managed_uninstalls:
 managed_updates:
 optional_installs:
     GoogleChrome
     AdobeReaderDC
> add-pkg AutoDMG --manifest site_default --section optional_installs
Doing git commit: gneagle modified 'manifests/site_default' via manifestutil
Added AutoDMG to section optional_installs of manifest site_default.
> new-manifest yet_another_manifest
Doing git commit: gneagle created 'manifests/yet_another_manifest' via manifestutil
> exit

27.7.41 Community Plugins

These are Munki repo plugins developed by third parties and are not part of Munki core. (which is one of the points of supporting repo plugins!)
If you experience issues with a plugin please make sure to send that issue to the correct repo.

| Name | URL | Description |
| —- | — | ———– |
| s3Repo | https://github.com/clburlison/Munki-s3Repo-Plugin | This plugin allows administrators to interact with their Munki repo hosted in a S3 compatible bucket. |

27.7.42 Introduction

This optional functionality provides Munki admins a way to get notified of clients in the field that are broken. Admins can choose to post a report to any existing report server or simply email themselves by simply placing an executable script named “report_broken_clients” in the munkitools root (/usr/local/munki) ala PreflightAndPostflightScripts.

27.7.43 Details

Currently the only “broken” case that is if /usr/bin/python does not contain the Apple provided Objective-C Python bindings. This could happen if the user of the machine installs a non-Apple provided version of Python over the top of /usr/bin/python.

managedsoftwareupdate simply tries to import an ObjC-backed Python module and calls the “report_broken_client” script if it fails to import.

At the point of this error, it’s unknown what the managedsoftware runtype was, so the script is simply passed “custom”.

In the future there may be more failure cases, in which case the script may be passed different information.

27.7.43.1 report_broken_clients script

Much like preflight and postflight scripts, this script must be executable and only writable by root:wheel otherwise it will not be executed. Also, it can be written in any language supported by the OS X system it’s executed on.
This page is a list of talking points for discussion surrounding the Munki Road Map

28 Purpose

The purpose of this page is to itemize ideas and suggestions that were made on the munki-dev list. The hope is that if we can record the ideas as they are made, then there is less of a chance of them falling into the ether and disappearing forever. This page is not the Munki Road Map itself, but rather a list of topics that may make it to the Road Map in the future.

29 Possible Munki Improvements

  • “auto” Munki recipes
  • Improve Documentation
  • Update Demo Setup (10.8 does not expose Web Sharing anymore) - Done 16 Feb 2013 gneagle
  • Localization Upkeep - See LocalizationMaintenance
  • Metadata support for Apple Updates - in progress Feb 2013 Heig Gregorian
  • munkiimport improvements
  • Copy keys from previous version of package if present in new pkginfo_keys_to_copy key
  • Improved munki-dev support (As in, not all Greg) - See [[MunkiDevSupport|Munki-Dev-Support]]
  • MunkiWebAdmin Improvements
  • MWA with Django REST framework
  • MWA with MSU integration? Server-side client manifests?
  • Optional Installs - See OptionalInstallRoadMapDiscussion
  • Open Issues
  • Go through open Issues and assign priorities
  • Scheduled OS X Support Deprecated
  • 6 years and newer
    If you munkiimport the .pkg that installs SMART Notebook (or the entire SMART Learning Suite), you may find the item seems to keep needing to be reinstalled.

To prevent that, install the .pkg on one client machine and then run

makepkginfo -f /Applications/SMART\ Technologies/Notebook.app

to get the installs array, which you can put into the pkginfo for SMART Notebook.

Here’s an example of what that installs array might look like:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.smarttech.notebook.Notebook.10</string>
            <key>CFBundleShortVersionString</key>
            <string>17.0.1181.0</string>
            <key>CFBundleVersion</key>
            <string>17.0.1181.0</string>
            <key>path</key>
            <string>/Applications/SMART Technologies/Notebook.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Including images/graphics/screenshots in Product descriptions

29.0.1 Introduction

Since you can include a subset of HTML in product descriptions, you can include IMG tags.
Together with a web server (like, say, your Munki server…) you can add images like screenshots to your product descriptions.

29.0.2 Details

To add image content to a product description:

  • Create your artwork in a web-friendly format (jpg, gif, png are good suggestions.) Images lay out best if they are no more than 560px wide.
  • Copy to a web server. (If your Munki repo does not require authentication/authorization, create an artwork folder in your Munki repo, and copy it there. Otherwise, you might need to find or configure a “public” web server for this task; or perhaps you can configure your web server so that the artwork folder does not need authorization.)
  • Add an IMG tag to your product description. Make sure you escape the HTML for inclusion inside plist XML. This generally means changing “<” to &lt;, “>” to &gt; and “&” to &amp;.

An example description:

    <key>description</key>
    <string>Mozilla Firefox is a free and open source web browser.
&lt;br&gt;&lt;br&gt;
&lt;img src="http://munkiserver/repo/artwork/Firefox_screenshot_01.png"&gt;</string>

Note that this artwork will not be cached for offline viewing; if your web server is not available when the description is viewed, a broken image placeholder will be displayed instead.


A list of all the supported keys for pkginfo files.

29.0.3 Introduction

This is a list of all the supported keys for pkginfo files. See [[Pkginfo Files]] for examples of the proper use of these keys.

29.0.3.1 Keys

Key Type Notes
apple_item boolean Should this item be considered as an Apple update item? See Apple-Software-Updates-With-Munki Defaults to false.
autoremove boolean See Munki and AutoRemove. Defaults to false.
blocking_applications array of strings See Blocking Applications
catalogs array of strings See MunkiCatalogDocumentation
category string Munki2-specific customization, not required
copy_local boolean Adobe CS5 install items only. Copy update to /tmp before installing. Optional.
description string Description of the item being installed
developer string Munki2-specific customization, not required
display_name string “Pretty” display name that is used in MSC.app
force_install_after_date date yyyy-mm-ddThh:mm:ssZ (evaluated in local time)
forced_install boolean This is Deprecated. Use unattended_install
forced_uninstall boolean This is Deprecated. Use unattended_uninstall
icon_name string Specify the name of the icon file to be used. Defaults to value of ‘name’ key + ‘.png’.
installable_condition string NSPredicate string that must evaluate true for this item to be allowed to install. Same format as used in [[Conditional Items]], but is used only to filter whether the item can be installed on the client, not to decide whether it will be installed. See here for more details.
installed_size integer Size of the installed item in kbytes. Used to determine if there is enough free space before install. Typically generated by makepkginfo/munkiimport.
installer_item_hash string SHA-256 hash of item to ensure integrity at install time. Typically generated by makepkginfo/munkiimport. Can also generate with shasum -a 256 <filepath>
installer_item_location string Relative path (from the pkgs directory) to the installer item. Typically auto generated.
installer_item_size integer Size of the installer item in kbytes. Typically auto generated.
installer_type string This key may be absent, in which case an installer item type of Apple package is assumed. Possible values include AdobeSetup, AdobeUberInstaller, AdobeAcrobatUpdater, AdobeCS5AAMEEPackage, AdobeCS5PatchInstaller, AdobeCCPInstaller, copy_from_dmg, nopkg, profile, startosinstall, and appdmg (deprecated). This key is typically auto-generated.
minimum_munki_version string Lowest version of the Munki tools that must be running before attempting to install this item.
minimum_os_version string Lowest OS version with which this item is compatible. Defaults to 10.4.0 for bundle packages and 10.5.0 for flat packages
maximum_os_version string Highest OS version with which this item is compatible.
name string Mandatory. The single most important key. This is the name for the item, referred to in manifest files and in requires and update_for arrays.
notes string Arbitrary admin notes. Not included in catalogs when built with makecatalogs.
PackageCompleteURL string Optional key to redirect actual package download to arbitrary location. Useful to offload bandwidth from location of munki repo/server
PackageURL string PackageInfo-level key that overrides the value of PackageURL in Munki’s global preferences. An alternate way to redirect download of a specific package to an alternate server.
package_path string Relative path to the package from the root of a mounted disk image. Useful if there are multiple packages on a disk image or the package you’d like to install is not located at the root of the mounted disk image.
installcheck_script string If present, this script is executed to determine if an item needs to be installed. A return code of 0 means install is needed; any other return code causes install to be skipped.
uninstallcheck_script string If present, this script is executed to determine if an item needs to be uninstalled. A return code of 0 means uninstall is needed; any other return code causes uninstall to be skipped.
OnDemand boolean Whether this item should be treated as an “OnDemand” install. More info
postinstall_script string A script to be executed after a successful install.
postuninstall_script string A script to be executed after a successful uninstall.
preinstall_alert dictionary An alert dialog to be shown to the user before an attempted install. More info
preuninstall_alert dictionary An alert dialog to be shown to the user before an attempted uninstall. More info
preinstall_script string A script to be executed before an attempted install.
preuninstall_script string A script to be executed before an attempted uninstall.
receipts array of dictionaries A list of package receipts left by this item. See Receipts.
requires array of strings A list of other Munki-managed packages that are required to be installed before this item can be installed. More info
RestartAction string Possible values: RequireShutdown, RequireRestart, RecommendRestart, RequireLogout, None
supported_architectures array of strings
suppress_bundle_relocation boolean If true, Munki will attempt to suppress the Apple Installer feature that causes it to update applications and other bundle types that have been moved from their default location. Functional only on bundle-style packages; this option has no effect on flat packages at this time.
unattended_install boolean If true, Munki can attempt to install this item without notifying the user. Note: this is an optional key. Setting it to false is the same as omitting the key altogether.
unattended_uninstall boolean If true, Munki can attempt to uninstall this item without notifying the user. Note: this is an optional key. Setting it to false is the same as omitting the key altogether.
uninstall_method string Possible values: removepackages, remove_copied_items, remove_app, uninstall_script, remove_profile, one of the “Adobe*" removal methods, or the absolute path to a local script. |
| uninstall_script | string | Script that performs an uninstall.|
| uninstaller_item_location | string | Used with Adobe removal methods that require an uninstaller package.|
| uninstallable | boolean | If true, this item can be successfully uninstalled by Munki.|
| update_for | array of strings | List of other Munki-managed packages that this should be considered an update for. More info|
| version | string | Version number string. Examples: 1.0, 3.6.10|

29.0.3.2 receipts

Array of dictionaries

Most keys are automatically generated by makepkginfo or munkiimport when importing an Apple package. The only key you might need to add or modify is the “optional” key.

Receipt Key Type Description
filename string
installed_size integer
name string
packageid string
version string
optional boolean If set to true, Munki won’t use this receipt to determine installation state, but will use its information (if present) when removing an installed package

29.0.3.3 installs

Array of dictionaries

Not all keys appear in every entry. Use makepkginfo -f /path/to/item to generate these.

Installs Key Type Description
CFBundleIdentifier string Value for CFBundleIdentifier in a plist or application/bundle type.
CFBundleName string Value for CFBundleName in a plist or application/bundle type.
CFBundleShortVersionString string Value for CFBundleShortVersionString in a plist or application/bundle type.
md5checksum string An MD5 checksum used for version comparison by the file type.
minosversion string Minimum OS version required for an application type item. Derived automatically from the application bundle’s Info.plist.
path string Path to the item installed.
type string One of ‘application’, ‘bundle’, ‘plist’ or ‘file’.
version_comparison_key string When install item is any type but ‘file’, this is the name of the key to be used for version comparison logic. If unspecified, ‘CFBundleShortVersionString’ is used. The key and its value must always be included in this install item so that this item can be compared with the version on disk.

29.0.3.4 items_to_copy

Array of Dictionaries

Used with copy_from_dmg installer_type to tell Munki what and where to copy.

items_to_copy key Type Description
destination_path string Destination directory for the item, required. Since 2.2.0, Either this or destination_item (containing a full path) must be present.
group string Optional. Group for copied item. Defaults to admin.
mode string Optional. Mode for copied item (see man chmod for valid formats). Defaults to ‘o-w’
source_item string Required. Relative path from the root of the disk image to the item to be copied.
destination_item string Copy item as name specified. Used if you want to rename the item as it is copied. Since 2.2.0 you can specify a full path to the destination item when you omit destination_path.
user string Optional. Owner for copied item. Defaults to root.

29.0.3.5 installer_choices_xml

Array of Dictionaries

Used with Apple metapackages to control what subpackages are installed. See [[ChoiceChangesXML]] for more information.

installer_choices_xml key Type Description
attributeSetting integer
choiceAttribute string (“visible”, “enabled”, “selected”)
choiceIdentifier string

29.0.3.6 installer_environment

Dictionary

Used to specify arbitrary environment variables for use by /usr/sbin/installer. The combination of the key ‘USER’ and the value ‘CURRENT_CONSOLE_USER’ is special, and causes Munki to set the USER variable to the current console user and the HOME variable to the home of the current console user.

Key Type Notes
VARIABLE_NAME string

These keys are automatically generated by makepkginfo/munkiimport when importing an Adobe CS3/4/5/6 installer package.

Key Type Notes
AdobeSetupType string
payloads array of dictionaries

29.1.0.1 adobe_install_info

Dictionary

These keys are automatically generated by makepkginfo/munkiimport when importing an Adobe CS3/4/5/6 installer package.

| adobe_install_info keys | Type | Description |
|—————————–|———-|———————-|
|serialnumber|string| |
|installxml|string| |
|uninstallxml|string| |
|media_signature|string| |
|media_digest|string| |
|payload_count|integer| |
|suppress_registration|boolean| |
|suppress_updates|boolean| |
Launch up the Symantec Endpoint Protection Installer.app

Even though the installer app will warn you you’ll have to reboot, you won’t actually have to, so just click Continue.

Then, from the menu bar, select Tools and then Create remote deployment package.

This will create a .pkg you can then import into your Munki repository. For example:
munkiimport ~/Downloads/SEPRemote.pkg

Unfortunately, SEP will, by default, go into an endless install loop without an installs array, so you’ll have to create an installs array to put into your pkginfo.

Install SEP on a client and then run this (or similar) command on the client machine to get the installs array:
makepkginfo -f /Applications/Symantec\ Solutions/Symantec\ Endpoint\ Protection.app

You should get something like this to paste into your pkginfo file:

    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.symantec.sep.mainapp</string>
            <key>CFBundleName</key>
            <string>Symantec Endpoint Protection</string>
            <key>CFBundleShortVersionString</key>
            <string>14.0.2415.0200</string>
            <key>CFBundleVersion</key>
            <string>12</string>
            <key>minosversion</key>
            <string>10.6</string>
            <key>path</key>
            <string>/Applications/Symantec Solutions/Symantec Endpoint Protection.app</string>
            <key>type</key>
            <string>application</string>
            <key>version_comparison_key</key>
            <string>CFBundleShortVersionString</string>
        </dict>
    </array>

Troubleshooting tips

29.1.1 Introduction

Where to start troubleshooting when things aren’t working as you expect.

See also the [[FAQ]].

29.1.2 Details

29.1.2.1 Command line

Run /usr/local/munki/managedsoftwareupdate -vvv to get more verbose output.

29.1.2.2 Logs

By default, logs are written to /Library/Managed Installs/Logs/

ManagedSoftwareUpdate.log is the main log; errors and warnings from the most recent run are in errors.log and warnings.log, respectively.

You can increase the amount of detail in ManagedSoftwareUpdate.log with sudo defaults write /Library/Preferences/ManagedInstalls LoggingLevel -int 2 (higher integers for even more detail).

The Managed Software Center application runs as the user, and uses a different path, described here:
https://github.com/munki/munki/wiki/MSU-Logging

When installing Apple Installer packages, Munki calls the command-line /usr/sbin/installer tool. That tool logs to /var/log/install.log.

Munki can be configured to check for and install Apple software updates; in that case it calls /usr/sbin/softwareupdate. Apple’s softwareupdate tool also logs to /var/log/install.log.

29.1.2.3 Server troubleshooting

The Munki client talks to the Munki server via normal web protocols – you may be able to troubleshoot by using a web browser to download the same info:

http://yourmunkiserver/repo/manifests/name_of_client_manifest

http://yourmunkiserver/repo/catalogs/production

http://yourmunkiserver/repo/catalogs/testing

29.1.2.4 Still stuck?

Ask for help here: http://groups.google.com/group/munki-discuss
Options for updating Munki tools on client machines

29.1.3 tl;dr:

Use AutoPkg and run the munkitools2.munki recipe.

29.1.4 Details

The Munki tools are distributed as a distribution package, which contains four component packages. This enables several things for the Munki admin:

  1. Admins can choose to install only a subset of the Munki tools; for example, they can choose to not install the Munki admin tools (makecatalogs, makepkginfo, munkiimport) on most client machines (though doing so is probably not worth the effort).
  2. If you have customized or replaced the launchd jobs used by Munki, you can upgrade to newer tools without having your changes overwritten, by choosing not to install the launchd jobs that are included with the munkitools pkg.
  3. In many cases, you can update the Munki tools silently in the background without needing a restart. As long as the launchd subpackage has not changed, no reboot is required.

All of these require installing only a subset of the packages included in the distribution package. There are a few approaches to accomplishing that:

  1. Using installer’s ChoiceChangesXML files and Munki’s support for embedding them into pkginfo. You could, for example, use the following installer_choices_xml to install only the core tools and Managed Software Center.app; skipping the install of the admin tools and the launchd plists:

    <key>installer_choices_xml</key>
    <array>
        <dict>
            <key>attributeSetting</key>
            <integer>1</integer>
            <key>choiceAttribute</key>
            <string>selected</string>
            <key>choiceIdentifier</key>
            <string>core</string>
        </dict>
        <dict>
            <key>attributeSetting</key>
            <integer>0</integer>
            <key>choiceAttribute</key>
            <string>selected</string>
            <key>choiceIdentifier</key>
            <string>admin</string>
        </dict>
        <dict>
            <key>attributeSetting</key>
            <integer>1</integer>
            <key>choiceAttribute</key>
            <string>selected</string>
            <key>choiceIdentifier</key>
            <string>app</string>
        </dict>
        <dict>
            <key>attributeSetting</key>
            <integer>0</integer>
            <key>choiceAttribute</key>
            <string>selected</string>
            <key>choiceIdentifier</key>
            <string>launchd</string>
        </dict>
    </array>
  2. Editing the Distribution file inside the munkitools distribution pkg – this would have a similar effect as the previous approach, but could be used outside of Munki – for example, if installing the tools via ARD or manually.

29.1.4.1 Easier approach

An easier approach is to extract the component pkgs from the distribution pkg, and then import each component pkg seperately.

You can create pkginfo items for munki-core, munki-admin, munki-app, munki-launchd and use Munki’s dependency relationships to ensure everything needed gets installed and that reboots are enforced only when necessary.

<table>
<tr><td>munki-app</td><td>unattended_install: True</td><td>requires: munki-core</td></tr>
<tr><td>munki-admin</td><td>unattended_install: True</td><td>requires: munki-core</td></tr>
<tr><td>munki-core</td><td>unattended_install: True</td><td>requires: munki-launchd</td></tr>
<tr><td>munki-launchd</td><td>RestartAction: RequireRestart</td><td></td></tr>
</table>

If a managed_installs in a manifest specified only “munki-app”, munki-app, munki-core, and munki-launchd would be installed. For future updates, as long as munki-launchd hasn’t changed, the updates would happen as unattended installs. If a future update included an updated munki-launchd, the unattended_install would be invalidated, and a reboot would be needed, meaning the update would either wait until all users were logged out, or for a user to initiate the update via Managed Software Center.

Extracting the component packages from the distribution package might look like:

% pkgutil --expand munkitools-2.8.0.2810.pkg munkitools_pkg
% cd munkitools_pkg
% ls
Distribution                      munkitools_app-4.2.2759.pkg       munkitools_launchd-2.0.0.1969.pkg
munkitools_admin-2.8.0.2810.pkg   munkitools_core-2.8.0.2810.pkg
% pkgutil --flatten munkitools_app-4.2.2759.pkg ../munkitools_app-4.2.2759.pkg
% pkgutil --flatten munkitools_launchd-2.0.0.1969.pkg ../munkitools_launchd-2.0.0.1969.pkg
% pkgutil --flatten munkitools_admin-2.8.0.2810.pkg ../munkitools_admin-2.8.0.2810.pkg
% pkgutil --flatten munkitools_core-2.8.0.2810.pkg ../munkitools_core-2.8.0.2810.pkg
% cd ..
% ls munkitools_*.pkg
munkitools_admin-2.8.0.2810.pkg   munkitools_app-4.2.2759.pkg       munkitools_core-2.8.0.2810.pkg    munkitools_launchd-2.0.0.1969.pkg
% munkiimport munkitools_admin-2.8.0.2810.pkg
<snip>
% munkiimport munkitools_app-4.2.2759.pkg
<etc>

29.1.4.2 Easiest approach

The easiest approach is to use AutoPkg: https://github.com/autopkg/autopkg

Once you’ve installed the Munkitools recipes (hint: autopkg repo-add recipes) you can simply do

autopkg run munkitools2.munki

to import the Munki 2 tools into your Munki repo.

29.1.5 Conclusion

These techniques should allow for quicker and more seamless updates to Munki tools for your client machines, as in many cases you can update the Munki tools with no user action required.

29.1.6 Introduction

Upgrading to Munki 2 is easy. You don’t have to make any changes on your server if you don’t want to.
Later, if you add Munki 2-specific data to your Munki server, any clients running Munki 1 will simply ignore the extra data. Munki (1) and Munki 2 clients can co-exist and use the same server.

29.1.7 Details

  • Start by upgrading a few clients with the Munki 2 tools. See here https://munkibuilds.org for the latest versions.
  • Munki (1) can install the Munki 2 tools. Just import them as you would previous versions of Munki.
  • If you use AutoPkg (and you should) add the autopkg/recipes repo and use the munkitools2.munki recipe to import the new tools into your Munki repo.
  • Start importing icons into your Munki repo. See [[Product Icons|Product Icons]] for more info.
  • Add category and developer info to your pkginfo files. Focus initially on items in optional_installs (if you have any).

29.1.8 Introduction

Upgrading to Munki 3 is easy. You don’t have to make any changes on your server if you don’t want to.
Later, if you add Munki 3-specific data to your Munki server, any clients running Munki 1 or 2 will simply ignore the extra data. Munki 1, 2, and 3 clients can co-exist and use the same server.

29.1.9 Details

  • Start by upgrading your admin workstation to Munki 3. You’ll need the updated Munki 3 admin tools to be able to import “Install macOS.app” applications, and to take advantage of repo plugins if you want to run your Munki repo in the cloud.
  • Next, upgrade a few clients with the Munki 3 tools. See here for the latest versions.
  • Munki (2) can install the Munki 3 tools. Just import them as you would previous versions of Munki.
  • If you use AutoPkg (and you should) add the autopkg/recipes repo and use the munkitools3.munki recipe to import the new tools into your Munki repo.
  • Start using the new features!

How to restrict access to your munki repository using HTTP Basic Authentication

29.1.10 Introduction

If you’re using munki to distribute licensed software, you’ll want to restrict access to the repository. It’s possible to use client certificates (as described in Using Munki With SSL Client Certificates, but HTTP Basic Authentication is much easier to set up.

29.1.11 Details

HTTP Basic Authentication (RFC2617) is a very simple authentication scheme that simply sends a username and a password (separated by a colon and base64 encoded) in the headers of each HTTP request. If it’s used over unencrypted HTTP it’s insecure (as it’s trivial to sniff the password on the network), but in combination with HTTPS and a signed server certificate it’s reasonably secure.

29.1.11.1 Restricting Access to the Repository

29.1.11.2 Using Mac OS X Server 10.6

I will assume that you already have a repository set up that clients can connect to - if not, refer to the 10.6 Web Technologies Administration guide. I strongly recommend that you use SSL for your munki repository, with a signed server certificate. If you don’t have one, refer to the 10.6 Getting Started guide.

Since you can’t edit the Apache configuration files directly (well you can, but they will get overwritten by Server Admin), you have to enable overrides.

  1. Launch Server Admin and connect to your server.
  2. Select the Web service, and switch to the Sites tab.
  3. Select the site that hosts your munki repository.
  4. Select the Options tab, and enable Allow All Overrides.
  • NB: Your repository has to live under the Web Folder root, and not under an Alias. Overrides (.htaccess files) will not be enabled for folders under Aliases.
  1. Click Save.

You then have to create a .htaccess file in the root of your munki repository:

  1. Launch Terminal.app and cd to your repo_root.
  2. Create a user that will be used to access the repository using htpasswd (here munki is used as an example):

    $ htpasswd -c .htpasswd munki
    New password: 
    Re-type new password: 
    Adding password for user munki
  3. You can add more users to the .htpasswd file using htpasswd .htpasswd ANOTHERUSER if you don’t want to use the same username and password for all clients.
  4. Using vi, emacs, pico or nano, create a new file called .htaccess (including the leading dot, making the file hidden).
  5. Enable basic authentication with:

    AuthType Basic
    AuthName "Munki Repository"
    AuthUserFile /path/to/your/munki/repo_root/.htpasswd
    Require valid-user
  6. While you’re at it, you might want to restrict access based on IP address as well:

    Order Deny,Allow
    Deny from all
    Allow from 192.168.0.0/16
  7. Save the file and exit.

29.1.12 Using an Apache Server

I will assume that you already have a repository set up that clients can connect to.

  1. In the terminal, cd to your munki repo_root.
  2. Create a user that will be used to access the repository using htpasswd (here munki is used as an example):

    $ htpasswd -c .htpasswd munki
    New password: 
    Re-type new password: 
    Adding password for user munki
  3. You can add more users to the .htpasswd file using htpasswd .htpasswd ANOTHERUSER if you don’t want to use the same username and password for all clients.
  4. Open the Apache configuration file (typically /etc/apache2/httpd.conf) in a text editor (as root or using sudo).
  5. Find the <Directory> section for your munki repository, and after the existing configuration directives add:

      <Directory "/path/to/your/web/root">
          Options All +MultiViews -ExecCGI -Indexes -Includes  # Just an example
          AllowOverride None                                   # Just an example
          AuthType Basic
          AuthName "Munki Repository"
          AuthUserFile /path/to/your/munki/repo_root/.htpasswd
          Require valid-user
      </Directory>
  6. While you’re at it, you might want to restrict access based on IP address as well:

    Order Deny,Allow
    Deny from all
    Allow from 192.168.0.0/16
  7. Save the file and exit.

29.1.12.1 Verify the Configuration

  1. Verify that you get an authentication prompt if you try to view a catalog file in a web browser (e.g. https://your.munki.server:8043/repo_root/catalogs/testing).
  2. Verify that you can authenticate as the user you created in step #2.
  3. Verify that if you run /usr/local/munki/managedsoftwareupdate --checkonly on a client you get an error message saying that it can’t access its manifest.

29.1.13 Configuring the Clients to Use a Password

HTTP Basic Authentication consists of an extra Authorization header, which we can add to the munki configuration file in the AdditionalHttpHeaders array. But first we have to base64 encode the username and password:

$ python -c 'import base64; print "Authorization: Basic %s" % base64.b64encode("USERNAME:PASSWORD")'
Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ=

Substitute the username and password you created in the .htpasswd file in your repository. Add this line to ManagedInstalls.plist:

<key>AdditionalHttpHeaders</key>
<array>
    <string>Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ=</string>
</array>

Or if you prefer you can set it with defaults (e.g. to push it to your existing clients with ARD):

$ defaults write /Library/Preferences/ManagedInstalls AdditionalHttpHeaders -array "Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ="

If you have multiple AdditionalHttpHeaders use -array-add, otherwise the whole array will be overwritten by the defaults command.

29.1.13.1 Protecting the Password From Local Users

As all users on a machine can read /Library/Preferences/ManagedInstalls.plist, they’ll be able to read the password and access the repository. You can put the AdditionalHttpHeaders in /private/var/root/Library/Preferences/ManagedInstalls.plist instead, which is only readable by administrators.

29.1.13.2 Verify the Configuration

  1. Verify that if you run /usr/local/munki/managedsoftwareupdate --checkonly on a client with the Authorization header configured that it successfully downloads the manifest and checks for updates.

29.1.14 References

29.1.15 Munki Catalog Concepts

Munki catalogs are the main mechanism by which a Mac OS X systems administrator can deploy certain software installations and updates to one group of users, while denying those same installs and updates to another group.

Additionally, Munki catalogs allow for filtering which versions of installer items are “visible” to a specific groups of Macintosh machines. The main intention behind catalogs is to provide a method for implementing a development, testing, and production software package deployment workflow.

This multiple catalog model allows the sysadmin to test updates with a small group of
test machines before making software updates available to all production Mac OS X client machines in the computing environment. As the Mac OS X systems administrator makes changes to the development and testing catalogs and then finally pushes them out to the production catalog, minimal changes are made to the Mac OS X client manifests.

Munki catalogs are searched in the same order as they are specified in the client
manifest; if a software item is available in more than one catalog, the version in the earliest listed catalog will be used. Please be aware that development and testing catalog key entries should be placed before the production entry. As such, the earlier catalog entries will take precedence over the later entries in the manifest. Also, if there are no catalog entries in a particular client munki manifest, then the catalog listed in the parent manifest will be used.

As a caveat, munki catalogs are not recommended for making arbitrary or logical software groupings like “AdobeApps” or “Utilities”, but rather for unstable/stable or development/test/production staging, or similar deployment workflow purposes.

29.1.16 Catalog naming

You may name catalogs anything you like, with a single exception: the catalog name “all” is reserved for use internally by Munki. You should not create a catalog named “all”. You should also not point any client to the “all” catalog.

Catalog names take on the case-sensitivity of the underlying filesystem on which they are stored. This can have unexpected consequences. In general, it is best to avoid catalog names that differ only by case.

On a case-insensitive filesystem (like JHFS+, the most commonly used filesystem on Mac OS X, or NTFS, the most commonly used filesystem on Windows), you will have undesired behavior if you have catalog names that differ by case. A catalog named “testing” and one named “Testing” cannot exist at the same time in the same directory of a case-insensitive filesystem. Depending on the Munki version, this can result in one catalog overwriting the other, or may cause makecatalogs to display a warning message.

29.1.17 Practical Munki catalog examples

Currently, munki catalogs are created by the Mac OS X systems administrator with a command line tool (written as a Python script) named “makecatalogs” (usually installed
in /usr/local/munki/makecatalogs). This tool can be run directly on the munki web server (if it is running Mac OS X) or on any machine that has mounted the munki repo storage as a file share. makecatalogs recursively walks the munki repo/pkgsinfo directory and then builds a XML catalog file based on the pkginfo files it finds, complete with relative paths to the appropriate installer items.

Munki manifests usually have one or more catalog key entries such as “testing” or “production” which point the client manifest to munki catalogs to search for installation packages. This allows you to have a munki manifest named “A-mac” that searches both the “testing” and “production” catalogs, and another munki manifest named “B-mac” that searches only the “production” catalog.

In this scenario, a new version of a software package is added to the “testing” catalog first. Mac OS X client machines with “testing” catalog entries in their manifests can see and download the new package immediately and can install it via the “Managed Software Updates” interface. Client machines with manifest “B-mac” won’t see the new package until it is added to the “production” catalog.

The underlying idea here is that most of the Mac OS X client machines in a given computing environment are configured to use the production catalog only. Here is a simplified example of a production client machine manifest:

<key>catalogs</key>
<array>
    <string>production</string>
</array>

In another example, a group of test machines are configured to also search the testing catalog:

<key>catalogs</key>
<array>
    <string>testing</string>
    <string>production</string>
</array>

Finally, a much smaller group (maybe just a single systems administrator) may have a development catalog entry in their manifest as well. Take special note of the order of the catalog key entries, as this is important. Earlier catalog entries will take priority over later entries. Be careful not to reverse the order of these catalog entries or there will be unexpected results such as development and testing Mac client machines not installing the newest versions of software available.

<key>catalogs</key>
<array>
    <string>development</string>
    <string>testing</string>
    <string>production</string>
</array>

Continuing on with this example, let’s say the “in production”, supported version of Firefox is 3.6.3. This version is in the production catalog, so all client machines that have an entry in their manifest like this:

<key>managed_installs</key>
<array>
    <string>Firefox</string>
</array>

and are looking only at the production catalog will get Firefox 3.6.3. Mozilla then releases Firefox 3.7. The Mac OS X systems administrator doesn’t want every production client machine to get the new version right away; the update should first go to a subset of test machines and users. So the sysadmin makes a pkginfo file and assigns it only to the testing catalog, and then runs the “makecatalogs” script to update the catalog.

The client machines that have “Firefox” in the managed_installs section of their manifests and have “testing” in their catalogs entry can now “see” Firefox 3.7, so
they automatically download and have this new version available for install. The
vast majority of client machines, though, don’t have “testing” in their list of catalog entries. As a result, these production client machines do not see the listing for Firefox 3.7 and stay with Firefox 3.6.3.

Later, the sysadmin decides Firefox 3.7 is stable and solid in the computing environment
and wants to install it on all production client computers. So then the sysadmin edits the pkginfo file for Firefox 3.7, changes its catalog assignment to “production”, and rebuilds the catalogs.

Now all production client machines in your organization can “see” Firefox 3.7 and automatically download it. Additionally, all of the machines that didn’t install it while it was in testing can install it now via the “Managed Software Updates” interface.

29.1.18 Catalogs and included_manifests

Munki manifests can contain other manifests. These are listed under “included_manifests” in a given manifest. If an included manifest contains a list of catalogs, these are the only catalogs that will be used for managed_installs/managed_updates/managed_uninstalls items within that manifest.

This is often not what is wanted, especially when included manifests are used to group commonly used software packages. Often what is wanted is for Munki to use the catalogs defined in the “primary” manifest; that is, the main manifest used by the machine running Munki. In this case, your included manifest(s) would have no catalog list. If an included manifest has no catalog list, the catalog list of the parent manifest is used. This enables the Munki administrator to create groups of packages or application installs by defining them in an included manifest, while controlling the development/testing/production version for a given client in the client’s primary manifest.

29.1.19 Conclusion

In summary, using the multiple munki catalog model is an efficient way for the Mac OS X
systems administrator to manage a complete enterprise wide systems and applications software deployment workflow. This method minimizes the need to manually edit client manifest files and allows for a large number of software packages to be tested and brought into production on client Mac machines in a short amount of time.
Tips on securing a Munki data repository

29.1.20 USING MUNKI WITH SSL CLIENT CERTIFICATES

29.1.20.1 INTRODUCTION

By default, Munki uses standard HTTP requests for transporting files, but like most web based transport, it can be secured using by HTTPS to encrypt communications with the web server. However, HTTPS only secures the contents of the data on the wire as it passes from host to host – it does not have the facility to control which hosts or users can access a site.

If the data you choose to store in the Munki repo is considered sensitive or privileged, you will require a means of controlling exposure. To regulate access, Munki provides support for SSL Client Certificates to ensure only authorized clients utilize the Munki data.

29.1.20.2 REQUIREMENTS

This document assumes that you have already provisioned a web server for Munki, and are familiar with the basic tenets of Public Key Infrastructure and Apache HTTP Services. In addition, you should already have a web server with properly registered DNS for the host.

The examples and tools referenced in this document are based on the builtin Apache 2.2 httpd service in Mac OS X Server. Other web servers or Apache installations will be similar, but not in all cases.

To complete this demo, you will be required to download the provided materials.

==== Click here to download the materials used in this demo. ====

Once you have downloaded the materials, unpack them, you can put them anywhere you like. When you have completed the initial setup, you will migrate the materials to a more appropriate location.

Disclaimer: The scripts provided in the materials folder are only intended to exemplify the basic operations required to secure and maintain a Munki+Apache repo. They should in no way be considered exhaustive or authoritative. If you to use these scripts in a production environment, you do so at your own risk.

29.1.20.3 CONTENTS

  • Securing Apache
  • Certificates
    • Creating an OpenSSL Configuration
    • Creating a Certificate Authority
    • Creating a Server Certificate
    • Creating a Client Certificate
    • Revoking a Client Certificate
  • Installing the CA
  • Creating a Secure Virtual Host
    • Setup
  • Configuring Munki to use SSL Certificates
  • Troubleshooting

29.1.20.4 Securing Apache

To configure a secure Munki HTTPS repository, we will need to do two things: establish a Certificate Authority and create a Secure Virtual Host configuration for Apache to serve.

If you have not already done so, login to your server host and download the demo materials. We will assume you to be working on the actual Munki web server for this portion of the demo.

NOTE: The certificates we are going to be generating are 1024 bits long. This is the lowest common denominator approach, instituted to avoid compatibility issues with Apache and like components.

29.1.20.4.1 Certificates

To setup the CA and other actions, we will use a series of scripts. These scripts use simple calls to the /usr/bin/openssl utility to batch configure many of the tedious operations required to perform these tasks. Those that have used openssl utility before know that it is largely interactive, and requires one to answer a great number of questions during execution.

  • Creating an OpenSSL Configuration

    To expedite the setup, it is recommended that you create a custom OpenSSL configuration file to prepare some sane defaults during operation. Not only will this step save you some time later, but it will also ensure your answers remain consistent where they need to be.

  1. In the unpacked materials folder, you will see a subfolder labeled config. Browse into that folder and begin by opening the openssl.cnf file in your text editor of choice. For more information about the openssl.cnf file, see the man page for config. Provided below are a list of default values you should edit before proceeding. You may need to add these keys in some cases:
  2. default_days = 365 –> CRL Expiration period in days.
  3. countryName_default = AU –> Country Code. Two letters.
  4. stateOrProvinceName_default = Some-State –> Province/State. Not abbreviated.
  5. localityName_default = Locality Name (eg, city) –> City
  6. 0.organizationName_default = Internet Widgits Pty Ltd –> Company
  7. organizationalUnitName_default = Organizational Unit Name (eg, section) –> Department
  8. commonName_default = Common Name (eg, YOUR name) –> MUNKI_CA
    • This last default is singular. Unlike the rest of the defaults, each certificate you create will have a unique CN. I would suggest using a default indicated above.
  9. emailAddress_default = Email Address –> Administrator’s Email
  10. Once you have made the appropriate modifications to the openssl.cnf, you may save it and close the editor.

  • Creating a Certificate Authority

    The easiest way to create a CA, is to use the supplied script createCA.sh. This script will create a self contained CA which you can migrate to a secure location later. We will not go into detail about the openssl demoCA structure here. If you need further information, consult Google or read the various man pages for the openssl utility.

  1. Open Terminal.app and cd into the unpacked materials folder
  • Inside this directory you should see several folders listed: bin, config, servers, and clients.
  1. Begin the setup by running the following command: sudo ./bin/createCA.sh
  2. The first prompt you receive asks you to create a password.
  • This is for the CA’s private key passphrase. Make it a good one, and remember it always. You will need to refer to this password time and again.
  1. Next are a series of prompts for which you have already selected defaults by editing the openssl.cnf file.
  • You can select the default by simply hitting enter when prompted for a value.
  1. Next we generate the Certificate Revocation List (CRL).
  • Enter the passphrase for the CA’s private key. If you mess up, you will have to start over again or generate the CRL manually.
  1. Setup is complete.
  • Inside your current working directory, you should have a new folder labeled demoCA which stores your PEM formatted ca.crt and a.key, as well as the other files need to manage your CA.
  • You are now ready to start signing certificate requests, and you will begin by signing the CSR for your server.
  • Do not close Terminal.app.

  • Creating a Server Certificate

Creating a certificate for your server is a very similar process. We are going to use a script again, but there are two differences: We will remove the passphrase from the server’s private key, and we need to select a specific CN for the server’s certificate.

Unlike the CA’s key, we need to remove the passphrase from the server’s private key because this certificate will be used in a non-interactive environment (httpd). Failure to do so would result in us having to type in the passphrase for the key each time we restarted the web service.

The other difference is that we are going to use the server’s fully qualified domain name (FQDN) for the CN portion of the server’s certificate DN. Though this step is not strictly necessary in the present context, this will ensure that the certificate is uniquely identified with a particular host, in this case our server.

  1. Begin by invoking the newServer.sh script, like this: sudo ./bin/newServer.sh your.server.com.
  • This script needs one argument – the name of your server. It will verify this via DNS before continuing, so enter it properly.
  1. The script will again ask you for a passphrase.
  • Do not worry about selecting a strong passphrase. You have to enter something, so use “xxxx” or something similar.
  1. You will now be asked to remove the passphrase you just entered.
  • Enter the passphrase, and it will be removed from the key (this gives new meaning to the phrase “redundant security”).
  1. Next, you will use the defaults we set up to answer the questions, but when prompted for the CN, use the FQDN of your Munki Server.
  • You may also specify a different email address if so desired.
  1. Two new questions here, A challenge password [] and An optional company name []:.
  • Simply hit return to leave these attributes blank.
  1. After the CSR is generated, we need to have the CA sign it to prove it’s validity.
  • You are the CA, so when prompted to enter the passphrase, do so, and choose yes and yes respectively to Sign the certificate? [y/n] and 1 out of 1 certificate requests certified, commit? [y/n].
  1. Once the above is complete, the script will install the server certificate and key under the servers/<your.server.com> directory for later use.
  • Server certificate creation is complete.
  • Do not close Terminal.app.

  • Creating a Client Certificate

With our server certificate in hand, we are ready to create a client certificate/key pair that we can distribute to those we will grant access to the server. This step is identical to the previous in almost every way:

We still generate a private key

We still remove the passphrase

We still select a unique value for the CN

We still have the CA sign the CSR, but …

Different Location: In contrast to the server certificate, your end-product will be stored in clients/<clientname> – that’s easy enough to see, and makes sense too.

File Format: Worthy of note, the addClient.sh script we are about to use will concatenate the certificate and private key into a single file that will make it more convenient to distribute.

  1. Like before, invoke the script, using the full path and a single argument: sudo ./bin/addClient.sh munki_client
  • Note: The argument name is arbitrary, but if you want to use a client name with spaces, this script (and presumably the others) will not work.
  • This is a limitation of the script, primitive as it is. So, for the purposes of the demo, select a name that does not contain any spaces.
  1. For instructions regarding selecting a passphrase, and it’s subsequent removal, see steps 2 and 3 in the section above.
  2. Again, we are going to be leveraging the defaults we setup (I am sure you are glad you did this now.), but answer carefully when asked for a CN.
  • Enter the same name we provided as an argument to the script: munki_client
  1. Enter the CA private key password and we receive another familiar set of questions, Sign the certificate? [y/n] and 1 out of 1 certificate requests certified, commit? [y/n].
  • As before, leave them blank, and hit enter to continue.
  1. At this stage, the script has all the information needed to generate a certificate/key pair combo file. It will do this without any further intervention. When it is complete you should find the file clients/munki_client/munki_client.pem is available to distribute to your client.
  • Client Certificate creation is complete.
  • Do not close Terminal.app.

  • Revoking a Client Certificate

Before we continue with instructions for installing the CA, it is vital we touch on an important characteristic of leveraging PKI in this manner. What we are doing here is preparing to grant access to clients based solely on the possession of a certificate signed by our duly appointed Certificate Authority. Great! We only give the certs to people we trust so, no problem.

But, what if some black hat or maladjusted user absconds with the cert? Well, we could panic for little while and then resolve to wait for the certificate to expire, but that may take a long time… We could try and track down the hacker and make them give back the certificate and all the copies they made for their friends… Or maybe we just destroy the CA and start over… You get the picture.

Enter the Certificate Revocation List. This is a list of all the certs that you have issued to clients, but you no longer wish to validate – a blacklist of sorts. Good News: the createCA.sh script has already generated a CRL for you, all we need to do is get revoking.

Note: DO NOT revoke our previously created client cert unless you are willing to re-create it. We will need it later in the demo. If you choose, you can run through the setup for a separate client cert to try this script out.

  1. To revoke a previously issued certificate, invoke: sudo revokeCert.sh munki_client
  • Where munki_client is the name of the certificate to revoke, without any file extension. (ie. If you created clients/foobar and distributed foobar.pem, you would send the argument foobar.)
  • Again, no spaces here. The scripts will choke.
  1. When the script receives the argument, it will check to ensure you have first issued a certificate with that name before proceeding. If the client exeists, it will revoke the certificate and restart the web server to force Apache to reload the CRL.
  • Do not close Terminal.app.

29.1.20.5 Installing the CA

Once configured, your CA is ready to install, but where do you put it? Well, you can place it wherever you like as long the location is:

  1. Secure
  • Choose a sensible location and ensure you apply appropriate permissions.
    • Suggested: /private/etc would be a good choice.
    • Permissions: The createCA.sh should apply appropriate permissions; see the script for further detail.
  1. Accessible to Apache
  • Ensure that your CA is located in a place accessible to Apache, and has permissions appropriate to do so.

For the purposes of this demo, securely relocate the unpacked materials to the suggested location:

  1. cd /
  2. sudo cp -R /path/to/unpacked/materials /private/etc/munki
  • Do not close Terminal.app.

CHECK: When you are done, the /private/etc/munki directory should contain: bin, clients, config, demoCA, and server.

29.1.20.6 Creating a Secure Virtual Host

If you haven’t noticed already, /private/etc/munki/config contains a boilerplate secure virtual host configuration for Apache: munki.conf. Also contained in the config directory is a separate archive: munki-site.zip – this is the sample Munki repo that we will be using for the demo.

  • Setup

We need to do three things here. The first thing is edit the virtual host configuration. Second, unpack the demo site. Again, this is based on Mac OS X Server default configurations. You can store the site anywhere you like, but we are going to be using a vanilla setup. The third thing we need to do is install the Apache virtual host.

NOTE: The virtual host configuration in the demo actually describes a secure virtual host, and a distinct “members-only” directory for the Munki repo. More on this below …

  1. Edit the Virtual Host Configuration
  • Grab a copy of the munki.conf and put it on your Desktop
  • Open the file in your editor of choice
    1. Edit the ServerName directive to match the FQDN of your server
    2. Edit the ServerAdmin directive to match the web admin’s email address
    3. Edit the four SSL file directives to point to their appropriate files.
    • If you put the munki CA in /private/etc, then you will only need to edit the SSLCertificateFile and SSLCertificateKeyFile directives to match your server name.
    1. Edit the SSLRequire directive
    • The conditionals used in this directive are directly related to attributes of your client certificate’s DN. Edit this carefully to match the applicable attributes. There is more information about this in the comments of the actual virtual host configuration file.
  1. Setup the Site Folder
  • Open Terminal.app
  • sudo cp /private/etc/munki/config/munki-site.zip /Library/WebServer/Documents
  • cd /Library/WebServer/Documents
  • sudo unzip /Library/WebServer/Documents/munki-site.zip
  • sudo chown -R root:admin /Library/WebServer/Documents/munki
  1. Setup the Virtual Host
  • Copy the munki.conf file to
  • sudo cp ~/Desktop/munki.conf /private/etc/apache2/sites
  1. Restart the Web Server

This concludes the setup of our secure Munki repo. When the web services on your server are restarted, your secure site should be available at …

https://your.server.com

Try it out in your browser. You should be prompted to download the server’s public certificate and then be presented with an image. Likewise, the actual repository which lives one level down should also prompt you, but this time it will want you to supply the certificate …

https://your.server.com/repo

If all went well, you should be prompted to supply a certificate. Don’t worry about trying to install the certificate and testing it in your web browser. Web browsers can be irksome when dealing with client certs. We will do some testing in the next step.

If you do not achieve the expected results, or something went wrong, try running through the setup again or consult the Troubleshooting section at the end for this document for possible causes.

29.1.21 Configuring Client to use SSL Certificates

The labour of setting up your secure web site is about to pay off. Configuring a Munki client to use certificate-based authentication couldn’t be easier…

  • Configuration
  1. Install the Munki Package
  • You can download the latest Munki Mac OS X installer package here.
  1. Install the Client Certificate
  2. You will need to transport a copy of the client certificate munki_client.pem from the server’s CA store to the intended client. Do this in any manner you see fit, (scp is a good choice) but place it on the Desktop for easy access.
  3. sudo mkdir /Library/Managed\ Installs/certs
  4. sudo chmod 0700 /Library/Managed\ Installs/certs
  5. sudo mv ~/Desktop/munki_client.pem /Library/Managed\ Installs/certs/munki_client.pem
  6. sudo chmod 0600 /Library/Managed\ Installs/certs/munki_client.pem
  7. sudo chown -R root:wheel /Library/Managed\ Installs/certs
  8. Edit the ManagedInstalls.plist
  9. Open the preferences file in your editor of choice
    • If you do not already have a Munki preferences file see [configuration] for details.
  10. Edit the ManifestURL key to contain the URL for your server host
  11. Remove the value from the ClientIdentifier key
    • This key should be left blank
  12. Edit the SoftwareRepoURL key to contain the repo URL for your host
  13. Edit the boolean UseClientCertificate key so that is is true
    • Configuration of the client is complete.
    • Do not close Terminal.app.

With the Munki preferences file configured and the certificate/key combo file securely installed, we should no be able to access the secure repo.

  • Test the Setup
  1. sudo /usr/local/munki/managedsoftwareupdate -v -v -v --checkonly
  • Expected result? Your Munki client should be able to download its manifest from the secure repo.

29.1.22 Troubleshooting

This documentation is only meant to provide a jumping off point for setting up an Apache/SSL config – it is not exhaustive. Since it was written, much of the munki code has changed. The addition of curl now provides support for a fully implemented SSL setup and it works very well. I think the wiki page still provides a good overview of what is involved in getting the setup you are looking for (ie. The creation of a CA, Certs, etc.) but it cannot be expected to work out-of-thebox in every environment. The key to getting a functional secure setup is understanding the mechanics of an Apache/SSL configuration and being able to troubleshoot it.

If you are having trouble using the virtual host config file provided in the demo materials (many people have), try creating your own basic secure setup using Mac OS X Server Admin. I would advise first getting your feet wet by simply getting communications between server and client using SSL, and not worrying about client certs.

If you have correctly used the scripts in the demo materials to generate a CA and server certificate, you can use these in a stock Mac OS X Server setup.

  • At the Server…
  1. Use Server Admin to import the server certificate and corresponding private key
  2. Use Server Admin to create a new virtual host (Server Admin calls this a “Site”)
  3. Configure the new virtual host to use this key pair to encrypt the service
  • “Enable Secure Sockets Layer (SSL)”
  1. Turn the service on
  2. Open Safari so we can test the new virtual host
  3. Enter the URL for your secure Apache host
  • Safari should prompt you about verifying the identity of the website; this is because the CA you created that signed the server’s cert is not trusted.
  • This is OK and proves that the server’s cert is active and the service is working
  1. Close Safari
  • You now have a secure virtual host
  1. Stop the Web service
  2. Adjust the “Web Folder” path on your virtual host to point to your munki repo
  • Ensure you have the root correct
  • Make sure you save
  1. Start the Web service
  2. Use Safari and the enter the URL to your secure virtual host and test that you can access some of the munki repo resources.
  • If you can retrieve any of the manifests or catalogs, you are in business.

  • At the Client…

  1. Edit ManagedInstalls.plist and change the URLs for your ManifestURL and SoftwareRepoURL so that they specify “https://
  2. Now try running: sudo managedsoftwareupdate -vvv –checkonly
  • managedsoftwareupdate should complain
  • “ERROR: Error 60: SSL certificate problem, verify that the CA cert is OK. Details:”
  • this happens because the server cert’s CA is not trusted; the same thing that happened with Safari
  1. To correct this you can do one of two things:
  2. Import the CA certificate into the System.keychain
  3. Add a SoftwareRepoCACertificate key to the ManagedInstalls.plist
  • I would advise solution B.
  1. Solution B:
  • cd /Library/Managed\ Installs
  • sudo mkdir certs
  • sudo scp :/path_to_your_demoCA/demoCA/cacert.pem ./certs/cacert.pem
  • sudo defaults write /Library/Preferences/ManagedInstalls SoftwareRepoCACertificate “/Library/Managed Installs/certs/cacert.pem”
  1. Try running: sudo managedsoftwareupdate -vvv –checkonly
  • This time it should work!

If you can get this far, you have one part of the setup done and using client certs is just around the corner.

Hope this helps,

– Brian

29.1.23 = Under Construction =

29.1.24 References

http://www.modssl.org/docs/2.8/ssl_howto.html#auth-simple

http://httpd.apache.org/docs/2.0/

http://www.securityfocus.com/infocus/1823

http://developer.apple.com/internet/serverside/modssl.html

http://onlamp.com/onlamp/2008/03/04/step-by-step-configuring-ssl-under-apache.html

http://it.toolbox.com/blogs/securitymonkey/howto-securing-a-website-with-client-ssl-certificates-11500

http://www.afp548.com/articles/system/ldap-ssl.html

http://code.activestate.com/recipes/117004/

http://www.osmonov.com/2009/04/client-certificates-with-urllib2.html

http://www.threepillarsoftware.com/soap_client_auth

http://bugs.python.org/issue3466
An example of using preflight scripts and a server-side plist to achieve WPKG-like grouping of clients based on hostnames and regex.

NOTE: This is a user-contributed solution and is not directly part of Munki. It may not work in your environment, or with future OS releases or future releases of Munki.

29.1.25 The Problem

Out of the box, client configuration scenarios for Munki feel like trying to choose between the lesser of a handful of evils. Looking at all the documentation, I saw no middle ground between the following 3 cases:

  1. Specific ClientIdentifier’s specifically written into the client configuration plist. This requires changing client-id’s individually on the client-side when wanting to make manifest configuration more granular or changing which manifest a client receives. Large scale changes become difficult, and tracking which clients are in which group becomes a chore.
  2. For server-side configuration of ClientIdentifier’s you can make a manifest with the exact name of a client, but then there needs to be one manifest for each client even if most of the clients have 90% similar software to each other. As well, when a new client is installed there needs to be a manifest created before it can receive software updates. This is the only future-proof way to roll-out munki without further scripting or programming.
  3. As a last resort, you could simply use the default manifest to serve all software to all clients. This means department-specific licensed software isn’t managed, and so needs to be done manually. That defeats a lot of the purpose of managed software.

None of these are ideal, but they’re really the only options for Munki out of the box unless you want to script your own CGI based off the example. Unfortunately, this complicates the server setup. Do you really want to enable CGI just to cater to one script? What if you can’t enable CGI because you’re hosting the Munki repository off of a NAS box? There’s elegance and worth in the flat file server structure. It makes backup and portability a cinch.

29.1.26 The Solution

The answer is to adopt WPKG’s behavior for attaching manifests to hostnames while using a preflight script for the matching logic in order to maintain flat file server structure. For those who haven’t worked with WPKG, at its heart the hosts.xml file is just a list of hosts and profiles. The magic, though, is that it allows for regex in the definition of hostnames. So if you construct your hosts.xml as a list going from most specific to least specific regex then you get configuration files that are only ever as granular as they need to be. The hosts.xml, or in this case the MunkiManagedHosts.plist, resides on the server while the logic for matching the regex to the hostname is done through a preflight script on the client.

Below is an example based on the configuration currently in use at my organization. I have a bunch of ordinary clients that only need the basic set of software. I also have a few departments, like Editorial, that use a few other pieces of software. In addition, I have a single test machine which needs to be getting a separate set of packages so that I can test packages before rolling them out to users.

My test machine has the hostname “IT2”. Editorial machines have hostnames like “Editorial1”, “Editorial2”,“Editorial3”, and so on. Other machines have a variety of other names. In practice, my ManagedMunkiHosts.plist file comes out looking something like this:

29.1.26.1 MunkiManagedHosts.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">

<!--
Format of file and behavior based on WPKG.org's hosts.xml behavior.
Host names can be either direct matches or in the form of a regex.
Script returns only first match, so be careful with specificity and ordering of hosts.
-->
<dict>
    <key>hosts</key>
    <array>
         <!-- configure one specific host like my test machine-->
        <dict>
            <key>name</key>
            <string>IT1</string>
            <key>manifest-id</key>
            <string>testing</string>
        </dict>
         <!-- take advantage of internal naming schemes to separate by department -->
        <dict>
            <key>name</key>
            <string>EDITORIAL.+</string>
            <key>manifest-id</key>
            <string>editorial</string>
        </dict>
        <!-- use a catch-all for all other basic clients-->
        <dict>
            <key>name</key>
            <string>.+</string>
            <key>manifest-id</key>
            <string>default</string>
        </dict>
    </array>
</dict>
</plist>

The MunkiManagedHosts.plist regex solution allows fine control over granularity, but doesn’t make that granularity a requirement for admins that don’t want to shoot themselves in the foot with something that would be difficult to change later.

In terms of the structure of my manifests, I have a default manifest for all software that needs to be installed everywhere. Then I have the editorial manifest that refers to the default manifest, but then adds a few department-specific pieces of software. My testing manifest gets all default software, but from the testing catalog rather than the default catalog.

The preflight script that makes this all possible is as follows:

29.1.26.2 preflight

#!/usr/bin/python

import sys
import os
import socket
import re
from munkilib import fetch
from munkilib import FoundationPlist

## disturbing hack warning! (untested for < 10.11)
## this works around an issue with App Transport Security on 10.11
## Remove the comment hashes from the following 4 lines for 10.11+
#from Foundation import NSBundle
#bundle = NSBundle.mainBundle()
#info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
#info['NSAppTransportSecurity'] = {'NSAllowsArbitraryLoads': True}

#
#WPKG-like Dynamic Manifest based on Hostname Preflight Script by John Rozewicki
#2010-12-08
#
#Pulls the hosts plist config from Munki repo if newer. This hosts plist is 
#a regex-able mapping of hostnames to manifests in order to mimic the 
#functionality of the WPKG hosts.xml file.
#
#Hosts from the hosts plist are parsed in order, and the script bails after the
#first match. This allows for specificity of manifests to be handled server-side
#rather than on the client, and also allows for admins to make manifest
#delineation only as granular as is necessary.
#

RepoURL = "http://YOUR_REPO_ROOT_URL_HERE"
ConfigName = "ManagedInstalls.plist"
HostsFileName = "ManagedMunkiHosts.plist"
ConfigDir = "/Library/Preferences"
ConfigPath = os.path.join(ConfigDir, ConfigName)
HostsFileURL = os.path.join(RepoURL, HostsFileName)
HostsFilePath = os.path.join(ConfigDir, HostsFileName)

def UpdateClientIdentifier(ConfigPath, ManifestName):
    config = FoundationPlist.readPlist(ConfigPath)
    config["ClientIdentifier"] = ManifestName
    FoundationPlist.writePlist(config, ConfigPath)

if (sys.argv[1] != "logoutinstall") and (sys.argv[1] != "installwithnologout"):
    print "Checking for new %s" % (HostsFileName)
    if fetch.munki_resource(
            HostsFileURL, HostsFilePath)["http_result_code"] == "200":
        hostname = socket.gethostname()
        print "     Matching hostname to manifest."
        for host in FoundationPlist.readPlist(HostsFilePath)["hosts"]:
            name = host["name"].lower()
            manifest = host["manifest-id"].lower()
            if re.match(name, hostname):
                print "     Setting ClientIdentifier to manifest name: %s." % (manifest)
                UpdateClientIdentifier(ConfigPath, manifest)
                break

If this technique is used in conjunction with Dynamic Client Configurations Via Preflight Scripting then we have an extremely dynamic configuration with global configuration options and client -> manifest linking all handled by just 2 extra files on the server with 1 preflight script on the client.

Client configuration in this setup then becomes a simple matter of dropping a preflight script into the /usr/local/munki directory. As long as the preflight script is there, the client will always download the newest configuration from the server, and it will always link the right manifest to the client.

29.1.27 What are Stupid Munki Tricks?

This documentation section contains tricks or unusual ways various people have come up with for using Munki. Although these tricks worked when documented, they may be made obsolete or non-functional by later versions of the Munki tools.

30 Example of how the tools work

31 Introduction

Here’s a look at the current functionality of the tools.

32 Details

To wrap your head around the current functionality of the munki tools, here’s a sample workflow…

On the server, we have a manifest file for a client that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>catalogs</key>
        <array>
            <string>testing</string>
            <string>production</string>
        </array>
        <key>included_manifests</key>
        <array>
        </array>
        <key>managed_installs</key>
        <array>
                <string>ServerAdminTools</string>
                <string>TextWrangler</string>
                <string>Silverlight</string>
        </array>
        <key>managed_uninstalls</key>
        <array>
        </array>
</dict>
</plist>

Note that under “managed_installs” we have listed three items.
On the client:

root# /usr/local/munki/managedsoftwareupdate
Managed Software Update

Retreiving list of software for this machine...
    0..20..40..60..80..100

The manifest is downloaded from the server. In this demo, it’s simply named after the FQDN of the host.

Retreiving catalog 'testing'...
    0..20..40..60..80..100
Retreiving catalog 'production'...
    0..20..40..60..80..100

The testing and production catalogs are downloaded from the server. Each contains a list of available software.

Downloading TextWrangler2.3.dmg
    0..20..40..60..80..100
Downloading Silverlight.2.0.40115.0.dmg
    0..20..40..60..80..100

managedsoftwareupdate compares the list of managed_installs to what’s actually installed on the machine and determines that TextWrangler and Silverlight need to be installed. It then downloads installer items for those items.
Finally, it prints a summary of what needs to be done:

The following items will be installed or upgraded:
    + TextWrangler-2.3
        Free text editor from the makers of BBEdit
    + Silverlight-2.0.40115.0.0
        Microsoft browser plugin for rich Internet experience

That’s the initial run of managedsoftwareupdate. It writes out an InstallInfo.plist that looks like this:

root# cat /Library/Managed\ Installs/InstallInfo.plist 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>managed_installs</key>
    <array>
        <dict>
            <key>description</key>
            <string>Apple's administration tools for OS X server.</string>
            <key>installed</key>
            <true/>
            <key>installed_version</key>
            <string>10.5.3</string>
            <key>manifestitem</key>
            <string>ServerAdminTools</string>
            <key>name</key>
            <string>ServerAdministrationSoftware</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Free text editor from the makers of BBEdit</string>
            <key>display_name</key>
            <string>TextWrangler</string>
            <key>installed</key>
            <false/>
            <key>installer_item</key>
            <string>TextWrangler2.3.dmg</string>
            <key>manifestitem</key>
            <string>TextWrangler</string>
            <key>name</key>
            <string>TextWrangler</string>
            <key>version_to_install</key>
            <string>2.3</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Microsoft browser plugin for rich Internet experience</string>
            <key>display_name</key>
            <string>Microsoft Silverlight</string>
            <key>installed</key>
            <false/>
            <key>installer_item</key>
            <string>Silverlight.2.0.40115.0.dmg</string>
            <key>manifestitem</key>
            <string>Silverlight</string>
            <key>name</key>
            <string>Silverlight</string>
            <key>version_to_install</key>
            <string>2.0.40115.0.0</string>
        </dict>
    </array>
    <key>removals</key>
    <array>
    </array>
</dict>
</plist>

This shows the state of each managed item, and is used by the managedsoftwareupdate to do the actual installs. Let’s do that now:

root# /usr/local/munki/managedsoftwareupdate --installonly 
Mounting disk image TextWrangler2.3.dmg
Preparing for installation
Preparing the Disk
Preparing Target Volume
Preparing TextWrangler2.3
Installing TextWrangler2.3
Configuring Installation
Validating package
Writing files
Writing files: 28% complete
Writing files: 66% complete
Writing package receipt
Finishing Installation
Finishing Installation
The software was successfully installed
Mounting disk image Silverlight.2.0.40115.0.dmg
Preparing for installation
Preparing the Disk
Preparing Target Volume
Preparing Microsoft® Silverlight™ Browser Plug-In
Running Microsoft® Silverlight™ Browser Plug-In Installer script
Installing Microsoft® Silverlight™ Browser Plug-In
Configuring Installation
Validating package
Writing files
Writing files: 0% complete
Writing files: 95% complete
Writing package receipt
Finishing Installation
Running Microsoft® Silverlight™ Browser Plug-In Installer script
Finishing Installation
The software was successfully installed

managedsoftwareyupdate reads the contents of !InstallInfo.plist and installs the items in order, using the installation packages downloaded and cached earlier. It also logs its actions in /Library/Managed\ Installs/Logs/ManagedSoftwareUpdate.log:

Mon May 11 11:36:06 2009 ### Beginning managed installer session ###
Mon May 11 11:36:06 2009 Processing installs
Mon May 11 11:36:06 2009 Mounting disk image TextWrangler2.3.dmg
Mon May 11 11:36:10 2009 Installing TextWrangler2.3 from TextWrangler2.3.pkg
Mon May 11 11:36:12 2009  Package name is TextWrangler2.3
Mon May 11 11:36:12 2009  Installing at base path /
Mon May 11 11:36:16 2009  The install was successful.
Mon May 11 11:36:21 2009 Install of TextWrangler2.3 was successful.
Mon May 11 11:36:21 2009 Mounting disk image Silverlight.2.0.40115.0.dmg
Mon May 11 11:36:26 2009 Installing Microsoft® Silverlight™ Browser Plug-In from Silverlight.2.0.pkg
Mon May 11 11:36:28 2009  Package name is Microsoft® Silverlight™ Browser Plug-In
Mon May 11 11:36:28 2009  Installing at base path /
Mon May 11 11:36:31 2009  The install was successful.
Mon May 11 11:36:32 2009 Install of Microsoft® Silverlight™ Browser Plug-In was successful.
Mon May 11 11:36:33 2009 ###    End managed installer session    ###

If we run managedsoftwareupdate again…

root# /usr/local/munki/managedsoftwareupdate 
Managed Software Update

No changes to managed software scheduled.

For more info, let’s look at the log (/Library/Managed Installs/Logs/ManagedSoftwareUpdate.log):

Mon May 11 11:38:10 2009 ### Beginning managed software check ###
Mon May 11 11:38:10 2009 Getting manifest client_manifest.plist from http://munki/repo/manifests/greg_neagle...
Mon May 11 11:38:10 2009 **Checking for installs**
Mon May 11 11:38:10 2009 Getting catalog testing from http://munki/repo/catalogs/testing...
Mon May 11 11:38:10 2009 Getting catalog production from http://munki/repo/catalogs/production...
Mon May 11 11:38:10 2009 Looking for detail for: ServerAdminTools, version latest...
Mon May 11 11:38:10 2009 Found: ServerAdministrationSoftware  10.5.6.1.1  apps/ServerAdmin10.5.6v1.1.dmg
Mon May 11 11:38:10 2009 ServerAdminTools version 10.5.3 is already installed.
Mon May 11 11:38:10 2009 Looking for detail for: TextWrangler, version latest...
Mon May 11 11:38:10 2009 Found: TextWrangler  2.3  apps/TextWrangler2.3.dmg
Mon May 11 11:38:10 2009 TextWrangler version 2.3 is already installed.
Mon May 11 11:38:10 2009 Looking for detail for: Silverlight, version latest...
Mon May 11 11:38:10 2009 Found: Silverlight  2.0.40115.0.0  internet/Silverlight.2.0.40115.0.dmg
Mon May 11 11:38:11 2009 Silverlight version 2.0.40115.0.0 is already installed.
Mon May 11 11:38:11 2009 **Checking for removals**
Mon May 11 11:38:11 2009 No changes to managed software scheduled.
Mon May 11 11:38:11 2009 ###    End managed software check    ###

managedsoftwareupdate determines that all our managed items are installed and schedules no work to be done.

We can run managedsoftwareupdate –installonly again:

aquaman:~ root# /usr/local/munki/managedsoftwareupdate --installonly
aquaman:~ root#

and it does nothing:

root# tail /Library/Managed\ Installs/Logs/ManagedSoftwareUpdate.log 
Mon May 11 11:41:53 2009 ### Beginning managed installer session ###
Mon May 11 11:41:53 2009 ###    End managed installer session    ###

I can remove a managed item:

root# rm -rf /Applications/TextWrangler.app

and when I run managedsoftwareupdate again:

root# /usr/local/munki/managedsoftwareupdate 
Managed Software Update

Downloading TextWrangler2.3.dmg
    0..20..40..60..80..100
The following items will be installed or upgraded:
    + TextWrangler-2.3
        Free text editor from the makers of BBEdit

It sees !TextWrangler is missing and schedules a reinstall.

root# /usr/local/munki/managedsoftwareupdate --installonly 
Mounting disk image TextWrangler2.3.dmg
Preparing for installation
Preparing the Disk
Preparing Target Volume
Preparing TextWrangler2.3
Installing TextWrangler2.3
Configuring Installation
Validating package
Writing files
Writing files: 3% complete
Writing files: 9% complete
Writing files: 17% complete
Writing files: 29% complete
Writing files: 38% complete
Writing files: 47% complete
Writing files: 58% complete
Writing files: 65% complete
Writing files: 65% complete
Writing files: 67% complete
Writing files: 71% complete
Writing files: 75% complete
Writing files: 77% complete
Writing files: 77% complete
Writing files: 91% complete
Writing package receipt
Finishing Installation
Finishing Installation
The software was successfully installed

Finally, we can edit the manifest on the server to remove items:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>catalogs</key>
        <array>
                <string>testing</string>
                <string>production</string>
        </array>
        <key>included_manifests</key>
        <array>
        </array>
        <key>managed_installs</key>
        <array>
                <string>ServerAdminTools</string>
        </array>
        <key>managed_uninstalls</key>
        <array>
                <string>TextWrangler</string>
                <string>Silverlight</string>
        </array>
</dict>
</plist>

Here we’ve moved !TextWrangler and Silverlight from the managed_installs to the managed_uninstalls. On the client, we’ll run managedsoftwareupdate again:

root# /usr/local/munki/managedsoftwareupdate 
Managed Software Update

Retreiving list of software for this machine...
    0..20..40..60..80..100
The following items will be removed:
    - TextWrangler
    - Silverlight

A little more detail:

root# tail /Library/Managed\ Installs/Logs/ManagedSoftwareUpdate.log
Mon May 11 11:48:39 2009 ### Beginning managed software check ###
Mon May 11 11:48:39 2009 Getting manifest client_manifest.plist from http://localhost/repo/manifests/greg_neagle...
Mon May 11 11:48:39 2009 **Checking for installs**
Mon May 11 11:48:39 2009 Getting catalog testing from http://localhost/repo/catalogs/testing...
Mon May 11 11:48:39 2009 Getting catalog production from http://localhost/repo/catalogs/production...
Mon May 11 11:48:39 2009 Looking for detail for: ServerAdminTools, version latest...
Mon May 11 11:48:39 2009 Found: ServerAdministrationSoftware  10.5.6.1.1  apps/ServerAdmin10.5.6v1.1.dmg
Mon May 11 11:48:39 2009 ServerAdminTools version 10.5.3 is already installed.
Mon May 11 11:48:39 2009 **Checking for removals**
Mon May 11 11:48:39 2009 Processing manifest item TextWrangler...
Mon May 11 11:48:39 2009 Looking for all items matching: TextWrangler...
Mon May 11 11:48:40 2009 Removal of TextWrangler added to ManagedInstaller tasks.
Mon May 11 11:48:40 2009 Processing manifest item Silverlight...
Mon May 11 11:48:40 2009 Looking for all items matching: Silverlight...
Mon May 11 11:48:41 2009 Removal of Silverlight added to ManagedInstaller tasks.
Mon May 11 11:48:41 2009 The following items will be removed:
Mon May 11 11:48:41 2009     - TextWrangler
Mon May 11 11:48:41 2009     - Silverlight
Mon May 11 11:48:41 2009 ###    End managed software check    ###

managedsoftwareupdate notes that !ServerAdminTools is already installed. It then looks at !TextWrangler, sees it is currently installed, and schedules it for removal. Same for Silverlight. Here’s what the !InstallInfo.plist now looks like:

root# cat /Library/Managed\ Installs/InstallInfo.plist 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>managed_installs</key>
    <array>
        <dict>
            <key>description</key>
            <string>Apple's administration tools for OS X server.</string>
            <key>installed</key>
            <true/>
            <key>installed_version</key>
            <string>10.5.3</string>
            <key>manifestitem</key>
            <string>ServerAdminTools</string>
            <key>name</key>
            <string>ServerAdministrationSoftware</string>
        </dict>
    </array>
    <key>removals</key>
    <array>
        <dict>
            <key>description</key>
            <string>Free text editor from the makers of BBEdit</string>
            <key>display_name</key>
            <string>TextWrangler</string>
            <key>installed</key>
            <true/>
            <key>installed_version</key>
            <string>2.3</string>
            <key>manifestitem</key>
            <string>TextWrangler</string>
            <key>name</key>
            <string>TextWrangler</string>
            <key>packages</key>
            <array>
                <string>com.poleposition-sw.lanrev_installease_TextWrangler2.3.pkg</string>
            </array>
            <key>uninstall_method</key>
            <string>removepackages</string>
        </dict>
        <dict>
            <key>description</key>
            <string>Microsoft browser plugin for rich Internet experience</string>
            <key>display_name</key>
            <string>Microsoft Silverlight</string>
            <key>installed</key>
            <true/>
            <key>installed_version</key>
            <string>2.0.40115.0.0</string>
            <key>manifestitem</key>
            <string>Silverlight</string>
            <key>name</key>
            <string>Silverlight</string>
            <key>packages</key>
            <array>
                <string>com.microsoft.installSilverlightPlugin</string>
            </array>
            <key>uninstall_method</key>
            <string>removepackages</string>
        </dict>
    </array>
</dict>
</plist>

We run managedsoftwareupdate –installonly again:

root# /usr/local/munki/managedsoftwareupdate --installonly 
Removing TextWrangler...
Gathering information on installed packages: 
    0..20..40..60..80..100
Determining which filesystem items to remove: 
Removing filesystem items: 
    0..20..40..60..80..100
Removing receipt info: 
    0..20..40..60..80..100

Removing Silverlight...
Determining which filesystem items to remove: 
Removing filesystem items: 
    0..20..40..60..80..100
Removing receipt info: 
    0..20..40..60..80..100

Looking at the log:

Mon May 11 11:54:05 2009 ### Beginning managed installer session ###
Mon May 11 11:54:05 2009 Processing removals
Mon May 11 11:54:05 2009 Removing TextWrangler...
Mon May 11 11:54:05 2009 Gathering information on installed packages
Mon May 11 11:54:05 2009 /Library/Receipts/BSD.pkg is not a valid receipt. Skipping.
Mon May 11 11:55:20 2009 Determining which filesystem items to remove
Mon May 11 11:55:28 2009 Removing filesystem items
Mon May 11 11:55:28 2009 Removing: /usr/share/man/man1/edit.1
Mon May 11 11:55:28 2009 Removing: /usr/bin/edit
Mon May 11 11:55:28 2009 Removing: /Applications/TextWrangler.app/Contents/Resources/twdiff.1
Mon May 11 11:55:28 2009 Removing: /Applications/TextWrangler.app/Contents/Resources/twdiff
[snip]
Mon May 11 11:55:30 2009 Removing: /Applications/TextWrangler.app/Contents/Info.plist
Mon May 11 11:55:30 2009 Removing: /Applications/TextWrangler.app/Contents
Mon May 11 11:55:30 2009 Removing: /Applications/TextWrangler.app
Mon May 11 11:55:30 2009 Removing receipt info
Mon May 11 11:55:30 2009 Removing /Library/Receipts/TextWrangler2.3.pkg...
Mon May 11 11:55:50 2009 Uninstall of TextWrangler was successful.
Mon May 11 11:55:50 2009 Removing Silverlight...
Mon May 11 11:55:50 2009 Determining which filesystem items to remove
Mon May 11 11:55:57 2009 Removing filesystem items
Mon May 11 11:55:57 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin/Contents/Resources/zh-Hant.lproj/Localizable.strings
Mon May 11 11:55:57 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin/Contents/Resources/zh-Hant.lproj
[snip]
Mon May 11 11:55:59 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin/Contents/MacOS
Mon May 11 11:55:59 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin/Contents/Info.plist
Mon May 11 11:55:59 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin/Contents
Mon May 11 11:55:59 2009 Removing: /Library/Internet Plug-Ins/Silverlight.plugin
Mon May 11 11:55:59 2009 Removing receipt info
Mon May 11 11:55:59 2009 Removing /Library/Receipts/Silverlight.2.0.pkg...
Mon May 11 11:56:12 2009 Uninstall of Silverlight was successful.
Mon May 11 11:56:12 2009 ###    End managed installer session    ###

If we run managedsoftwareupdate again, there’s nothing to do:

root# ./usr/local/munki/managedsoftwareupdate
Managed Software Update

No changes to managed software scheduled.

32.0.1 Deploying Xcode with Munki

32.0.1.1 Xcode 8

Nothing seems to have changed between Xcode 7 and 8 for deployment. The previous postinstall scripts continue to work as expected.

32.0.1.2 Xcode 7

The postinstall_script that worked on previous versions of Xcode continues to work for Xcode 7. There is an issue, however, specifically with Xcode 7.2.1 that requires additional attention. While the postinstall_script successfully installs the packages in the /Applications/Xcode.app/Contents/Resources/Packages/ directory, on first launch, Xcode prompts for admin credentials and then proceeds to install those same packages again. The current work around is to add the following lines to the end of the existing postinstall_script to tell Xcode not to check for these packages at launch:

# disable version check for MobileDeviceDevelopment
/usr/bin/defaults write /Library/Preferences/com.apple.dt.Xcode DVTSkipMobileDeviceFrameworkVersionChecking -bool true

A possibly bad side-effect of this approach would be if someone later manually installed a newer version of Xcode that came with a newer version of the MobileDeviceDevelopment pkg, Xcode would not attempt to install it.

32.0.1.3 Xcode 6

The same directions below used to deploy Xcode 5 continue to work for Xcode 6, verified with Xcode 6.1.1. Additionally, the Xcode Command Line Tools can be installed by either downloading them from the Apple Developer site and importing them into Munki, or by following the method described by Rich Trouton on his blog.

32.0.1.4 Xcode 5

I recommend you get a Mac Developer membership and use the version of Xcode available on the Developer site; this avoids having to deal with the App Store challenges. If you use the App Store version, see [[App Store Apps]] for some advice.

I’ve had good success with using munkiimport to import the Xcode 5 disk image, and then adding the following postinstall_script to the pkginfo:

<key>postinstall_script</key>
<string>#!/bin/sh

# make sure all users on this machine are members of the _developer group
/usr/sbin/dseditgroup -o edit -a everyone -t group _developer

# enable developer mode
/usr/sbin/DevToolsSecurity -enable

# accept Xcode license
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -license accept

# install embedded packages
for PKG in /Applications/Xcode.app/Contents/Resources/Packages/*.pkg; do
    /usr/sbin/installer -pkg "$PKG" -target /
done
</string>

Depending on your exact needs, you may need to modify this script and/or perform additional tasks.

32.0.1.5 Xcode 4.5

There are two extra installers that need to be installed after installing Xcode 4.5.2: Xcode.app/Contents/Resources/Packages/MobileDevice.pkg and Xcode.app/Contents/Resources/Packages/MobileDeviceDevelopment.pkg

You should mark them as update_for Xcode 4.5.2 so they can be uninstalled as well when Xcode is uninstalled. You can import the packages using munkiimport:

munkiimport /Applications/Xcode.app/Contents/Resources/Packages/MobileDevice.pkg --update_for=Xcode-4.5.2
munkiimport /Applications/Xcode.app/Contents/Resources/Packages/MobileDeviceDevelopment.pkg --update_for=Xcode-4.5.2

Xcode also needs a postinstall_script to enable developer mode and add users to the developer group:

    #!/bin/sh
    
    # Enable developer mode policies
    /usr/sbin/DevToolsSecurity -enable
    
    # Add a group to developer group
    /usr/sbin/dseditgroup -o edit -a <your_group_name> -t group _developer
    
    exit 0

And postuninstall_script to revert the changes:

    #!/bin/sh
    
    # Disable developer mode policies
    /usr/sbin/DevToolsSecurity -disable
    
    # Remove a group from developer group
    /usr/sbin/dseditgroup -o edit -d <your_group_name> -t group _developer
    
    exit 0

32.0.1.6 Xcode 4.3/4.3.1/4.3.2 for Lion

Xcode is now distributed as a self-contained Xcode.app via the Mac App Store (MAS) as well as Apple’s Developer Center. The applications are identical, though the MAS version will take a very long time to import to a DMG using munkiimport as it contains a high number of files and is very large. The version from Apple’s Developer Center is already a DMG, so it is recommended to use. This does require a developer account to access, but the free Safari developer program does provide access to Xcode. http://developer.apple.com/downloads

Xcode requires a !MobileDevice package to be installed on first launch, but we can install this easily with Munki. This can be done with a post-install script, but it is safer to import that package to your repo and set Xcode to require it. It is contained inside Xcode.app, at Xcode.app/Contents/Resources/Packages/MobileDevice.pkg

You may also want to download and import the Command Line tools and Auxiliary Tools for Xcode from the Developer site.

In order to properly remove the Command Line Xcode tools, you should be using version 0.8.2 of the Munki tools when importing the Command Line Xcode tools package.

32.0.1.7 Pre-Xcode 4.3

The receipts left on disk after installing versions of Xcode prior to 4.3 do not match the receipt info declared within the Xcode metapackage distribution file, so you will need to add an “installs” key to prevent Munki from attempting to reinstall Xcode repeatedly. You may also want to add minimum_os_version and/or maximum_os_version keys to prevent attempted installs on the wrong OS versions. Some examples:

32.0.1.8 Xcode 4.2.1 for Lion

        <key>installs</key>
        <array>
            <dict>
                <key>CFBundleIdentifier</key>
                <string>com.apple.dt.Xcode</string>
                <key>CFBundleName</key>
                <string>Xcode</string>
                <key>CFBundleShortVersionString</key>
                <string>4.2.1</string>
                <key>path</key>
                <string>/Developer/Applications/Xcode.app</string>
                <key>type</key>
                <string>application</string>
            </dict>
        </array>
        <key>minimum_os_version</key>
        <string>10.7.2</string>

32.0.1.9 Xcode 4.2 for Snow Leopard

        <key>installs</key>
        <array>
            <dict>
                <key>CFBundleIdentifier</key>
                <string>com.apple.dt.Xcode</string>
                <key>CFBundleName</key>
                <string>Xcode</string>
                <key>CFBundleShortVersionString</key>
                <string>4.2</string>
                <key>path</key>
                <string>/Developer/Applications/Xcode.app</string>
                <key>type</key>
                <string>application</string>
            </dict>
        </array>
            <key>maximum_os_version</key>
        <string>10.6.9</string>
        <key>minimum_os_version</key>
        <string>10.6.8</string>

32.0.1.10 Xcode 3.2.6

        <key>installs</key>
        <array>
            <dict>
                <key>CFBundleIdentifier</key>
                <string>com.apple.Xcode</string>
                <key>CFBundleName</key>
                <string>Xcode</string>
                <key>CFBundleShortVersionString</key>
                <string>3.2.6</string>
                <key>path</key>
                <string>/Developer/Applications/Xcode.app</string>
                <key>type</key>
                <string>application</string>
            </dict>
            </array>
        <key>maximum_os_version</key>
        <string>10.6.9</string>
        <key>minimum_os_version</key>
        <string>10.6.6</string>

32.0.2 Uninstalling Xcode (pre-App Store versions of Xcode)

Since the package receipt info for Xcode is not useful, it can’t be used for uninstalls, either. Fortunately, Apple has provided an uninstall script that Munki can use:

        <key>uninstall_method</key>
        <string>/Developer/Library/uninstall-devtools</string>

32.0.2.1 More XCode 4 for Lion notes

Now that Xcode 4 is a free download from the Mac App Store, I wanted to be able to use munki to distribute it (as an optional install) to Lion machines. Here’s what I did:

  1. “Purchased” and downloaded Xcode 4.2.1 from the Mac App Store.
  2. Control-clicked the “Install Xcode.app” and chose “Show Package Contents”.
  3. Navigated to the Resources directory, in which I found an Xcode.mpkg and a Packages subdirectory.
  4. Copied the Xcode.mpkg and a Packages subdirectory to a new directory named Xcode4.2.1.
  5. Used DiskUtility to make a disk image of the Xcode4.2.1 directory. (Be sure when making a disk image that you choose to make a read-only or compressed disk image. Read-write disk images will cause “Hash value integrity check” errors unless Munki’s PackageVerificationMode is set to ‘none’ or the installer_item_hash is removed from the pkginfo (neither change is recommended).
  6. Used munkiimport to import it into my munki repo.
  7. Changed minimum_os_version to <string>10.7.2</string>.
  8. Added an “installs” item for /Developer/Applications/Xcode.app as described above.
  9. Changed the uninstall_method to <string>/Developer/Library/uninstall-devtools</string> as described above.

    32.0.2.1 Introduction

32.0.3 Munki 3

  • Introduction
  • [[macOS Installer Application support]]
  • [[Authorized Restarts]]
  • [[Notification Center Support]]
  • [[Repo Plugins]]
  • [[Removal of Unused Software]]
  • Featured Items
  • [[Allowing Untrusted Packages]]
  • [[Upgrading to Munki 3]]
  • [[Munki 3.1 localization needs]]

32.0.4 Managed Software Center

  • Introduction
  • [[Munki Links]]
  • [[Product Icons|Product icons]]
  • [[Screenshots In Product Descriptions|Screenshots in Product Descriptions]]
  • [[Client Customization|Client customization]]
  • [[Custom Help Content|Custom Help content]]
  • Featured Items

32.0.5 Command-line Tools

  • [[makepkginfo]]
  • [[munkiimport]]
  • [[managedsoftwareupdate]]
  • [[makecatalogs]]
  • [[manifestutil]]

32.0.6 Munki configuration

  • [[Preferences]]
  • [[Managed Preferences Support In Munki]]
  • [[Apple Software Updates With Munki]]

32.0.7 Manifests

  • [[Manifests]]
  • [[Conditional Items]]

32.0.8 Catalogs

  • [[Using Munki Catalogs]]

32.0.9 Pkginfo

  • [[Pkginfo Files|Pkginfo Files]]
  • [[Supported Pkginfo Keys|Supported Pkginfo Keys]]
  • [[Pre And Postinstall Scripts|Pre and Postinstall Scripts]]
  • [[Munki And AutoRemove]]
  • [[Blocking Applications]]
  • [[ChoiceChangesXML]]
  • [[CopyFromDMG]]
  • [[Pkginfo For Apple Software Updates]]
  • [[Managing Configuration Profiles]]
  • [[How Munki Decides What Needs To Be Installed]]

32.0.10 Advanced configuration

  • Securing the Munki repo
  • Using SSL client certificates
  • [[Using Basic Authentication]]
  • Preflight And Postflight Scripts
  • Introduction
  • [[Dynamic Client Configurations Via Preflight Scripting]]
  • [[WPKG like Dynamic Manifests Without CGI]]
  • [[Report Broken Client]]
  • [[MSU Logging]]
  • [[Munki With Git]]
  • [[Bootstrapping With Munki]]
  • [[License Seat Tracking]]
  • [[LaunchD Jobs and Changing When Munki Runs]]
  • Web Request Middleware
  • [[Authorized Restarts]]
  • [[Repackaging]]
  • [[Creating Disk Images]]
  • Stupid Munki Tricks
  • Introduction
  • [[Managing Printers With Munki]]
  • [[Managing Admin Rights With Munki]]
  • [[Execute Munki With a LogoutHook]]

32.0.12 More

  • [[Troubleshooting]]
  • [[Professional Support]]
  • [[Known Issues and Workarounds]]
  • [[Building Munki packages]]
  • [[Removing Munki|Removing Munki]]
  • [[More Links And Tools|More Links and Tools]]
  • [[Munki Configuration Script|Munki Configuration Script]]

32.0.13 Product-specific notes

32.0.14 Legacy Documentation

32.0.15 Introduction

Munki 3 adds “native” support for using the startosinstall tool – included inside the macOS installer application since 10.11 – to install macOS upgrades.

This feature is new in Munki 3.

32.0.16 Background

Prior to the release of Munki 3, the supported method of performing OS upgrades was to use the createOSXinstallPkg toolset to create an installer package from an “Install macOS Foo.app” application. You’d then import the installer package and manage it like any other package.

10.12.4 dealt a serious blow to the createOSXinstallPkg toolset: Apple changes made it now impossible to include additional packages as part of the install. Additionally, Apple changed the location and functionality of brtool, a tool used to set up the macOS install boot on CoreStorage volumes. With some effort, basic functionality of createOSXinstallPkg is working again under 10.12.4 (and later), but it appears that the ability to add additional packages is lost forever due to new security measures by Apple. (10.13 changes further break createOSXinstallPkg and there is no plan to address these changes.)

In addition, if one examines the contents of the /macOS Install Data folder after a 10.12 createOSXinstallPkg package completes preparation for a macOS install, and compares that to the contents of the /macOS Install Data folder after startosinstall completes preparation for a macOS install, it’s clear that createOSXinstallPkg does not set things up the same way – that over time, Apple has changed details of the set up process, and createOSXinstallPkg has not kept pace.

Given the breakage and the pace of change, it seemed prudent to focus efforts on a mechanism that is at least somewhat-Apple supported, even if it provides less flexibility and functionality than createOSXinstallPkg did.

32.0.16.1 Importing a macOS installer

munkiimport, makepkginfo, and iconimporter now have support for macOS installers.

Use munkiimport /Applications/Install macOS Sierra.app to wrap the installer in a disk image and import it into your Munki repo. You may also import an existing diskimage containing a copy of “Install macOS Sierra.app”.

Add the item to a manifest as you would any other Munki item.

32.0.16.2 Avoiding Unsupported Hardware

Munki will gladly offer the OS install on hardware that is not capable of running that particular release, if you add the item to managed_installs or optional_installs. You can use logic like the one found here for Sierra to do a conditional item and prevent this from looping at the worst, or polluting logs with errors and warnings at the least. An alternative implementation is here: https://github.com/munki/munki-facts/blob/master/facts/sierra_upgrade_supported.py

32.0.16.3 Munki 3.1 changes

startosinstall OS upgrade pkginfo items can now contain an additional array of strings, which are added as additional options to the startosinstall binary. For example:

<key>additional_startosinstall_options</key>
<array>
    <string>--converttoapfs</string>
    <string>NO</string>
</array>

No guarantees that these additional options will actually work or be supported by Apple in future releases; testing is your responsibility, bugs are Apple’s.

32.0.17 Implementation notes

You don’t need to add installs items or receipts to the pkginfo item for an imported Install macOS Sierra.app. Munki knows how to tell if the target Mac already has the same major.minor (or a higher major.minor) version installed.

In the vein of https://github.com/munki/munki/wiki/How-Munki-Decides-What-Needs-To-Be-Installed – Munki simply checks the major.minor OS version. If your startosinstall item installs 10.12.4, any version of macOS 10.12 is enough to satisfy Munki. This prevents Munki from offering a 45-minute install of 10.12.4 to machines running 10.12-10.12.3 and “masking” a softwareupdate Delta/Combo Update to 10.12.4. (This also matches the behavior you would get when using a package built with createosxinstallpkg and this installs array: https://github.com/munki/munki/wiki/Installing-OS-X#sierra)

A macOS installer that is a pending update will be installed after all other items in managed_installs. It’s automatically considered an apple_item, so Apple software updates will not be checked for or installed in the same session.

As with other Munki items that require a restart after install, Managed Software Center will trigger a logout before starting the install session. All other pending managed_installs will be installed first; the macOS upgrade will be started last. If startosinstall completes successfully, it will trigger a reboot. Munki will exit after doing a subset of the actions it normally does at the end of a Munki run. Currently that includes running a postflight script (if one exists) with a special runtype of “startosinstall”.

Before the reboot, however, Munki will create the /Users/Shared/.com.googlecode.munki.checkandinstallatstartup file, which will cause Munki to enter “bootstrapping mode” after the OS upgrade is complete. See [[Bootstrapping With Munki]] for more detail on this subject.

32.0.17.1 Marking other items as update_for a macOS install

Nothing prevents you from defining other Munki items as ‘update_for’ a startosinstall item, but such items will not be installed during the same session in which the macOS upgrade is started; instead they will be re-evaluated (and possibly installed) during the “bootstrapping mode” after the OS upgrade is complete. (If your item that installs Sierra is conditionally offered only to machines running < 10.12, though, it will no longer be in managed_installs after the OS upgrade is complete, and “update_for” items will not be processed at all.)

32.0.17.2 Supported versions

Currently only Sierra installers are supported; startosinstall was added in El Capitan, but the syntax and behavior is different and testing showed that quite a lot of additional code would need to be written to attempt to get a acceptable experience and success rate with El Capitan installs. Using createosxinstallpkg will continue to be the recommendation for El Capitan and earlier OS installs.
High Sierra Beta installers have so far worked as expected; it’s likely the High Sierra release will work as well – Munki 3.1 or later will be recommended.

32.0.17.3 preinstall_script and postinstall_script

Preinstall and postinstall script support is present, but currently untested. Note that a postinstall_script will actually run after the macOS upgrade is set up, but before the OS is actually installed/upgraded. If you need a script to run after the the OS is upgraded, you’ll need to use “requires” to install the script as something that runs at boot (one time only perhaps) before you start the macOS update. The “outset” tool or a similar mechanism might be a good choice for this task.

32.0.18 More questions and answers

  • What OS versions are supported for running startosinstall?
  • Testing by Eric Holtam, Clayton Burlison and myself seems to indicate that we should be able to successfully update to 10.12.x from 10.8-10.11. See https://docs.google.com/spreadsheets/d/19PmHyriABFeJZ2NluIDPh9BTlwJYmy_fUAI5p4P2bb0/

  • Which “Install macOS/OS X” applications actually work with this implementation, especially at the loginwindow (with no active user session)?
  • Only the Sierra installer is currently supported. High Sierra is expected to work as well. Use the createOSXinstallPkg tool to create installer packages for older versions of OS X.
    Tool for making pkginfo files

32.0.19 Introduction

Well-crafted pkginfo files are the key to munki’s functionality. Creating these by hand is tedious and error-prone. The makepkginfo tool can help.

32.0.20 Details

Tool: makepkginfo

Creates a managed install pkginfo plist given an Installer item:
a .pkg, a .mpkg, a .mobileconfig profile, or a .dmg containing a .pkg or .mpkg at the root of the mounted disk image.

makepkginfo now also supports a few other dmg types:

  1. Drag-and-drop application dmgs
  2. Adobe CS4 Update installer dmgs
  3. DMGs containing Adobe CS4 Deployment Toolkit packages and install files
  4. (Adobe CS5/CS6/CC products are also supported, but generally must be repackaged with AAMEE or CCP. See [[Munki And Adobe CS5]], [[Munki And Adobe CS6]] and other wiki documentation for more info.)

You may also pass items that are installed by the package using the ‘-f’ flag.
These are added to the ‘installs’ key of the catalog item plist and are used when
processing the catalog to check if the package needs to be installed or
reinstalled.

You can leave off the installer item, and just pass “-f” items to build a list of items to add to an existing pkginfo file.

The generated plist is printed to STDOUT.

Usage: makepkginfo [/path/to/package_or_dmg] [-f /path/to/item/it/installs ...]

A simple example:

> ./makepkginfo /path/to/ServerAdminToold1055.dmg
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>description</key>
    <string></string>
    <key>installer_item_location</key>
    <string>ServerAdminToold1055.dmg</string>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>ServerAdministrationSoftware</string>
    <key>receipts</key>
    <array>
        <dict>
            <key>packageid</key>
            <string>com.apple.pkg.ServerAdminTools</string>
            <key>version</key>
            <string>10.5.3.0</string>
        </dict>
        <dict>
            <key>packageid</key>
            <string>com.apple.pkg.ServerSetup</string>
            <key>version</key>
            <string>10.5.3.0</string>
        </dict>
    </array>
    <key>version</key>
    <string>10.5.3.0</string>
</dict>
</plist>

Another example:

> makepkginfo --file /Applications/iWork\ \'08/Keynote.app --file /Applications/iWork\ \'08/Pages.app --file /Applications/iWork\ \'08/Numbers.app /Volumes/iWork08/iWork08.pkg
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>description</key>
    <string></string>
    <key>installer_item_location</key>
    <string>iWork08.pkg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.iWork.Keynote</string>
            <key>CFBundleName</key>
            <string>Keynote</string>
            <key>CFBundleShortVersionString</key>
            <string>4.0.3</string>
            <key>type</key>
            <string>application</string>
        </dict>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.iWork.Pages</string>
            <key>CFBundleName</key>
            <string>Pages</string>
            <key>CFBundleShortVersionString</key>
            <string>3.0.2</string>
            <key>type</key>
            <string>application</string>
        </dict>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.iWork.Numbers</string>
            <key>CFBundleShortVersionString</key>
            <string>1.0.2</string>
            <key>type</key>
            <string>application</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>iWork</string>
    <key>receipts</key>
    <array>
        <dict>
            <key>packageid</key>
            <string>com.apple.pkg.iWork08</string>
            <key>version</key>
            <string>3.0.0.1352</string>
        </dict>
    </array>
    <key>version</key>
    <string>08</string>
</dict>
</plist>

Note that in both of these examples the required key installer_item_location will almost certainly be wrong unless you store all of your installer items at the root of the pkgs directory in the repo.

Here’s makepkginfo run against a Firefox dmg:

> makepkginfo /Volumes/repo/pkgs/apps/Firefox\ 3.5.3.dmg
<?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>catalogs</key>
    <array>
        <string>testing</string>
    </array>
    <key>installer_item_location</key>
    <string>apps/Firefox 3.5.3.dmg</string>
    <key>installer_item_size</key>
    <integer>18002</integer>
    <key>installer_type</key>
    <string>appdmg</string>
    <key>installs</key>
    <array>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>org.mozilla.firefox</string>
            <key>CFBundleName</key>
            <string>Firefox</string>
            <key>CFBundleShortVersionString</key>
            <string>3.5.3</string>
            <key>path</key>
            <string>/Applications/Firefox.app</string>
            <key>type</key>
            <string>application</string>
        </dict>
    </array>
    <key>minimum_os_version</key>
    <string>10.4.0</string>
    <key>name</key>
    <string>Firefox</string>
    <key>uninstall_method</key>
    <string>remove_app</string>
    <key>uninstallable</key>
    <true/>
    <key>version</key>
    <string>3.5.3.0.0</string>
</dict>
</plist>

32.0.21 Options

makepkginfo supports a lot of options:

<table>
<tr><td>-h</td><td>–help</td><td>Show a help message and exit</td></tr>
<tr><td>-f FILE</td><td>–file=FILE</td><td>Path to a filesystem item installed by this package, typically an application. This generates an “installs” item for the pkginfo, an item munki can use to determine if this software has been installed. Can be specified multiple times.</td></tr>
<tr><td>-p PKGNAME</td><td>–pkgname=PKGNAME</td><td>Optional flag.<br>-If the installer item is a disk image containing multiple packages, or the package to be installed is not at the root of the mounted disk image, PKGNAME is a relative path from the root of the mounted disk image to the specific package to be installed.<br>-If the installer item is a disk image containing an Adobe CS4 Deployment Toolkit installation, PKGNAME is the name of an Adobe CS4 Deployment Toolkit installer package folder at the top level of the mounted dmg. If this flag is missing, the AdobeUber* files should be at the top level of the mounted dmg.</td></tr>
<tr><td>-i ITEM<br>-a ITEM</td><td>–itemname=ITEM<br>–appname=ITEM</td><td>Optional flag.<br>-If the installer item is a disk image with a drag-and-drop item, ITEMNAME is the name or relative path of the item to be installed.<br>Useful if there is more than one item at the root of the dmg.</td></tr>
<tr><td></td><td>–displayname=DISPLAYNAME</td><td>Optional flag.<br>String display name of the package. <br>Note: overrides any display_name in the package itself.</td></tr>
<tr><td></td><td>–description=DESCRIPTION</td><td>Optional flag.<br>String description of the package.<br>Note: overrides any description in the package itself</td></tr>
<tr><td>-d DESTINATIONPATH</td><td>–destinationpath=DESTINATIONPATH</td><td>Optional flag.<br>If the installer item is a disk image with a drag-and-drop item, this is the path to which the item should be copied. Defaults to “/Applications”.</td></tr>
<tr><td>-u UNINSTALLERDMG</td><td>–uninstallerdmg=UNINSTALLERDMG</td><td>Optional flag.<br>If the installer item is a disk image containing an Adobe CS4 Deployment Toolkit installation package or Adobe CS3 deployment package, UNINSTALLERDMG is a path to a disk image containing an AdobeUberUninstaller for this item.</td></tr>
<tr><td></td><td>–postinstall_script=SCRIPT_PATH</td><td>Optional flag.<br>Path to an optional postinstall script to be run after installation of the item. The script will be read and embedded into the pkginfo.</td></tr>
<tr><td></td><td>–preinstall_script=SCRIPT_PATH</td><td>Optional flag.<br>Path to an optional preinstall script to be run before installation of the item. The script will be read and embedded into the pkginfo.</td></tr>
<tr><td></td><td>–postuninstall_script=SCRIPT_PATH</td><td>Optional flag.<br>Path to an optional postuninstall script to be run after removal of the item. The script will be read and embedded into the pkginfo.</td></tr>
<tr><td></td><td>–preuninstall_script=SCRIPT_PATH</td><td>Optional flag.<br>Path to an optional preuninstall script to be run before removal of the item. The script will be read and embedded into the pkginfo.</td></tr>
<tr><td></td><td>–uninstall_script=SCRIPT_PATH</td><td>Optional flag.<br> Path to an uninstall script to be run in order to uninstall this item. The script will be read and embedded into the pkginfo.</td></tr>
<tr><td>-c CATALOG</td><td>–catalog=CATALOG</td><td>Optional flag.<br>Specifies in which catalog the item should appear. The default is ‘testing’. Can be specified multiple times to add the item to multiple catalogs.</td></tr>
<tr><td>-o USER</td><td>–owner=USER</td><td>Optional flag.<br>If the installer item is a disk image used with the copy_from_dmg installer type, this sets the owner of the item specified by the –item flag. The owner may be either a UID or a symbolic name. The owner will be set recursively on the item.</td></tr>
<tr><td>-g GROUP</td><td>–group=GROUP</td><td>Optional flag.<br>If the installer item is a disk image used with the copy_from_dmg installer type, this sets the group of the item specified by the –item flag. The group may be either a GID or a symbolic name. The group will be set recursively on the item.</td></tr>
<tr><td>-m MODE</td><td>–mode=MODE</td><td>Optional flag.<br>If the installer item is a disk used with the copy_from_dmg installer type, this sets the mode of the item specified by the –item flag. The specified mode must be in symbolic form. See the manpage for chmod(1) for more information. The mode is applied recursively.</td></tr>
<tr><td>-V</td><td>–version</td><td>Print the version of the munki tools and exit.</td></tr>
</table>
Info on managedsoftwareupdate tool

32.0.22 Introduction

managedsoftwareupdate is the main client tool for Munki. It runs automatically approximately every hour, or in response to events from Managed Software Center.app, but can also be manually invoked.

32.0.23 Details

Usage: /usr/local/munki/managedsoftwareupdate [options]

This is the main client tool. It functions in a similar manner to Apple’s softwareupdate command-line tool.

32.0.23.1 Options

short the long command    description
-h –help Show a help message and exit
-a –auto Used by launchd LaunchAgent for scheduled runs. No user feedback or intervention. Not tested or supported with other options.
-l –logoutinstall Used by launchd LaunchAgent when running at the loginwindow.
–installwithnologout Used by Managed Software Update.app when user triggers an install without logging out.
–manualcheck Used by launchd LaunchAgent when checking manually.
-m –munkistatusoutput Provides GUI progress feedback when installing.
–id=ID Alternate identifier for manifest retrieval
-q –quiet Quiet mode. Logs messages, but nothing to stdout. –verbose is ignored if –quiet is used.
-v –verbose More verbose output. May be specified multiple times.
–checkonly Check for updates, but don’t install them. This is the default behavior.
–installonly Skip checking and install any pending updates.
–applesuspkgsonly When checking for updates, check only for Apple SUS packages, skip Munki packages.
–munkipkgsonly When checking for updates, check only for Munki packages, skip Apple SUS.
-V –version Print the version of the munki tools and exit.

32.0.23.2 Commonly used options

  • --installonly Causes managedsoftwareupdate to install items it has previously downloaded
  • --version Returns managedsoftwareupdate’s version information

32.0.23.3 Operation overview

Client asks for a main manifest. It’s retrieved and stored locally. Main manifest contains some metadata and a list of managed installs. On the client, it’s named client_manifest.plist in Munki 2 and earlier, though on the server it may have any name. Under Munki 3, the local copy of the main manifest is saved under the same name it has on the server (or technically the resource name in the GET request).

managedsoftwareupdate requests a manifest via one of three values:

1) if you pass –id=arbitrarystring at the command line, it uses ‘arbitrarystring’ as the request:

http://webserver/repo/manifests/**arbitrarystring**

2) If no –id option is passed, it looks for a ClientIdentifier value in /Library/Preferences/ManagedInstalls.plist and uses that.

3) If no ClientIdentifier is available, it uses the fully-qualified hostname of the machine:

http://webserver/repo/manifests/**hostname.mycompany.com**

If that fails, it tries the short hostname:

http://webserver/repo/manifests/**hostname**

If that fails, it tries the machine serial number:

http://webserver/repo/manifests/**AABBCCDDEEFF**

If that fails, it tries to retrieve a manifest named “site_default”:

http://webserver/repo/manifests/**site_default**

Note that if the ManifestURL takes the form of a CGI invocation (http://webserver/cgi-bin/getmanifest?), the final URLs look like:

http://webserver/cgi-bin/getmanifest?arbitrarystring

The CGI approach opens the possibility for pattern matching and more logic in the client-to-catalog mapping. You can do server-side logic to dynamically return the appropriate manifest for a given client.

Next, the client asks for more detail on each managed install.

As we get more detail on each managed install, we may discover some dependancies, so we request more info on these as well.

We then check the items to see if they are already installed.

For items that are not installed, or have an older version, we download installer items and put them in a staging folder.

(any items previously staged that have no corresponding catalog item are removed from the staging folder - this covers the case where an item is erroneously added to a manifest and then removed before it is actually installed)
Using the dependency info and the catalog items, we build a list of items to be installed and their order. (InstallInfo.plist)

Unless the --auto option is passed, after checking for and downloading updates, managedsoftwareupdate will quit. You’ll need to run it a second time with --installonly to get it to install the updates. This is a safety measure to make it less likely you’ll accidently install something that requires a restart underneath a logged-in user.
Documentation for manifestutil

32.0.24 Introduction

/usr/local/munki/manifestutil can help you create and edit client manifests. It supports a variety of options, but its biggest strength is when run with no options. It then runs as an interactive shell with tab-completion for the subcommands, options, and even package names, catalog names, and section names:

32.0.25 Details

32.0.25.1 Configuration

manifestutil shares configuration information with munkiimport, so if you’ve configured munkiimport you should not need to configure manifestutil in order to use it. If you haven’t configured either munkiimport or manifestutil:

% /usr/local/munki/manifestutil --configure
Path to munki repo (example: /Volumes/repo) [Repo fileshare URL (example: afp://munki.pretendco.com/repo) [afp://munki/repo](/Volumes/repo]:):

You need to provide the local path to the munki repo, and if the repo lives on a file share that must be mounted locally, the URL for that share (afp or smb).

32.0.26 Usage

/usr/local/munki/manifestutil 
Entering interactive mode... (type "help" for commands)
help
Available sub-commands:
    add-catalog
    add-included-manifest
    add-pkg
    configure
    copy-manifest
    display-manifest
    exit
    find
    help
    list-catalog-items
    list-catalogs
    list-manifests
    new-manifest
    remove-catalog
    remove-included-manifest
    remove-pkg
    version
add-pkg
Usage: add-pkg PKGNAME --manifest MANIFESTNAME [--section SECTIONNAME]
add-pkg AdobePhotoshopCS5 --manifest allure --section managed_uninstalls

In the above command I typed add-p[AdobeP[tab](tab]) --m[all[tab](tab]) --s[managed_un[tab](tab])

The tab-completion is very useful when adding package names to a manifest – you can use tab-completion to get a list of names:

remove-pkg Adobe[tab][tab]
AdobeAfterEffectsCS5       AdobeCS4DesignStandard     AdobeCS4MasterCollection   AdobeFlashProCS5.5         
AdobeInDesignCS5           AdobeLightroom3            AdobeMasterCollectionCS5   AdobeProductionPremiumCS5  
AdobeReaderX               AdobePhotoshopCS5          

and manifests:

remove-pkg AdobePhotoshopCS5 --manifest al[tab][tab]
aleta        allure       allure-test  alturas 

and sections:

remove-pkg AdobePhotoshopCS5 --manifest allure --section [tab][tab]
managed_installs    managed_uninstalls  managed_updates     optional_installs

Which helped me write this command:

remove-pkg AdobePhotoshopCS5 --manifest allure --section managed_uninstalls
Removed AdobePhotoshopCS5 from section managed_uninstalls of manifest allure.

The find command can find every manifest that has a certain package, and you can optionally restrict the search to a specific section:

find AdobePhotoshopCS5 --section managed_installs
agree: AdobePhotoshopCS5
aleta: AdobePhotoshopCS5
[snip]
voodoo: AdobePhotoshopCS5
willie: AdobePhotoshopCS5
zircon: AdobePhotoshopCS5
groups/TalDevL122Lab: AdobePhotoshopCS5
127 items found.

find AdobePhotoshopCS5 --section managed_uninstalls
greenbo: AdobePhotoshopCS5
1 items found.
display-manifest greenbo
catalogs:
    production
included_manifests:
    groups/DisneyStandardConfiguration
managed_installs:
    PhotoshopCS4
    ExpressionMedia2
    FinalDraft8
    WacomTablet
managed_uninstalls:
    AdobePhotoshopCS5

Tool for importing packages into your Munki repository

32.0.27 Introduction

munkiimport is a command-line-based assistant for importing pkgs, disk images and apps into your Munki repo. It creates a pkginfo file for the installer item, wraps the pkg or app into a disk image if needed, and uploads the disk image or flat package to the repo, optionally under a subdirectory of your choosing. If the pkg/dmg upload is successful, munkiimport then uploads the pkginfo and opens it in your preferred editor.

32.0.28 Details

Basic usage:

Run munkiimport --configure to tell the utility about your repo and preferred editor:

munkiimport --configure
Path to munki repo (example: /Volumes/repo): [Munki 3 no longer prompts for this]
Repo URL (example: afp://munki.pretendco.com/repo): [This is normally a afp: or smb: URL for a repo on a remote server, or a file: URL for a local file path]
pkginfo extension (Example: .plist): 
pkginfo editor (examples: /usr/bin/vi or TextMate.app):

Now import a pkg, or disk image:

munkiimport /Users/gneagle/Downloads/tl-3.1.1-client-osx.dmg
     Item name [ThinLinc Client]: 
  Display name []: 
   Description []: Remote workstation client.  
       Version [3.1.1.0.0]: 
      Catalogs [testing]: production
    
     Item name: ThinLinc Client
  Display name: 
   Description: Remote workstation client.
       Version: 3.1.1.0.0
      Catalogs: production
    
Import this item? [y/n] y
Upload installer item to subdirectory path [None]: apps
Copying tl-3.1.1-client-osx.dmg to /Volumes/repo/pkgs/apps/tl-3.1.1-client-osx.dmg...
Saving pkginfo to /Volumes/repo/pkgsinfo/apps/ThinLinc Client-3.1.1.0.0...

…and then /Volumes/repo/pkgsinfo/apps/ThinLinc Client-3.1.1.0.0 opens in TextMate for additional editing. Once you’re done with any editing, the command line shows:

Rebuild catalogs? [y/n] 

Most of the time you’ll answer ‘y’ to rebuild the catalogs after you’ve made changes. You might answer ‘n’ if you are going to be importing more items and want to wait until all new items are imported before rebuilding the catalogs.

32.0.29 Additional notes

By default the pkginfo file is opened with the defined pkginfo editor. If you wish to avoid this you can set the pkginfo editor to an empty string (or delete the preference from com.googlecode.munki.munkiimport). If this preference is empty or undefined the pkginfo is not opened in an editor.

Preferences set by --configure are stored in the OS X preferences domain “com.googlecode.munki.munkiimport”, which is has file storage for the current user account in ~/Library/Preferences/com.googlecode.munki.munkiimport.plist

© https://gittobook.org, 2018. Unauthorized use and/or duplication of this material without express and written permission from this author and/or owner is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to this site, with appropriate and specific direction to the original content.
Table