This blog has moved…

Hey all, just a quick post to urge you to head on over to I have moved this blog to GitHub and am using Jekyll and Disqus to automate the blog-like tools.

I transferred many of the blog posts from this blog to that one, so if you have comments to make, and find the post on the new blog, please add your comment there rather than here ūüôā

Munki, Git and Munki-Do

Munki-Do inherited from its father MunkiWebAdmin by Greg Neagle et al., the ability to commit to a Git-initiated Munki Repo when making changes to Munki manifests.

Over the past few days I’ve been looking at how Git can interact with Munki. Using Git with Munki is covered in the Munki Wiki. It describes how to set up a git repository on a server with which you have CLI access.

In my tests, I’ve been using a private repository on Bitbucket. I also started with an existing Munki repo, rather than setting up a new one.

Setting up git on an existing Munki Repo

Setting up the test Munki repo with Git was done as follows:

  • An empty repo was set up on
  • The existing munki_repo folder was initialised for git using the commands: cd /path/to/munki_repo; git init
  • The pkgs folder was set to be ignored, as I didn’t want the large pkg/dmg/app files to be uploaded to the repo. This was done by editing /path/to/munki_repo/.gitignore and simply adding the line pkgs to the file.
  • Then, sync the repo to the server:

$ git add .
$ git commit -m "Initial import"
$ git remote add origin
$ git push --set-upstream origin master

Munki-with-Git challenges

Version control is an essential tool in any Mac Administrator’s workflow. However, using Git with Munki has challenges due to the munki repository containing potentially very large packages, unsuitable for free cloud Git repositories such as Bitbucket, and challenging for paid private repositories on Github or elsewhere due to bandwidth issues. Even using your local organisation’s Git service could have bandwidth issues.

A solution such as Git Fat could help with these issues, as the large files are dealt with separately. Alistair Banks describes an example Git Fat setup here. Git-LFS is another solution that could help. I intend to test these out and report in a future post.

Configuring Munki-Do for Git

I have extended the functionality of Munki-Do so that it can now update Git repos when changes are made to pkginfo files, and therefore catalogs. In Munki-Do, Git is enabled by setting the path to the git command on the system hosting Munki-Do, in In my case, I’m running Munki-Do in a Docker Container, and the path is as follows:

GIT_PATH = '/usr/bin/git'

Bitbucket doesn’t respond to --author flags in git commit commands, so Munki-Do has been recoded to set the author variables based on the current user using git config and git config commands.

Since the Bitbucket repository is a private one, to enable automated interaction with the Bitbucket server, an ssh key needs to be generated on Munki-Do’s host, and the public key imported to the Bitbucket repo. The process for doing this is described here.

My test Munki-Do host is a Docker Container, so I imported my SSH key from my host Mac into the Docker Container using commands in the Dockerfile:

ADD id_rsa /root/.ssh/id_rsa
RUN touch /root/.ssh/known_hosts
RUN chown root: /root/.ssh/id_rsa && chmod 600 /root/.ssh/id_rsa
RUN ssh-keyscan >> /root/.ssh/known_hosts

Note that id_rsa must be first copied from ~/.ssh/ to the same folder as the Dockerfile.

In my testing, sometimes the above ssh-keyscan command is not successful during docker build, in which case your git commits will fail. Take notice of the output of the build to ensure success! You can run the command again in a bash shell in the container if it fails during build.

Munki-Do (beta): a web tool for managing Munki packages

Disclaimer: Munki-Do is still a very much work in progress, so shouldn’t be used in production. I welcome the raising of issues, and pull requests.

Screen Shot 2015-09-30 at 16.37.22

Munki-Do (as in “munki see, munki do”) enables the manipulation of Munki packages via the web. Munki-Do is based on¬†MunkiWebAdmin (v1) from Greg Neagle,¬†and was forked from Steve Kueng’s own forked version¬†( – this version utilises a more recent version of Django, and has significant UI changes in comparison with the original MunkiWebAdmin.

Some existing functionality from MunkiWebAdmin has been retained:

  1. Manifests: create/delete manifests, and manage the contents of manifests.
  2. Catalogs: view the contents of catalogs, view pkginfo file contents in tabular form.

New functionality has been added:

  1. Add multiple packages to a new or existing catalog
  2. Remove multiple packages from a catalog
  3. Move multiple packages to a new or existing catalog (i.e. replace existing catalog entry with another one, e.g. batch move a set of packages into the ‘production’ catalog)
  4. Delete packages and their associated pkginfo files

The remaining functionality of the original MunkiWebAdmin has been removed from Munki-Do, such as reporting and licensing tools, as there are other products that can do this better. I recommend:

The function to manipulate pkginfo files utilises munkitools (specifically, the makecatalogs command). This has been tested on an Ubuntu 14.04 VM, but you will need to ensure that your nginx user has write permissions to your munki repo. Use of group permissions is recommended.

The code which enables movement of packages between catalogs is a derivation of code from Munki-Trello by Graham Gilbert:

A Docker container for Munki-Do is available here:

I’ve also made a Docker container for Steve Kueng’s fork of MunkiWebAdmin, available here:


Greg Neagle¬†announced at MacSysAdmins this week¬†that he is working on MunkiWebAdmin2, which will allow full editing of pkginfo files including the catalog key. He also announced that MunkiWebAdmin2 will drop licensing and reporting tools, as with Munki-Do. I decided to put Munki-Do in production anyway, since I’d been working on it for a while, and as it may still provide the additional benefit of bulk changes to catalogs, and the ability to delete packages and pkginfo files to keep your repository from becoming too large and unwieldy.

I welcome all feedback on whether this could become a useful tool in your workflow. I’ll revisit the tool once MunkiWebAdmin2 is released.

A “Do Not Disturb” application for Munki

UPDATE: I’ve tweaked this app based on the idea of¬†Arjen van Bochoven¬†in his comment

A Mac user complained that Managed Software Center popped up in the middle of a conference presentation. I started looking into how to suppress notifications.

do-not-disturbAs a quick fix, I created an AppleScript application which suppresses notifications for 24 hours, utilising the SuppressUserNotification key in /Library/Preferences/ManagedInstalls.plist.

The application sets the key to TRUE, and runs a preflight script every time Munki runs on a client to check whether 24 hours have passed or not, after which it will reset the key back to FALSE.

The application

If you use MunkiReport-PHP and/or Sal clients in your organisation, or else have no reporting tools, then you can download my pre-made package for distribution:

If you use MunkiWebAdmin or some other reporting tool which uses an incompatible preflight script, then follow the instructions for compiling it yourself, here:

(See also my earlier post on getting MunkiWebAdmin to work with MunkiReport-PHP and/or Sal).

Screen Shot 2015-07-04 at 00.46.39

Importing into Munki

Now import to Munki and place in the manifest of the people you wish to have access. The uninstall method needs changing to ensure proper removal:


You could permanently disable notifications, but that would mean users never become aware of updates, so some applications that require intervention such as closing blocking applications could get somewhat out of date.

There is interest in the use of Apple’s Notification Centre for Managed Software Updates, but this is not yet considered reliable. If it becomes suitable, then Apple’s built in Do Not Disturb feature could be utilised.

I’ll update this post if/when better solutions emerge.

Importing Matlab into Munki

Matlab is a cross-platform commercial programming tool. Its use is licensed, either with a personal license code or through a license server. It is made available as an ISO from the Mathworks website by authorised accounts. A silent installation method is detailed here.

Previously I had installed Matlab on a Mac, and then imported the resulting App into Munki. For R2015a, I’ve written up the way I imported Matlab into Munki without having to install Matlab first.

See for full details.

This method involves packaging the installer ISO together with the license and configuration files into a DMG, and then using a postinstall_script in the Munki pkginfo file to mount the ISO and run the silent installer script.


An important part of the pkginfo file is that Matlab R2015a should not appear as an update for previous versions of Matlab. Each version can coexist on Macs, and users may wish to have multiple versions on their computer. All versions have the same CFBundleIdentifier, so to avoid this making the newer version appear to be an update of the older, the minimum_update_version key is used:


It should be noted that you need to have a different Name for each version of Matlab if you want them all to be separately available on the Managed Software Center, e.g. Matlab_R2014a, Matlab_R2015a etc.

“Connect to Server” favourites across devices using Safari bookmarks

I made a comment on the MacAdmins Slack #general board yesterday about my wish that the favourites list in the Go > “Connect to Server” list would share between devices using iCloud. This led scriptingosx to helpfully reply with a simple way of achieving this using Internet Shortcuts.

I stumbled across another way of doing this by not reading the above blog properly. I decided to use Safari bookmarks rather than desktop shortcuts. These are automatically shared with iCloud as long as you tick the box for Safari sharing in your iCloud System Preferences.

First, it would make sense to create a bookmark folder to house your favourite shortcuts.

In Safari, click on Bookmarks > Add Bookmark folder.

Screen Shot 2015-06-26 at 23.44.21

Then go to Bookmarks > Edit Bookmarks, and drag¬†the new folder to move it if required (I put all my favourites in the “Favourites” folder as I use the Favourites bar).

Now, open a new tab and go anywhere in the internet (it doesn’t matter where) and press Ctrl-D to add a bookmark.

Select the new folder you just created and enter the Server URI address you wish to bookmark. As you’re likely to want to use these addresses on multiple computers, it may be worth adding the username to the field. Take a copy of the address with Ctrl-A Ctrl-C, as you’ll need it in the next step.

Screen Shot 2015-06-26 at 23.51.17

Alternatively, you can just give the shortcut a descriptive name if you prefer. You’ll be adding the server address below anyway.

Now, go back to the Edit Bookmarks tab, and select your entry.

Screen Shot 2015-06-26 at 23.54.07

Double click on the URL address, and paste in your server URI address, replacing whatever you bookmarked.

Screen Shot 2015-06-26 at 23.54.19

That’s it. Now you have a shortcut to your server in your Safari favourites, which are accessible from all your iCloud connected devices. (Sorry, most¬†links won’t actually work on your iOS devices though!).

Screen Shot 2015-06-27 at 00.01.09

As pointed out on the scriptingosx blog, these addresses can be any valid URI address format, such as ftp, ssh, vnc, smb, and afp addresses, and Microsoft Remote Desktop rdp addresses using the format described in this Microsoft Technet article, e.g.


RDP¬†links do work on your iOS device, as long as you have the Microsoft Remote Desktop app installed (although the domain doesn’t pass through, despite the Technet article stating that it is compatible with iOS).

Munki-Enroll tweaked: Leverage DeployStudio’s “Computer Information” fields to customise Munki builds

Munki-Enroll is a useful tool to use when installing the Munki tools on Mac clients. It enables the automated creation of unique client manifests, which makes it easy to change the group manifests of a client remotely at any time using tools like manifestutil, MunkiAdmin or MunkiWebAdmin, utilising the included_manifest key in Munki manifests.

I have tweaked Munki-Enroll in order to leverage a feature of DeployStudio called Computer Information fields. These are four text fields available in the Hostname workflow page.

Screen Shot 2015-06-13 at 21.33.32

The contents of these fields are actually written to a preference file on the host computer at /Library/Preferences/, with key names Text1, Text2, Text3, Text4. If you are using Imagr instead of DeployStudio, you could easily script the use of these fields with commands such as:

sudo defaults write /Library/Preferences/ Text1 "Some text"

I use these fields to determine manifest enrolment using Munki-Enroll. This allows me to have only two DeployStudio workflows for all computers: one for new, out-of-box Macs which don’t require a rebuild, and one for rebuilding Macs. All other imaging variations are determined by Munki manifests. My DeployStudio workflows include installing the MunkiTools package, and then a script which reads the contents of the Computer Information fields and posts them to Munki-Enroll using curl:

COMPFIELD1=`defaults read /Library/Preferences/ Text1`
COMPFIELD2=`defaults read /Library/Preferences/ Text2`
COMPFIELD3=`defaults read /Library/Preferences/ Text3`
COMPFIELD4=`defaults read /Library/Preferences/ Text4`

One could just write the manifest names one wished to include in the client manifest directly into these fields, and pass them to munki-enroll. In my case, I wished to use shortcuts to make inputting quicker, so I added some processing to the script so interpret shortcuts (COMPFIELD1-4) and output manifest names (IDENTIFIER1-4):

Field Shortcut Munki manifest Function
#1 empty
_cg_za – _cg_zf
Default package set for Regular Users
Zone (area) specific packages, including local admin user creation
Zone D Student Laptop build (Open Access)
#2 empty
Default package set (if #1 is set to ZA-ZF)
Join to Active Directory (desktop build)
Join to Active Directory and add managed wifi profile (laptop build)
“Light touch” all-optional build
#3 empty

Do not encrypt
Encrypt the Mac using Crypt

I’m not using the fourth Computer Information field at this time. Of course, your organisation’s manifests are very unlikely to be the same, but I hope this gives you an idea of the flexibility that can be gained using the Computer Information fields with Munki-Enroll. I also use the contents of Computer Information field 1 in my Munki AD-binding package to determine the Active Directory Organisational Unit.

The manifests are then passed to the Munki-Enroll web page using a curl command:

/usr/bin/curl --max-time 5 --data \
"hostname=$LOCALHOSTNAME&identifier1=$IDENTIFIER1&identifier2=$IDENTIFIER2&identifier3=$IDENTIFIER3" \

Note that this is a POST command – a change from the default munki-enroll which uses GET.

The Munki-Enroll script has been tweaked to accept each identifier and add them as included_manifests to the client manifest:

    // Add parent manifest to included_manifests to achieve waterfall effect
    $dict->add( 'included_manifests', $array = new CFArray() );
    if ( $identifier1 != "" )
            $array->add( new CFString( $identifier1 ) );
    if ( $identifier2 != "" )
            $array->add( new CFString( $identifier2 ) );
    if ( $identifier3 != "" )
            $array->add( new CFString( $identifier3 ) );
    if ( $identifier4 != "" )
            $array->add( new CFString( $identifier4 ) );

Take a look at my tweaked version of Munki-Enroll here:

The full enroll.php and scripts:

Microsoft Office 2016 Preview and OneDrive for Business Beta don’t play together, yet

As a Mac SysAdmin in a dominantly Microsoft leaning organisation, I’m led to test new MS offerings with a view to rolling them out to Mac users once they reach their production stage. Sometimes, as in the case of OneDrive for Business, the need to use it is so¬†great that we have to offer to deploy the Beta version.

However, there appears to be a problem if you have both Office for Mac 2016 Preview and OneDrive for Business (Beta) installed. Every time you start your computer, or restart OneDrive for Business (Beta), an alert is displayed:

Screen Shot 2015-05-20 at 09.45.18

Pressing “Yes” opens “Microsoft Upload Centre” – not very informative. Opening the Microsoft Upload Centre Preferences and clicking “Delete Files” to empty the Office Document Cache apparently solved the problem for some, but not for me.

The official word from Microsoft came in the following thread of the Office365 community forum:

  • Close OneDrive for Business Mac (Beta)
  • Open a terminal window and delete the¬†OfficeFileCache as follows:
$ rm -rf ~/Library/Group Containers/UBF8T346G9.Office/Microsoft/AppData/Microsoft/Office/15.0/OfficeFileCache
  • Reopen OneDrive for Business Mac (Beta)

Microsoft stated that this would need to be done everytime the OneDrive for Business process is started. Their alternative is “Choose to install either Office 2016 Mac Preview OR OneDrive for Business Mac Preview on your system.” So I guess these Beta programs are not ready to play with each other, yet.

Docker: Use Cases presentation – 19/3/2015 London Apple Admins @ ThoughtWorks London

Back on 19th March 2015 I gave a short informal presentation at the second London Apple Admins meeting at ThoughtWorks London, about how I’ve been using Docker to setup some Mac administration tools, with the examples of Crypt, Munki-Trello and Munki-enroll. Here’s my segment:

The excellent hosts Ben Toms (@macmuleblog), Steve Quirke (@Steve2CV) and Graham Gilbert (@grahamgilbert) also gave presentations about Bushel, Docker and Sal respectively.

A test Docker-BSDPy environment

Some Mac Admins have recently blogged about testing BSDPy using Docker:

I decided to try it out in a setup that suited me. Here’s how it went.

What is BSDPy?

Put simply, BSDPy is an alternative to Apple’s NetBoot/NetInstall. The premise is to¬†provide a NetBoot/NetInstall service from a Linux host, removing another necessity for an OS X Server. Since Apple stopped providing server-grade hardware, this has been on Mac Admins’ agendas.

The posts above details all the reasons for trying this. This post is not intended to replace those posts, simply to document the set up I used to get this working.


My set up is a MacBook Air, with 8GB RAM, and the following programs installed:

  • VirtualBox
  • VMWare Fusion¬†(version 6). Version 7 will work. Note this isn’t a free program, but is required to test NetBooting an OS X VM. If you have a spare physical Mac on your network, you can use this instead.
  • DeployStudio
  • Vagrant
  • TextWrangler with Command Line Tools – this enables the edit command. You can substitute nano or vi or another editor.

Side note: I use AutoPkg to install TextWrangler, VirtualBox and Vagrant.

1. Setup VMWare Fusion

My setup was based on instructions on¬†Der Flounder’s blog:¬†

  • Open VMWare Fusion, click on File > New
  • Drag “Install OS X” (you already got this from the App Store, right?) into the “Install from Disk or Image” window
  • Allow the standard setup for OS X 10.10, but press “Customise” before launching.
  • In the “Startup Disk” pane, set the VM to boot to the “Network Adapter NAT”.
  • Leave VMWare Fusion open (but don’t start the VM) while you perform the remaining tasks – you need the virtual network interface to be active.

2. Setup Vagrant

I used a CentOS VM to better emulate my shop’s configuration.

If you wish, you can just clone the Vagrantfile and shown below using git, and move on to Step 4:

$ mkdir -p ~/vagrant/docker-bsdpy
$ git clone ~/vagrant/docker-bsdpy

Otherwise, carry on reading to create the files yourself:

$ mkdir -p ~/vagrant/docker-bsdpy/nbi
$ cd ~/vagrant/docker-bsdpy
$ vagrant init chef/centos-7.0
$ edit Vagrantfile

Vagrantfile should have the following contents:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config| = "chef/centos-7.0" "public_network"
  config.vm.synced_folder '.', '/vagrant', disabled: true
  config.vm.synced_folder '.', '/usr/local/docker', {:mount_options => ['dmode=777','fmode=777']}


This config allows us to populate¬†~/vagrant/docker-bsdpy with scripts, and¬†~/vagrant/docker-bsdpy/nbi with our NetBoot Images, so we don’t need to manually copy them into the VM.

3. Create a Startup script which will be used to setup the Docker BSDPy environment

$ cd ~/vagrant/docker-bsdpy
$ edit

The contents of The ETH variable is the network interface you are going to use. In my case, the virtual interface created by my VMware Fusion installation (enp0s8) worked best. You may get away with eth0 or eth1. Experiment!:


# Set this to match the valid interface

# Setup machine
yum update -y
yum install -y nano docker-io
service docker restart
chkconfig docker on

# Pull
docker pull hunty1/bsdpydocker

# Clean up
docker stop bsdpy
docker rm bsdpy

# Run
chmod -R 777 /usr/local/docker/nbi
IP=`ifconfig $ETH | awk '/inet / {print $2}' | sed 's/ //'`
echo $IP

docker run -d \
  -p \
  -p \
  -p \
  -v /usr/local/docker/nbi:/nbi \
  -e DOCKER_BSDPY_NBI_URL=http://$IP \
  --name bsdpy \
  --restart=always \

4. Make a DeployStudio NetBoot Image

Or use an existing one. I won’t go through GUI snapshots. Just make sure Python is enabled, and it’s set to HTTP type (not NFS). Once created, you need to move or copy it to the nbi folder and make some tweaks:

$ cp /Library/NetBoot/LibrarySP0/OSX-NETBOOT.nbi ~/vagrant/docker-bsdpy/nbi/
$ cd ~/vagrant/bsdpy/nbi/OSX-NETBOOT.nbi
$ rm NetInstall.dmg
$ mv NetInstall.sparseimage NetInstall.dmg
$ edit NBImageInfo.plist

You may wish to remove the entries from the DisabledSystemIdentifiers array. You should also ensure the following keys are set as follows:


5. Vagrant up!

It’s time to start up your virtual Linux server.

$ chmod 755
$ vagrant up

You will be asked to select a network interface. On my tests, vmnet8 was the correct choice.

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'chef/centos-7.0' is up to date...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Available bridged network interfaces:
1) en1: Wi-Fi (AirPort)
2) en0: Ethernet
3) p2p0
4) vmnet1
5) vmnet8
==> default: When choosing an interface, it is usually the one that is
==> default: being used to connect to the internet.
    default: Which interface should the network bridge to? 5

Now, we are ready to run the startup script. If all goes well, you should be able to netboot to your NBI!

$ vagrant ssh -c 'sudo /usr/local/docker/'

My setup encountered problems with a VirtualBox Guest Additions mismatch. YMMV. This is why I haven’t set to run in the Vagrantfile. You can uncomment it from the Vagrantfile if you want to try this out, and can certainly uncomment for subsequent vagrant ups. These commands fixed it:

$ vagrant ssh -c 'sudo yum update -y'
$ vagrant ssh -c 'sudo /etc/init.d/vboxadd setup’

If you encountered this too, you’ll get an error about needing to install a new kernel-devel-3.* package. Copy the version into the command:

$ vagrant ssh -c 'sudo yum install gcc yum install kernel-devel-3.*' ### copy the full path from the error message
$ vagrant ssh -c 'sudo /etc/init.d/vboxadd setup’
$ vagrant reload

6. Boot your VMWare Fusion VM

Boot up your VMWare Fusion OS X VM. If all goes well, you’ll see the VMWare boot screen, attempting to boot from EFI Network, and then the OS X boot screen with spinning globe:
Screen Shot 2015-04-29 at 22.25.04

Screen Shot 2015-04-29 at 22.25.08

To check what’s going on, you can monitor the log:

$ vagrant ssh -c 'sudo docker logs -f bsdpy'

Screen Shot 2015-04-29 at 22.29.11

Here’s my very first virtual DeployStudio workflow window!

Screen Shot 2015-04-29 at 19.54.01