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.

Categories
Mac admin'ing

T2 Macs don’t count as external boot media

I don’t see this documented anywhere in an officially explicit way, so I’m writing a blog post on this. With the introduction of T2-chip Macs, Apple introduced something called Startup Security Utility, and the official line there is that you can change the setting to “Allow booting from external media,” and then you can boot from “an external hard drive, thumb drive, or other external media.”

What the official knowledgebase article doesn’t tell you is that (again, just based on my own testing—if someone has official Apple documentation laying this out in a clear way, please comment below, and I’ll amend this post with a link to the official explanation) is that a T2-chip Mac does not count as “an external hard drive, thumb drive, or other external media.”

So, here’s what I’ve found based on my testing, if you change the Startup Security Utility settings to be as lax as possible:

  • You can target disk mode boot a T1 Mac to a T2 Mac.
  • You can target disk mode boot a T1 Mac to another T1 Mac.
  • You probably cannot target disk boot a T2 Mac to a T1 Mac… I’ve tried this with several machines of varying models, and sometimes it works; other times it doesn’t. I would probably err on the side of assuming it won’t work.
  • You cannot target disk mode boot a T2 Mac to another Mac.

And by “target disk mode boot,” I mean actually booting one Mac from another Mac, not mounting another Mac as an external drive inside an already booted Mac.

What’s been your experience? Are there tricks to get this to work that I’m not seeing?

If you know this to be true, is there official Apple documentation that lays this out clearly?

Categories
Mac admin'ing

If you update an AutoPkg parent recipe, but your override is still using old settings…

AutoPkg has a cool feature called parent trust that allows you to create recipe overrides that store a hash of the parent recipe (instead of running the parent recipe directly), and then prevent you from running the recipe if there’s a change to the parent recipe, until you update the trust info. (I also have a script that runs a list of recipes, checks trust info, and prompts you to approve changes if there are changes.)

But you may sometimes run into a situation in which you see the changes, the changes are important (for example, the download URL has changed to a new URL), but even after you accept the changes and update the trust info in your override recipe, the recipe still keeps using the old URL.

Here’s an example: AndroidStudio SEARCH_PATTERN error.

So if you make an override for AndroidStudio: autopkg make-override AndroidStudio.munki, you should see something like this:
   <key>Input</key>
   <dict>
      <key>MUNKI_REPO_SUBDIR</key>
      <string>apps/android</string>
      <key>NAME</key>
      <string>AndroidStudio</string>
      <key>SEARCH_PATTERN</key>
      <string>(https\://redirector\.gvt1\.com/edgedl/android/studio/install/.+/android-studio-ide.+\.dmg)</string>
      <key>SEARCH_URL</key>
      <string>https://developer.android.com/studio</string>
      <key>VERSION_SEARCH_PATTERN</key>
      <string>https\://redirector\.gvt1\.com/edgedl/android/studio/install/([0-9.]+)/android-studio-ide.+\.dmg</string>
      <key>VERSION_SEARCH_URL</key>
      <string>https://developer.android.com/sdk/index.html</string>

Those input variables are copied over from the parent recipe. But then if the parent recipe updates SEARCH_URL to be a different URL, your override will still have the old value for SEARCH_URL.

So if you see a change to a parent recipe, and your override still seems to be using the old values, check your override for input variables, and delete the ones you don't want to override.

Categories
Mac admin'ing

Force-stopping the MunkiStatus progress bar at the login window

Sometimes, the MunkiStatus progress bar over the login window can get stuck, and pressing the Stop button can take a while to halt the progress bar completely.

To kill it immediately, press Cmd-Option-Shift-Escape (this is a slight modification of the usual force-quite key combination, which is Cmd-Option-Escape).

Full credit to Yehuda Bialik and Greg Neagle for this tip. The Wiki on Bootstrapping With Munki is now updated also to include a note this keyboard shortcut.

Categories
Mac admin'ing

Using AppleScript to install macOS software updates via System Preferences

Right now, this is a bit more of a proof-of-concept, but since /usr/sbin/softwareupdate has become increasingly unreliable in the past year for automating and enforcing Apple software updates, having a way to automate installing updates through the GUI on certain relatively unattended Macs is worth exploring. I’ve created a GitHub project for that called Sys Pref Software Updates (or spsu, for short).

Categories
Mac admin'ing

A way to install macOS Catalina guest on VirtualBox on a Mac host

Why this blog post?

I won’t say this is the way to install macOS Catalina on VirtualBox, but it’s certainly a way, and it’s difficult to find information about a way to do it. There are a lot of posts indicating that 10.15 or 10.15.1 worked but 10.15.2 and beyond don’t. Or that there are difficulties with VirtualBox and APFS. There are also, if you look for blog posts about macOS guests, many blog posts about Apple-unsanctioned “hackintosh” setups on Windows or Linux hosts.

So there may be a way easier way to set up Catalina as a guest on a Mac host, but at least this is something (happy to link to better tutorials if people post them).

Install macOS High Sierra

I did a modified version of How to Install macOS High Sierra in VirtualBox on Windows 10 to get High Sierra installed on VirtualBox. These are the key parts:

Creating the .iso

hdiutil create -o /tmp/HighSierra.cdr -size 7316m -layout SPUD -fs HFS+J
hdiutil attach /tmp/HighSierra.cdr.dmg -noverify -nobrowse -mountpoint /Volumes/install_build
asr restore -source /Applications/Install\ macOS\ High\ Sierra.app/Contents/SharedSupport/BaseSystem.dmg -target /Volumes/install_build -noprompt -noverify -erase
hdiutil detach /Volumes/OS\ X\ Base\ System
hdiutil convert /tmp/HighSierra.cdr.dmg -format UDTO -o /tmp/HighSierra.iso
mv /tmp/HighSierra.iso.cdr ~/Desktop/HighSierra.iso

Creating the VM

Call the VM macOS (the tutorial says to use High Sierra, but we’ll be upgrading this later). Use two processors and 128 MB of video memory. Add the .iso to the optical drive part of storage.

Configuring the VM

Run these commands:
VBoxManage.exe modifyvm "macOS" --cpuidset 00000001 000306a9 04100800 7fbae3ff bfebfbff
VBoxManage setextradata "macOS" "VBoxInternal/Devices/efi/0/Config/DmiSystemProduct" "MacBookPro11,3"
VBoxManage setextradata "macOS" "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion" "1.0"
VBoxManage setextradata "macOS" "VBoxInternal/Devices/efi/0/Config/DmiBoardProduct" "Mac-2BD1B31983FE1663"
VBoxManage setextradata "macOS" "VBoxInternal/Devices/smc/0/Config/DeviceKey" "ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc"
VBoxManage setextradata "macOS" "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 1

Installing High Sierra

The tutorial mentions having to deal with the EFI Internal Shell. You shouldn’t have to. Installing High Sierra at this point with HFS+ (not APFS) should work.

Upgrading to Catalina

Once you’ve booted up to Setup Assistant and answered all the questions, you should be logged in and able to go to the Mac App Store to download and install the macOS Catalina upgrade.

Booting to recovery mode

I didn’t find Cmd-R to be a very reliable way to boot to recovery mode. And Rich Trouton’s trick to booting to recovery mode using VMWare doesn’t really apply to VirtualBox.

Another blog post (How to boot into recovery mode on mac without holding Command + R Key on keyboard ?) did have the solution, though. Just run
sudo nvram "recovery-boot-mode=unused"
and then reboot. That will do a one-time boot to recovery mode. Then when you reboot again, it should boot back to regular mode.

Enabling FileVault… sort of

If you want to enable FileVault, you’ll have to do so from the command-line (it’ll be greyed out in the GUI), but FileVault will basically be unusable (unless you just want to test in recovery mode):
sudo fdesetup enable
Don’t do this unless you already have your VM snapshotted or backed up. It will likely make your VM unbootable.

Changing the serial number

By default, the macOS VirtualBox guest serial number is 0, but you can change it (make sure the VM is powered off first). h/t to Utsav Dusad on Superuser.com:
VBoxManage setextradata "macOS" VBoxInternal/Devices/efi/0/Config/DmiSystemSerial "ACTUALSERIALNUMBER"

Categories
Mac admin'ing

What can you do at the password prompt in Catalina’s recovery mode?

The mysterious password prompt

Starting in macOS 10.15 (Catalina), Apple started requiring a password to do anything useful after booting into recovery mode:


It’s not exactly clear what this password is for. T2-chip Macs have hardware-based encryption, and that encryption is able to turn on instantaneously. Without mounting the encrypted drive, you can’t really reset a password or have access to the data on the drive. This prompt just seems like a rather odd choice, especially since it appears to act as almost some kind of firmware lock… except it’s not.

Option 1: Erase without password or recovery key

If you don’t know the password to a user account and also don’t know the recovery key to FileVault, you can still use recovery mode to erase the current installation and reinstall macOS. Yes, that’s that menu item hidden in the top-left corner.


You can just click Recovery Assistant and then select Erase Mac….

You’ll then be prompted to join a wireless network, and then some kind of Internet recovery is downloaded and booted to, and then you’ll be back at recovery mode with a prompt to activate your Mac, and then with the opportunity to reinstall macOS on the freshly wiped drive.

Option 2: Use FileVault recovery key with no password

But let’s say you don’t want to wipe the drive necessarily—you just want to do other recovery mode stuff, and you don’t know any user passwords. Well, you can click Forgot all passwords?

Then you can enter the FileVault recovery key for the drive.

Option 3: User FileVault-enabled user password

And if you do know a user password, of course, you can select the user, and then enter a password when prompted.

The only odd thing about that is it doesn’t actually get you past FileVault encryption.

That’s right. Even though you’ve entered a user password, if you want to mount the Macintosh HD – Data partition, you’ll still be prompted for a FileVault-enabled user’s password again.

Categories
Other Computer Stuff

Changing ownership of files in Google Drive via Google Apps Script

This was a fun little exercise in Google Apps Script to essentially transfer ownership of Google Drive files from one user to another.

Here’s a script that the old user should run to change ownership of those files to the new user:
ChangeFileFolderOwnership.js

And here’s a script that the new user user should run to remove the old user as editor from the newly changed-ownership files:
RemoveEditorFromDriveFiles.js

Note: You cannot use the file.removeEditor() command to remove yourself as an editor, so that actually has to be run from the new owner’s account.

Another Note: Just as when you change ownership or add editorship manually, scripting will also produce a ton of emails to the new editor/owner that you’ve add that person, so the new editor/owner may want to set up some temporary Gmail filters to mark those as read and put into the trash.