Categories
Mac admin'ing

Things to keep in mind if using a profile to delay macOS updates

Now that Apple has removed the --ignore flag from softwareupdate, it’s recommending you use the forceDelayedSoftwareUpdates and enforcedSoftwareUpdateDelay flags (more details in Device Management Profile: Restrictions), which are supposed to, in theory, delay an updates user visibility a certain number of days after the update’s release.

The number of days delayed may not be precise

The number of days delayed is imperfect at best. I tested a 7-day delay and even 6 days after the release of the update, it was suddenly available. And here’s an example of someone last year who didn’t see an update released 10 days before, even with only a 7-day delay.

System Preferences and softwareupdate may not be in sync

In my own testing, if you delay an update but a Mac is two or more updates behind, softwareupdate -d -a or softwareupdate -l will still show an update available to download, but System Preferences > Software Update will show Your Mac is running the latest software update allowed by your administrator.

That can be a problem if you rely on a program like Nudge, which uses softwareupdate to determine whether an update is available but points users to System Preferences to do the actual update.

At this time, unless Apple makes significant changes, I wouldn’t recommend using the delay update profile settings if you have any utilities that use softwareupdate to check whether updates are available or not.

Categories
Mac admin'ing

How to deploy a .pkg via Munki if a config file has to be in the same directory

Vendors package software in funny ways sometimes. Every now and then, you might come across a vendor .pkg that comes with some kind of .xml or .cfg or .txt that has to be in the same directory as the .pkg. It’s likely because there’s some postinstall script in the .pkg itself that references that text file via relative path.

There are basically two approaches you can take here with Munki.

Approach #1 would be to create another .pkg that delivers that .pkg as a payload to a directory of your choosing (e.g., /tmp) and also delivers the config file to that same directory. Then, in your custom .pkg, you have your own postinstall script that runs something like installer -pkg /tmp/nameofpackages.pkg -target /

Approach #2 is what I’d recommend, if you’re using Munki, which would be manually creating a disk image that has both the .pkg and config file in the same directory, and then importing that disk image into Munki. Munki mounts .dmgs to an arbitrary random mount point, but since the .pkg and config file will be in the same directory within the mounted .dmg, it won’t matter, and when Munki sees the .pkg inside the .dmg, Munki will just install the .pkg, and everything will be cool.

Categories
Mac admin'ing

Some basics of DEPNotify and a sample script

If you’ve been doing Munki admin’ing for a short while, you’ve probably heard people talk about DEPNotify, whose README says is “a small light weight notification app that was designed to let your users know what’s going on during a DEP enrollment.”

Aforementioned DEPNotify README is fairly comprehensive in terms of going over all the options. There’s also a project called DEPNotify-Starter, which has a sample script that’s, as of this writing, 827 lines long.

If you just want a super simple script to launch up DEPNotify and have it install some Munki stuff, I created a very, very simple sample script (DEPNotifyMunkiSample.sh) that just shows how you can use it without a ton of extra options. Once you wrap your head around that, you can always complicate it with more options.

This is what the sample script looks like in action if there’s only MunkiAdmin to install:

Categories
Mac admin'ing

Fixing DEPNotify GUI not launching with keyPath error

I’m not sure how my computer got into this funky state, but I was playing around with a DEPNotify script, and after a while, I was suddenly getting these errors every time I tried to run it:

DEPNotify[12422:409983] Failed to set (keyPath) user defined inspected property on (DEPNotify.WindowController): [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key keyPath.

DEPNotify[12422:409983] Failed to set (backgroundColor) user defined inspected property on (DEPNotify.ViewController): [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key backgroundColor.

I tried rebooting my Mac. That didn’t make the problem go away. I tried creating a new user account, and that didn’t either. It didn’t matter whether I ran my script or just manually invoked DEPNotify with a single command. The screen would flash briefly, as if something were launching, but there was no DEPNotify window, and it wasn’t hidden or minimized.

When I did a Google search on the error, the only real results were someone not using the -fullScreen option properly two years ago and another case in which a script that starts DEPNotify just needed an update.

Unrelated to my problem (which I asked helped for but got no response), Arek Dreyer on the MacAdmins Slack (thanks, Arek!) was responding to someone else’s problem with the depNotifyReset.sh script. I didn’t run the script but tried to run the individual commands.

What ended up fixing it for me was sudo rm /var/tmp/depnotify.log and then killall cfprefsd. Then DEPNotify was functioning again!

Categories
Mac admin'ing

Python script to list software available in a Munki repo

I created a small project (for fun) to list out software available in a Munki repo. It’s called MunkiItemsList.

On a basic level, it looks for all the items that are listed in any optional installs manifest, and then lists out the display name, description, and highest version available. There are some additional options described in detail in the README.

Categories
Mac admin'ing

Python 3 script to add optional installs to the SelfServeManifest

Two years ago, I wrote a bash script that adds a bunch of optional installs to the SelfServeManifest using /usr/libexec/PlistBuddy, which is a fine tool, but it can get bit messy sometimes. I did play around with using /usr/local/munki/manifestutil, but it got a bit convoluted, and I figured “Hey, why not just write it in Python 3, now that the default shell is zsh instead of bash and Python 2 is end-of-life?”

So, yeah, the rationale here is that you may want to have a bunch of applications installed as default applications for your users but still give users the option to remove those applications later, so this Python 3 script would just make it seem to Munki as if the user has already selected these optional installs to install… and then she can always use Managed Software Center to remove those optional installs later if she doesn’t want them any more.

Categories
Mac admin'ing

If your VMWare guest macOS loses network connectivity

If you haven’t changed any settings, and suddenly the Internet connection on your VMWare guest macOS installation goes out, and shutting down the VM or rebooting the VM doesn’t help, try rebooting the host Mac. That will likely fix the problem (not sure why that problem comes up in the first place.

Categories
Mac admin'ing

Script to make Jamf Self Service policy install a Munki optional install

There is a huge project called jamJAR that seeks to integrate Munki and Jamf in a seamless way.

I’ve written a script that does something a bit less ambitious, but it may still be helpful to your organization if you are “using” Jamf Self-Service, really want to be using Managed Software Center, and still want to keep Self-Service around (either temporarily or semi-permanently).

Basically install_munki_optional.py is a script that you can include in a Jamf Self-Service policy that will attempt to install a Munki optional install item. Just make the item name (not necessarily the same as the display name, mind you) the Parameter 4 in Parameter Values. Oh, and make sure that item actually is an optional install available in Managed Software Center!

The script will attempt to add that item to the SelfServeManifest. If the item already exists in the SelfServeManifest, the script will launch up Managed Software Center and try to focus on the item to basically say “Hey, remember this is already installed?” If the item doesn’t already exist in the SelfServeManifest, the script will add the item to the SelfServeManifest, launch up Managed Software Center, and attempt a managedsoftwareupdate --auto run.

As it’s written, it’s using Munki’s embedded Python 3, but if you have your own Python 3 you’d rather use, just update the shebang path.

Categories
Mac admin'ing

Using a full macOS installer with Munki to patch macOS

Caveat

This works right now, but I don’t know if this will keep working in perpetuity. As Apple plans on removing enterprise options for macOS software update points out, being able to manage patches in macOS is a moving target, and Apple is increasingly making it difficult for administrators to manage patches effectively.

Shoutout

Shoutout to Rod Christiansen on the MacAdmins Slack for putting this strange (but still working for now) method of patching on my radar.

Why would you want to do this?

Recently, softwareupdate has become an increasingly unreliable way to install updates. Munki 5 recently brought in some changes to have Managed Software Center nudge users to install patches via System Preferences (more details at Manual Apple Updates in Munki 5), similar to what Nudge does.

That is still the most reliable way to get patches installed, but what if you have Macs that basically sit unattended, so Nudge or a nudge-like prompt from Managed Software Center will basically be useless?

Well, apparently, you can use the full macOS installer to automate patching.

Limitations and considerations

One huge limitation, of course, is that you can probably use this method to patch only the latest macOS release. In other words, as of this writing, the latest build available for macOS 10.14.6 is 18G5033, but the latest full downloader for 10.14.6 is build 18G103. So you can’t really use an 18G103 full installer to update a Mojave client to 18G5033.

I believe using the installer to patch is the equivalent of doing a non-destructive reinstall of macOS (which you usually do in recovery mode), which means the download is considerably bigger than a regular patch download (more like 8 GB instead of 1 GB), and the install time is also longer (35-60 minutes instead of 20-30 minutes).

If the machines you’re patching are FileVault encrypted, you’ll still have to have someone be present either before or after the full macOS install to either do an authorized restart beforehand or a manual unlocking of FileVault afterwards.

Tweaks to the pkginfo

When you import something like Install macOS Catalina.app into Munki, munkiimport will, by default, make the installer_type into startosinstall. You may still want that installer in your Munki repo so you can upgrade Mojave clients to Catalina, so keep that pkginfo, but also make a copy of that pkginfo and tweak things a bit.

Change the installer type to be a CopyFromDMG:
    <key>installer_type</key>
    <string>copy_from_dmg</string>
    <key>items_to_copy</key>
    <array>
        <dict>
            <key>destination_path</key>
            <string>/tmp</string>
            <key>source_item</key>
            <string>Install macOS Catalina.app</string>
        </dict>
    </array>

and then have a postinstall script that runs the startosinstall command after copying from the .dmg:     <key>postinstall_script</key>
    <string>#!/bin/zsh
# Run startosinstall
/tmp/Install\ macOS\ Catalina.app/Contents/Resources/startosinstall --agreetolicense
    </string>

You’ll also want to change the name, so it’s distinct from Install_macOS_Catalina:

    <key>name</key>
    <string>Update_macOS_Catalina</string>

Might as well update the display name as well:

    <key>display_name</key>
    <string>Update macOS Catalina</string>

The last important tweak is to throw an installcheck_script in there so Munki knows whether the patch is installed or not:     <key>installcheck_script</key>
    <string>#!/usr/local/munki/python
from distutils.version import LooseVersion
import subprocess
import sys
# Desired OS build
desired='19F101'
def main():
    # Get current OS build
    cmd = [ '/usr/bin/sw_vers', '-buildVersion' ]
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8')
    out, err = p.communicate()
    if err:
        print("ERROR: Unable to determine current OS build. Considering installed for now...")
        sys.exit(1)
    else:
        # Strip out extra carriage return from output
        curr_build = out.strip()
        if LooseVersion(curr_build) &gt;= LooseVersion(desired):
            print("The current build {} is already greater than or equal to {}".format(curr_build, desired))
            sys.exit(1)
        else:
            print("Current build {} is not yet {}".format(curr_build, desired))
            sys.exit(0)
if __name__ == "__main__":
    main()
    </string>

Manifest Change

You may also want to add in a Munki conditional item so that only 10.15 clients are targeted.

    <key>conditional_items</key>
    <array>
        <dict>
            <key>condition</key>
            <string>os_vers_minor == 15</string>
            <key>managed_installs</key>
            <array>
                <string>Update_macOS_Catalina</string>
            </array>
        </dict>
    </array>

What the update process looks like

    Evaluating predicate: os_vers_minor == 15
    Predicate os_vers_minor == 15 is True
    * Processing manifest item Update_macOS_Catalina for install
    Looking for detail for: Update_macOS_Catalina, version latest...
    Considering 1 items with name Update_macOS_Catalina from catalog testing
    Considering item Update_macOS_Catalina, version 10.15.5.19F101 with minimum Munki version required 3.0.0.3211
    Our Munki version is 5.0.0.4034
    Considering item Update_macOS_Catalina, version 10.15.5.19F101 with minimum os version required 10.15
    Our OS version is 10.15.5
    Considering item Update_macOS_Catalina, version 10.15.5.19F101 with maximum os version supported 10.15.99
    Our OS version is 10.15.5
    Found Update_macOS_Catalina, version 10.15.5.19F101 in catalog testing
    Adding Update_macOS_Catalina to list of processed installs
    Running installcheck_script for Update_macOS_Catalina
    Current build 19F96 is not yet 19F101
    installcheck_script returned 0
    Need to install Update_macOS_Catalina

    The following items will be installed or upgraded:
        + Update_macOS_Catalina-10.15.5.19F101
            Updates macOS version to 10.15.5, build 19F101
         *Restart required

A key piece from /var/log/install.log: 2020-06-02 09:30:54-07 HOSTNAME softwareupdate[401]: Starting softwareupdate CLI tool
2020-06-02 09:30:54-07 HOSTNAME softwareupdated[402]: softwareupdated: Starting with build 10.15.5 (19F101)
2020-06-02 09:30:54-07 HOSTNAME softwareupdated[402]: authorizeWithEmptyAuthorizationForRights: Requesting provided rights: 1
2020-06-02 09:30:56-07 HOSTNAME softwareupdated[402]: /Library/Bundles does not exist - watching for directory creation
2020-06-02 09:30:56-07 HOSTNAME softwareupdated[402]: Previous System Version : 10.15.5 (19F96), Current System Version : 10.15.5 (19F101)

Yeah, that’s it. That whole install (not counting the download of the installer) took a full hour to complete. On another machine I tested with, it was closer to 35 minutes to complete. So, your mileage may vary.

Categories
Mac admin'ing

AutoPkg failed: hdiutil: attach failed – no mountable file systems error

If, when running AutoPkg, you get an error like

failed: hdiutil: attach failed - no mountable file systems

but you’re able to mount the .dmg manually (i.e., it’s not a corrupted download), double-check you don’t have a restrictions profile installed that requires you to authenticate when mounting disk images. That setting is pretty much useless anyway if you’re an admin user (you won’t be prompted in the GUI to authenticate when mounting disk images via Finder), and it will just make it so when AutoPkg is trying to run

/usr/bin/hdiutil attach -plist -mountrandom /private/tmp -nobrowse /PATH/TO/DOWNLOADED/DISKIMAGENAME.dmg

that it will choke with that error.

(Oddly enough, if you just do hdiutil attach without all those other options, it will still work just fine.)

Special shoutout to @elios on the MacAdmins Slack for helping another user figure this out three years ago, and so that’s how I was able to solve my problem.