Category: Scripting and Packaging Page 1 of 2

Controlling Munki via Workspace ONE and Active Directory

I got something working recently, and I thought it was interesting enough that it’d be worth sharing.

Our MDM server is a SaaS instance of Workspace ONE UEM, and we have the AirWatch Cloud Connector installed in an on-prem VM to provide integration with Active Directory. Although WS1 bundles its own (modified) version of Munki, we don’t use it – we have a separate on-prem VM for our vanilla Munki server.

Unfortunately, this post is partially about printers (sorry). The challenge with setting up LPD printers on the macOS, is that the drivers need to be installed before the printer is added (or the printer is added with a generic driver, and must be removed and reinstalled). Munki is an excellent use case for this, as the requires and update_for pkginfo keys are perfect for setting up dependencies.

For several years, I used Graham Gilbert’s printer-pkginfo script to deploy printers with Munki. That, combined with my NoMAD group condition script, allowed me to deploy printers to only certain people’s devices – their user accounts in AD needed to be a member of a particular group.

With macOS 12.3 dropping Python 2 from the OS, I needed another solution. I landed on wyncomco’s fork of Nick McSpadden’s PrinterGenerator script. It works well, but with our move from NoMAD to Jamf Connect, how would we be able to leverage our AD groups to deploy these printers?

Thanks to the AirWatch Cloud Connector, I was able to add the AD security group to WS1 (in Accounts > User Groups > List View). The group in WS1 syncs periodically with AD, so users added to AD will appear in the WS1 group after a few hours.

In my case, though, I needed a Smart Group (sometimes called an “Assignment Group”) to actually make use of the user group. In Groups & Settings > Groups > Assignment Groups, add a new Smart Group where the first criteria is the Organization Group that contains your devices. Scroll down to User Group, and select the group you’re synching from AD. Name your Smart Group and click Save.

The last piece was how I’d get the printer to these users. Around the same time, VMware added the ability to run scripts through Workspace ONE. I had remembered Nick McSpadden’s post about Local-Only Manifests in Munki, which was perfect for this. I’d set up a separate manifest for WS1 to write to, and Munki would install the printer driver and the printer automatically.

First, in your Munki configuration profile, add this:


This tells Munki to check this additional manifest for potential items to install. There’s no need to create the file – if it doesn’t exist, Munki proceeds as normal, without printing any warnings/errors.

Lastly, add this script to WS1 (in Resources > Scripts), and assign it to your Smart Group. Set the language to Bash, and the execution context to System.



printer_installed=$(${defaults} read "/Library/Managed Installs/manifests/LocalOnlyManifest" managed_installs | ${grep} "MyPrinter")

if [ ! "${printer_installed}" ]; then
 ${defaults} write "/Library/Managed Installs/manifests/LocalOnlyManifest" managed_installs -array-add "MyPrinter"
    exit 0


In my case, I have it run immediately upon device enrollment, as well as when the network interface changes. The code runs a check to see if the Munki item MyPrinter is in the LocalOnlyManifest, and if not, it adds it. The next time Munki runs a background check, it will install the driver and printer automatically.

The end result is that when a user requires our printer, any AD admin can add the user to a particular group. Some time later, the user will receive the printer without needing to do anything. If the user already has our printer, but receives a new computer, the printer will be added as soon as the computer is set up – no additional admin work necessary.

I hope someone finds this useful for more than just printers!

MunkiReport in Azure

Following up on my last post – up until a couple of months ago, our production MunkiReport server was running Windows Server 2012 R2. Yep, MunkiReport was running in IIS, and MySQL was installed in the same VM. The server was about 8 years old, and while it had served us well, it was time to migrate to something more modern.

As we’re pushing to move more stuff into Azure, and containers are the future of these types of deployments, I spent a bunch of time figuring out how to get MunkiReport running as a Docker container in Azure. Even better: I automated it, so you can do it, too!

Please check out my GitHub repo for the script.

We’ve had this running in production for a couple of months now, and it’s averaged out to about $4.60/day for ~700 clients.

Due to some upcoming life changes, I’m not sure how much further development the script will receive from me. I intend to add some documentation, but there are definitely improvements that could be made (such as migrating to an ARM/BICEP template, or making some portions of the script optional). Please check out the script and let me know what you think!

Modern Bootstrapping: Part 2 (Building the Packages)

This is the second post in my multi-part series on modern bootstrapping with Workspace ONE UEM. If you haven’t read the first one, you can find it here.

Modern Bootstrapping: Part 1 (Intro)

For a while now, I’ve been meaning to post about how I’m bootstrapping our Macs using Workspace ONE UEM and several open source tools. This will be a multi-part series, and will culminate with a presentation at the University of Utah’s MacAdmins meeting for May 2021. I feel that it’d be best to start with some historical context and how bootstrapping has evolved since I joined the industry.

Using Munki to enable sudo for Touch ID

Ever since I got my MacBook Pro with a Touch Bar, I’ve avoided typing in my password as much as possible. macOS 10.14 and 10.15 added more places in the OS that accept Touch ID, which has been a welcome change. As part of my job, I tend to use the sudo command quite a bit, and this post from Rich Trouton has been a godsend. Just edit the appropriate file, restart your Terminal session, and you’re all set.

However, with many macOS patches and security updates, /etc/pam.d/sudo is reset back to defaults. I don’t know why this happens, but it’s quite annoying. After manually applying the change to this file again, I finally decided to script it.

Now, there are a handful of files that can really ruin your day if they become damaged or invalid. This is one of those files. Please proceed with caution, keep good backups, and be prepared to reinstall your OS if things get really messed up. That said, this worked for me on macOS 10.15.5, and will hopefully continue to work for years to come.

Since I use Munki, I decided to build a nopkg file that checks for the appropriate line in /etc/pam.d/sudo, and inserts it if it’s not present. To download the code, please see my GitHub repository.

A note about testing macOS 10.14 and DEP with VMs

Just a quick note if you’re following this method to test Apple’s Device Enrollment Program (DEP) with VMs: as of macOS 10.14.3, the hardware must meet the minimum system requirements for macOS 10.14.

With macOS 10.14.0 through 10.14.2, you were able to use serial numbers from Macs that could not run 10.14.x themselves. Since you’re booting VMs, that didn’t really matter. However, as of 10.14.3, the VM will stall while booting, then eventually reboot and stall again.

It’s unfortunate, as older hardware is easier to find – I had a stack of 2011 Mac minis that I kept specifically for VMs.

Update, 2019-09-03: Erik Gomez corrected me: if you create a VM with vfuse, specify the 2011 Mac mini’s serial number, but use Macmini6,2 instead of Macmini5,1 as hw_model, it’ll boot and let you proceed through DEP. I haven’t tested any other model, but this works great! Thanks, Erik.

Binding Macs to AD using Munki’s Configuration Profile support

Update, 2020-06-11: I’ve changed the code back to a script. Please see the GitHub repo for an explanation and the updated code.

Although the trend is to move away from binding Macs to Active Directory (most commonly using NoMAD), we’re still binding for various reasons:

  • Being able to authenticate with domain credentials for doing things that require admin privileges.
  • Being able to connect remotely using domain credentials.
  • Computer labs and other multi-user Macs.
  • We’re still using AD mobile accounts, for now.

Originally, we would bind Macs to AD as part of our DeployStudio imaging workflow. Unfortunately, we faced a couple of drawbacks with this approach:

  • By installing/configuring something only when imaging, you’re not enforcing the setting – it’s a one-shot thing. In the future, the setting could change, or the application might require an update, but you’re not going to reimage your entire fleet every time that happens.
  • When we moved from DeployStudio to Imagr, we needed to trim our workflows to be as slim as possible.

With the help of Graham Gilbert’s tutorial, we were able to move AD binding to Munki. This also gave us an unexpected benefit: in the past, we frequently found that the binding on Macs would randomly break. This was a major issue in the classrooms, where students and faculty would not be able to login to computers and start class. Moving this to Munki with a custom installcheck_script made it “self-healing” – every 1-2 hours, Munki will rebind the Mac, if necessary (or prompt the user to do this through Managed Software Center).

For the past year, there’s been a big push to move to configuration profiles for applying settings. Luckily, you can use the “directory” payload to bind to AD! However, it’s just running dsconfigad in the background anyway, so it’s entirely possible for your Mac’s binding to be broken, but the AD profile to show as successfully installed. The MDM protocol currently has no method of determining if the AD profile should be reinstalled, so Munki is a much more logical choice for deploying this. Armin Briegel’s tutorial was instrumental in assisting with this transition.

Code and usage instructions are available in my GitHub repository.

Deploying JMP Pro 12.x and 13.x licenses

As I’m reorganizing my GitHub repositories, I’ve realized that I forgot to post about my work with Shea Craig and the JMP Team at SAS. Because of them, I was able to deploy JMP Pro 12.x and 13.x licenses to our Mac labs.

You can find code and instructions at my jmp_pro_12_license_pkg and jmp_pro_13_license_pkg GitHub repositories.

NoMAD Group Condition for Munki

One of the most powerful features of Munki are conditional items – and the ability for an admin to provide custom conditions for deploying or removing software. For example, we’ve been using the scripts that Hannes Juutilainen has published to determine which macOS version is supported by a particular Mac’s hardware.  We can then offer the most appropriate OS upgrade to each Mac.

We recently deployed the excellent NoMAD to single-user Macs, with the intention of resolving keychain issues (and eventually moving away from Active Directory binding altogether). If you’re using AD with your Macs, it’s absolutely worth checking out.

When a user logs into NoMAD, some data about the user’s AD account is retrieved for later usage – such as their group membership (also known as Organizational Units, or OUs). In our environment, users are divided into different groups based on their department. What if we could use that for deploying printers, similar to Group Policy on Windows?

You might see where I’m going with this – check out the script on GitHub for requirements and usage instructions.

Deploying Gaussian

I thought I blogged about deploying Gaussian 09 when I published this GitHub repository, but I guess I forgot to do that.  Anyhow, here’s some code for deploying Gaussian 16, the latest version of the Gaussian software.

Page 1 of 2

Powered by WordPress & Theme by Anders Norén