Getting up and running with InstallApplications

Erik Gomez did a presentation in 2017 on his InstallApplications project:
Macbrained SF Pinterest April 2017

Now that Apple's deprecating monolithic imaging, a lot of workflows have gone to DEP=>MDM=>something else (like Munki).

After doing some testing with InstallApplications, I think we're probably going to stick with our custom script workflow, but I didn't want our tinkering with it to be in vain, so hopefully some of these notes should help another school, org, or company that wants to get its feet wet with InstallApplications and may actually find it better suited for their situation than for ours.

This isn't a comprehensive guide on how to set up InstallApplications—just some implementation notes that may help people on a few of the things we got hung up on when trying it. For more comprehensive details on InstallApplications, check out the README for it and also this blog post: CUSTOM DEP - PART 9: A PRACTICAL EXAMPLE OF INSTALLAPPLICATIONS, CRYPT, DEPNOTIFY AND MUNKI.

You will need a signing certificate for InstallApplications.

The kind you want, though, can't be obtained by an admin. It has to be created by the Team Agent.

When you add a certificate, make sure you select macOS from the drop-down menu, and then select Developer ID.

Then select Developer ID Installer

Once you go through the steps of setting up the certificate, you should have a certificate on your Mac to import into your Keychain. Import it into your login (not system) keychain.

Then, make a note of this part: Developer ID Installer: YOURDEVELOPERDESCRIPTION (AWHOLEBUNCHOFSTUFF). You'll use that later in the build-info.json file.

When you download the project from GitHub (or git clone it), you'll see a bunch of files and folders.

For the simplest set up, the only things you'll modify are build-info.json and com.erikng.installapplications.plist.

The generatejson.py file you'll use to generate a .json to put on a server somewhere (or build into your package).

When you run munkipkg on the InstallApplications project folder, you'll get a .pkg in the build folder, which you can upload to your MDM.

Special note to other Mosyle users out there—don't be silly like me and forget to check the checkbox after you upload your InstallApplications .pkg file.

Hat tip to jacobfgrant on the Mac Admins Slack for telling me the minimal files to modify.

MathType formulas shrink after editing and saving them in Microsoft Word

March 2019 Update: WIRIS has now announced a workaround for randomly resized equations. I don't know for sure that that's exactly the same problem as the shrinking formulas, but it could be. Definitely worth checking out if you're experiencing this issue.

One teacher had an issue in MathType that involved saved formulas in a Word doc shrinking after editing and saving them again (even if the edit involved no actual changes).

The weird thing is that we tried with another user on the same machine with the same document and couldn't replicate the behavior, so it seemed to be tied to the user profile, but then later, with a fresh user profile, the issue still seemed to persist. So maybe that was a weird anomaly (it not shrinking)?

I did a bit more digging and Googling and came across this answer from WIRIS:

This is an issue with Retina displays, so that's one possible workaround: if you have a non-Retina display, use that when inserting or editing equations. The equations will be fine if merely viewed or printed when using a Retina display, but when you insert or edit one is when the sizing issue happens.

As Charles suggested in an earlier reply, "Consider reverting to Version 16.15." This is, in fact, Microsoft's recommendation as well. The answer on an earlier question in the Microsoft Community answers forum describes how to do that.

"[F]ine if merely viewed or printed" means, as far as I can tell, if you have already existing formulas that haven't been edited.

We tried reverting to 16.15, and that seemed to fix the issue.

For Munki users trying to downgrade Word to address this particular MathType issue, this is what worked for us:

  • Import Word 2016 (version 16.15).
  • Get the installs array of the binary at /Applications/Microsoft Word/Contents/MacOS/Microsoft Word, and put that in the pkginfo.
  • Modify the pkginfo to also change the version to be higher than 16.16. For us, 16.16.18091015 was sufficient for the change to take hold.
  • Create a new catalog called mathtype, and make that the only catalog for this pkginfo.
  • Put in a preinstall_script that checks for the existence of /Applications/Microsoft Word, and deletes it if necessary. If you don't do this, Munki will install 16.15, but it won't actually replace 16.16.
  • Add the mathtype catalog to the relevant manifest(s) you want to have this downgraded version of Word. Put this catalog before production, testing, or any of the other regular catalogs you have (more details on why).

Example of the preinstall_script:

#!/bin/bash

# Doesn't work if the newer version is already there, so delete it
existing_word='/Applications/Microsoft Word.app'

if [[ -a "$existing_word" ]]; then

/bin/rm "$existing_word"

fi

This downgrade procedure is modeled after the general approach to downgrading via Munki, outlined on the wiki.

P.S. The shrinking MathType formula problem persists in Word 16.17 (Word 2019).

Using Santa to block macOS upgrades

In the past, I'd used the fake installer approach to stop users from upgrading to the newest macOS version.

But with macOS 10.14 (Mojave), I started blocking using Santa (see Using Santa to block an .app for more details on general Santa use). It's likely this Santa-blocking approach also works for High Sierra and Sierra as well—I just haven't tested it on those.

Just download Mojave to your Mac, and then run

santactl fileinfo /Applications/Install\ macOS\ Mojave.app --key SHA-256
to get the hash to block.

Then run a modified version of this command (substituting in the actual SHA-256 hash for the placeholder) to add it to the Santa blacklist:

/usr/local/bin/santactl rule --blacklist --sha256 "actuallonghashyougotfromthepreviouscommand"

We were able to test this on two Mojave installers downloaded using two separate Apple IDs, so the binary seems to be the same regardless of which Apple ID is used to download it.

If a user then tries to run the Mojave installer, she or he will see a message like this:

Again, since it's based on the binary (and since you don't want to block by Apple certificate—which you may not be able to do anyway with Santa?—so you have to block by binary), you would have to create a new rule for every new macOS installer that comes out (10.14, 10.14.1, 10.14.2, 10.14.3... 10.15, 10.15.1... 10.16... and so on).

Special Note

Thanks to @elios (on Mac Admins Slack) for pointing out that this probably would not block the startosinstall binary from running. I was able to test and verify blocking the .app binary does not, in fact, block the startosinstall binary from running.

Also, by default, Santa will get the binary for InstallAssistant_springboard. If you want to be super aggressive, you might also want to block the InstallAssistant and InstallAssistant_plain binaries. Otherwise, the user can still run those two to get the GUI assistant to launch up.

So you really have to ask yourself how aggressively you want to block Mojave. Are you preventing users from just accidentally upgrading? Or do you want to prevent from upgrading even the most determined users who have admin privileges?

If you want to block startosinstall as well, you can do that. Just find (and subsequently block) the SHA-256 hash it:

santactl fileinfo /Applications/Install\ macOS\ Mojave.app/Contents/Resources/startosinstall --key SHA-256
santactl rule --blacklist --sha256 "actuallonghashyougotfromthepreviouscommand"
One advantage you get from not blocking startosinstall is that you can still block users from double-clicking to install Mojave but not have Santa try to block Munki from installing Mojave, even if you have the InstallAssistant_springboard blocked.

If you block startosinstall, then try to install the upgrade with Munki, you'll see it mount the .dmg, then stop. The log entries will look something like this:

### Beginning os installer session ###
Starting macOS upgrade...
Mounting disk image Install macOS Mojave-10.14.2.dmg
[Errno 1] Operation not permitted
Starting macOS install failed with return code 1
ERROR: ------------------------------------------------------------------------------
ERROR: [Errno 1] Operation not permitted
ERROR: ------------------------------------------------------------------------------
ERROR: Error starting macOS install: startosinstall failed with return code 1
### Ending os installer session ###

Activating Geometer’s Sketchpad in macOS 10.13.6 (and beyond?)

In Licensing GSP Deployments by Terminal Command , I covered the officially sanctioned way to license GSP5 for Macs.

I believe that was still working even as of 10.13.5. It certainly was working in 10.12.

Unfortunately, with 10.13.6—unless you had an already activated GSP when you upgraded to 10.13.6 from 10.13.5 or earlier—you might get error messages like

usage: Sketchpad_Executable -license (register | deregister) -name LicenseName -code AuthorizationCode
in the terminal or like in the GUI, even if you're using an admin account.

So I opened a ticket with McGraw Hill, and they said:

The license for all users is stored in the "/Library/Application Support/The Geometer's Sketchpad/" so it must be a permissions issue with that folder, either creating it for a new install, or accessing it when deregistering an old install.

If you copy the "The Geometer's Sketchpad" folder for a non-admin user install (which would be found in "~/Application Support/The Geometer's Sketchpad", to the global /Library/Application Support/ folder, that should also work, provided that the folder permissions allow read/write.

Lo and behold, that was the the old non-sanctioned, unofficial way I used to license GSP5 on Macs.

Tested it out on 10.13.6. Works!

So, yeah, use the old way until McGraw Hill figures out what's going on.

Using ffmpeg to trim video

No real tutorial here, just a link to a great resource on this via Stack Overflow:
Cutting the videos based on start and end time using ffmpeg

Cutting with ffmpeg takes a lot less longer than rendering out via iMovie, and it results in a similarly sized output file instead of a giant one

P.S. My boss just showed me how you can do this in Quicktime with Edit > Trim. Much easier!

Waiting for FileVault encryption to finish to install macOS updates

If you notice you can't install new macOS updates on a Mac, it could be that it's still in the process of FileVault encrypting.

For example, here's a machine that's on macOS 10.13.4.

softwareupdate can't find any updates.

And even if you try to manually install the 10.13.6 combo update, you get macOS High Sierra 10.13.6 Update can't be installed on this disk. This volume does not meet the requirements for this update.

And, yup—lo and behold! The FileVault encryption is still in progress. Once that's done, the 10.13.6 update should install just fine.

Images not loading in Gmail canned responses

Do you use images in canned responses in Gmail? Did you notice your images suddenly showing up as blank boxes (both in the composition and in the actual sent message)?


Well, there's a fix for that. Use the new Gmail instead of the old Gmail:


Your images should now load (you do not need to re-create your old canned responses).

Integrating DetectX Swift with Munki

If you like DetectX Swift and want to integrate it with Munki, this is how I did it. Hat tip to Zack McCauley for doing the heavy lifting, which I'm now building on. I'd recommend you read his blog post first.

So instead of having an Outset script or separate Launch Agent, I decided to put the DetectX Swift scan as part of the Munki run (specifically a script in the postflight.d directory (if you put it in a preflight, it will be a blocking application that will prevent DetectX Swift from doing an unattended install upgrade) that MunkiReport creates):

It's best to use a separate Launch Daemon (example here), because the scan can sometimes take over a minute, and MunkiReport scripts will time out after ten seconds.

#!/bin/bash

# Run a DetectX Swift scan
/Applications/Utilities/DetectX\ Swift.app/Contents/MacOS/DetectX\ Swift search -aj /usr/local/munki/preflight.d/cache/detectx.json

Outside of MunkiReport (but connecting to the MunkiReport MySQL database), I have a script that generates a Python list of files that DetectX Swift has flagged as "issues":

$query="SELECT issues FROM detectx WHERE numberofissues > 0";
$result=mysqli_query($YOURDATABASECONNECTION, $query);
if(mysqli_num_rows($result)>0){
   // Create an array to store the results
   $larger_issues=array();
   while($row=mysqli_fetch_assoc($result)){
      
      // Create an array based on a semi-colon delimiter
      $smaller_issues=explode(";", $row['issues']);
      foreach($smaller_issues AS $smaller_issue){
          if((trim($smaller_issue)!='') AND (!in_array($smaller_issue, $larger_issues))){
            array_push($larger_issues, $smaller_issue);
         }
      }

   // End fetching results
   }

   if(!empty($larger_issues)){
      echo '<p>okay_to_delete = [ ';
      $counter=0;
      while($counter+1<count($larger_issues)){
         echo '\'' . $larger_issues[$counter] . '\',<br />';   
         $counter+=1;
      }
      echo '\'' . $larger_issues[$counter] . '\' ]</p>';
      //print_r($larger_issues);
   
   // End checking there are elements in larger issues (there should be)
   }

// End checking there are any issues
}

And finally I have a nopkg to do the actual cleaning of the issues DetectX flagged.

So why even have an array of okay-to-delete things?

Well, DetectX Swift has command-line options to scan, but it (at least as of this writing) does not have the option to command-line remove things, presumably so someone has a chance to review the things removed before actually removing them. Also, since it's just forcefully removing things (yes, I know about using shutil to remove, but I've run into weird situations in which that doesn't work consistently, so I'm using a subprocess to invoke rm instead), it's probably a good idea for at least one human to review things before they get removed.

The nopkg also copies the .json to /var/log (with a datetime stamp in the name) before removing anything.

Use docklib to manage macOS docks

docklib instead of dockutil

I have a few posts about using dockutil to manage the macOS dock. dockutil is still a valid and working project, but I'm starting to migrate my scripts to docklib instead.

Installing docklib

The installation instructions for docklib say you can put the docklib.py file in the same directory as the scripts that invoke it or you can put it "in your Python path." I'd recommend just grabbing the docklib .pkg from the releases page or using the AutoPkg docklib recipes to download it. The .pkg puts docklib.py in /Library/Python/2.7/site-packages/docklib.py.

Using docklib with Outset

docklib can be used in an Outset login-once or login-every script. There is no need to explicitly put in a delay to wait for the initial dock to appear before running your script. There is also no need, if you're specifying a dock (rather than modifying an existing one) to remove the default applications Apple puts on the dock. If you're specifying a dock, just say what you want to add. Use this suggested template:

import os
from docklib import Dock
tech_dock = [
   '/Applications/Google Chrome.app',
   '/Applications/App Store.app',
   '/Applications/Managed Software Center.app',
   '/Applications/System Preferences.app',
   '/Applications/Utilities/Activity Monitor.app',
   '/Applications/Utilities/Console.app',
   '/Applications/Utilities/Disk Utility.app',
   '/Applications/Utilities/Migration Assistant.app',
   '/Applications/Utilities/Terminal.app',
]
dock = Dock()
dock.items['persistent-apps'] = []
for item in tech_dock:
   if os.path.exists(item):
      item = dock.makeDockAppEntry(item)
      dock.items['persistent-apps'].append(item)
dock.save()

Checking if an item exists before removing/adding via docklib?

Here's an example of checking for something's existence on the right side of the dock before adding it. To check on the left side, it's a very similar process, except you just replace

section='persistent-others'
with
section='persistent-apps'

For example, this will add Microsoft Word only if it's not in the dock already:

from docklib import Dock
dock = Dock()
if dock.findExistingLabel('Microsoft Word', section='persistent-apps') == -1:
   item = dock.makeDockAppEntry('/Applications/Microsoft Word.app')
   dock.items['persistent-apps'].append(item)
   dock.save()

If you add an item using docklib that already exists in the dock, a second instance of it will be added to the dock, so you definitely should check for the existence of the item first.

However, if you want to remove an item, just use the standard removal procedure:

from docklib import Dock
dock = Dock()
dock.removeDockEntry('Microsoft Word')
dock.save()
If the item isn't in the dock when you try to remove it, docklib won't give any error or warning.

What I learned upgrading from MunkiReport 2 to MunkiReport 3

The setup for the old (version 2) MunkiReport was fairly simple. You essentially just downloaded the folder to your web server.

The setup for the new (version 3) MunkiReport has a bit more nuance to it. I had a lot of trouble setting it up, but thanks to some help from other Mac admins (special thanks to Rick Heil for getting me over the finish line), I was able to finally get it up and running.

Here are a few issues I ran into. Maybe if you're running into the same or similar issues, this list may help:

  • Ubuntu 16.04 doesn't have PHP 7.0.27 or higher, which the new version of MunkiReport requires, so I had to add it in with the appropriate PPA.
  • On a related note, once you add that PPA to your sources.list in Ubuntu, you get a whole ton of PHP versions available via apt: 7.0, 7.1, 7.2. It's best to make sure you have only version of PHP installed and remove all the rest. I'd recommend 7.2 at this point.
  • It's a good idea to start with the sqlite database just to eliminate MySQL connection issues as a possibility. That said, since the main MunkiReport 3 files don't live in the public-facing part of the web server, be especially mindful of this part of the wiki instructions: when using SQLite as backend (which is the default), check if the directory /app/db/ is writeable by the webserver.
  • If you're using AD or SAML authentication, move it up in the composer.json file from suggest to require and get rid of the description after the version number. For example, "adldap2/adldap2": "^8.0 Required for AD authentication" should change to "adldap2/adldap2": "^8.0" after being moved.
  • If you're running the composer command and get a [RuntimeException] The "--no-suggest" option does not exist. message, just ditch the --no-suggest part of the command.