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.

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 preflight.d directory that MunkiReport creates):

#!/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, which doesn't seem to require workarounds like this one.

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.

Upgrading to High Sierra: “You may not install this volume because the computer is missing a firmware partition”

If you try to upgrade to High Sierra (macOS 10.13) and get You may not install this volume because the computer is missing a firmware partition when trying to select your drive to upgrade, it may be because you're upgrading on an OWC drive.

If you're using Munki, the error may appear in your /Library/Managed Installs/Logs/Install.log as Starting macOS install: FAILED: startosinstall failed with return code 243.

Previously, you'd have to physically swap back the OEM drive, and then put the OWC drive back again, but now OWC has its own firmware updater tool that fixes the problem:
Aura SSDs: Firmware Update (beta).

Parental Controls keeps blocking allowed apps

If macOS Parental Controls keep blocking allowed apps (both allowed through the checklist in System Preferences and through manually approving via password), deleting the account and recreating it may not be enough to fix the glitch. Instead, try recreating an account with a new name.

I've found Santa to block things more reliably (or not to block things you've allowed). You can block by certificate or (for Apple applications you'd need to do this), block by binary.

CrashPlan 6.5 stuck on Connecting… and never times out

We had a couple of clients who would just never do an initial connection to CrashPlan after the upgrade from CrashPlan 4 to CrashPlan 6.5. But they would never time out or give an error message either.

Restarting the CrashPlan service didn't help. Restarting the computer didn't help. Uninstalling and reinstalling the client didn't help.

Turns out it if the detect-a-user script can't find a CP_USER_HOME, it will just keep trying to connect instead of erroring out. We modified our script, and now those clients are good (we did have to uninstall and reinstall the client after modifying the script, though).

P.S. Someone pointed out that I don't actually share the original or modified script. The point of this blog post isn't to say "Here's a script that works." There are lots of scripts that work. The point is more that if you're experiencing this issue ("connecting" and never timing out or providing an error message), you likely need to fix your script to output a CP_USER_HOME).

Getting the Team ID of kernel extensions in macOS 10.13 (and higher?)

Why do you need Team IDs?

Beginning with macOS 10.13 (High Sierra), Apple is now blocking kernel extensions unless you, in recovery mode (or recovery mode–like environment), change the policy on the machine itself or use an MDM profile to approve certain KEXTs by Team ID.

How do you find these Team IDs, though?

sqlite3

One way is to install the KEXTs on a 10.13 machine, user approve them, and then check the sqlite database to see what the Team IDs are:

sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy
SELECT * FROM kext_policy;

Here's an example of some of the output you might see:

EQHXZ8M8AV|com.google.dfsfuse.filesystems.dfsfuse|1|Google, Inc.|8
In this example, EQHXZ8M8AV is the Team ID and com.google.dfsfuse.filesystems.dfsfuse is the bundle ID.

You can use Control-D to exit the sqlite3 session.

Acknowledgements: Got commands from Enabling Kernel Extensions in High Sierra

codesign

Another way is to run this command on an existing bundle from the vendor:

codesign -dv --verbose=4 /PATH/TO/NAMEOFBUNDLE.app

For example, if you run

codesign -dv --verbose=4 /Applications/Google\ Drive\ File\ Stream.app
you should see in the output a line like
TeamIdentifier=EQHXZ8M8AV

This approach can be helpful in fringe cases (you just need the Team ID and not the bundle ID, which may be the case, and the KEXT you're looking for has an associated bundle you can run codesign on.

Acknowledgements: Got command from MunkiReport-PHP extensions module

Isn't there a list somewhere of all these Team IDs?

There is a list, actually. There's a spreadsheet that a bunch of Mac admins are sharing with each other. Unfortunately, at this point, it's a spreadsheet that anyone with the link can edit, so I wouldn't really count on that. At this point, I don't see anything malicious in there (and I haven't verified every single Team ID, of course), but I would probably play it safe and just get the Team IDs yourself. Chances are that you'll have to do it only once or twice a year at the most.

Create a .mobileconfig profile for a certificate

If you want to create .mobileconfig profile from a certificate (for example, to import into Munki), you can use Apple Configurator 2 to do so.

If you have your certificate already in your keychain, launch up Keychain Access.app and find the certificate you want to make into a .mobileconfig profile.

Right-click the certificate and select Export NAMEOFTHECERTIFICATE (export it as a .cer).

Then launch up Apple Configuration 2.app.

Select File and then New Profile


Select Certificates and then Configure.

Find and select the certificate you exported earlier.

Select File and then Save.


Pick a filename for your .mobileconfig, which you can deploy however you want (as I previously mentioned, you can import this into a Munki repo).

When DEP nag won’t work but Setup Assistant will to enroll in your MDM

Explanation
Symptoms
Workaround
Automating
Other Considerations

Explanation

The two-days-later update: after doing troubleshooting with our MDM, asking around to other Mac admins, Google searching, and creating an enterprise case with Apple, I finally got back a definitive answer from Apple, which is that this functionality is essentially broken in Sierra (10.12.6). They're saying it should be fixed in High Sierra beta (10.13.4 right now). It makes a lot of sense. Almost all of our fleet is 10.12.6 (as of this writing, anyway), and the few computers that did work were on 10.13.2 or 10.13.3 (so not beta but still working).

So there you go. Either use the workaround below or upgrade to 10.13 if you're having this issue.

Symptoms

We have a bunch of computers that refuse to get a DEP (Device Enrollment Program) nag, even though they get the DEP prompt using Setup Assistant.

I tried blowing out a bunch of files and folders by following the Reset an enrollment section of How to troubleshoot your DEP/MDM Enrollments (on the MicroMDM blog but with generic instructions that can work for any MDM). That worked, but it requires you to go through the Setup Assistant.

I tried creating two fresh (never booted) AutoDMG-created images—one that skips the Setup Assistant and one that doesn't. If I don't skip the Setup Assistant, it obviously works. Here's the weird thing, though: if I do skip the Setup Assistant, then running

sudo profiles -N
doesn't work (skips to the next line in the terminal) and
sudo /usr/libexec/mdmclient dep nag
either gives me this error:
[ERROR] Unable to get activation record: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.ManagedClient.cloudconfigurationd" UserInfo={NSDebugDescription=connection to service named com.apple.ManagedClient.cloudconfigurationd}
or spits back the activation record dictionary (but with no actual nag appearing):
Activation record: {
AllowPairing = 0;
AwaitDeviceConfigured = 0;
ConfigurationURL = "https://mymdmsenrollmentsurl.com/withabunchofotherstuffattheend";
IsMDMUnremovable = 1;
IsMandatory = 1;
IsSupervised = 1;
OrganizationAddress = "Our Address";
OrganizationEmail = "Our email";
OrganizationMagic = someidentifier;
OrganizationName = "Our organization name";
OrganizationPhone = Our organization phone;
SkipSetup = (
Passcode,
Registration,
Location,
Restore,
AppleID,
TOS,
Biometric,
Payment,
Zoom,
Siri,
Diagnostics,
FileVault,
iCloudDiagnostics
);
}
Now, if I actually just delete the /var/db/.AppleSetupDone file at this point and then go through the Setup Assistant, the Mac will DEP-enroll into the MDM.

So there is no network issue here (I've also tested there being no network issue on these devices by temporarily tethering them to my phone to go outside of our school's firewall—same issue).

So I really have no idea what's going on here. My MDM has all of the log information and all of my tests and insists it's not a problem on their end, but it's not the network, and it's not the image (again, a freshly created never-booted image).

Workaround

So, as yet, I don't have a solution for this. Maybe I'm the only one experiencing this. I've asked around on the Mac Admins Slack, contacted my MDM directly, contacted our Apple rep directly, done a ton of Google searches. Seems a bit weird that it's just us with a never-booted image having issues on and off network.

There is good news, though. I don't have to do Setup Assistant for every single computer or do (much worse) a factory reset on each machine to DEP-enroll it (and, yes, we have a whole deployed fleet already that needs to be DEP-enrolled).

I found that if I take the ConfigurationURL from the activation record dictionary and just put that in Safari, it will download and try to install the MDM profile in a DEP way (not just in a non-DEP way).

So the only real missing piece is the actual notification that pops up. Notifications aren't blocked (again, on a never-booted AutoDMG-created image, why would they without some custom script explicitly doing so).

Update (18/02/08): At least one other person, using another MDM, has not found this to work. Safari just loads a blank page and doesn't download and install the enrollment profile. I'm using Mosyle, and this works for Mosyle at least, as of this writing.

Automating

If that works for you (putting the ConfigurationURL in Safari and installing the profile via System Preferences), you can try also automating the workaround by having the .mobileconfig delivered as a payload to /tmp and then running a script like this as a postinstall script:

#!/bin/bash

# Install profile
/usr/bin/profiles -I -F "$3"/tmp/NAMEOFDEPPROFILE.mobileconfig
Had to run the separate profiles command because Munki will not support managing enrollment profiles.

Other Considerations

You don't have to use Safari to go to the ConfigurationURL, but it's handy to do so, because Safari, after downloading the enrollment profile, will just launch up System Preferences and try to install the profile. If you use another browser (e.g., Chrome), it will just download the profile, and you'll have to open it to get it to launch System Preferences to prompt for an install.

Yes, you can also just enroll in the MDM without using DEP, but Apple—with High Sierra's APFS default and the iMac Pro's secure boot—is moving more toward making macOS like iOS, so it's possible that DEP-enrolled devices may be treated differently or have different functionality from non-DEP-enrolled (but still MDM'ed) devices. Probably safest to do a DEP-enroll into the MDM.