Manage the Look of Launchpad

You can control the number of columns and rows in LaunchPad. To do so, edit the defaults domain with the key springboard-rows for the number of rows to display and springboard-columns to control the number of columns displayed. So to set the number of rows LaunchPad will show per screen, send the write verb into defaults for along with the springboard-rows and an -int of 4:

defaults write springboard-rows -int 4

Likewise, to set columns to 8:

defaults write springboard-columns -int 8

Then just killall for Dock:

killall Dock

In some cases you will also need to send a resetlaunchpad boolean into (for TRUE) along with a killall for Dock (or reboot):

defaults write resetlaunchpad -bool TRUE; killall Dock

Setup Google Cloud Functions

Google Cloud Functions provide a streamlined method for running a simple micro-service leveraging custom functions as well as SDKs for any Google service that can be imported into your script. Currently, node.js is the only non-beta language you can build scripts in.


Before you setup Google Cloud Functions in your G Suite domain, first provide the account of a developer with the appropriate permissions, identified in the attached screen. 

Enable The SDKs You Need

G Suite has a number of features exposed to their API by importing SDKs into projects. As an example, the Admin SDK provides us with endpoints and classes that make developing micro services to perform actions in the G Suite admin portal easier. In this section we’ll import that SDK, although the tasks for importing other SDKs is similar. 

To get started, open the Google Cloud Platform using the button in the upper left hand corner and click on APIs and Services (the names of these buttons change over time).

TheClick on the Enable APIs and Services button in the dashboard.

Under Credentials, provide the appropriate credentials for the app you’re importing the SDK into.

Search for Admin SDK in the search dialog.

Click Admin SDK, made by Google.

Click Enable.

Once enabled, you’ll need to create a service account for your function to communicate with.

Setup A Service Account

Service accounts give you a JWT, useful to authenticate from a Google Cloud Function back to an instance of the GSuite Admin portal endpoints. To setup a Service account, go to “IAM & admin” using the button in the upper left hand corner. 

Click on Services Accounts.

Provide a project name and a location (if your organization uses locations, otherwise leave that set to No Organization.

Create Your Google Cloud Function

The Google Cloud Function is the microservice that you can then call. This might be sending some json from an app to perform a task from an app, or sending a webhook to the function to perform an action. To get started with functions, click Cloud Function at the bottom of the Google Cloud Platform dashboard.

If functions aren’t enabled, click Enable Billing.

If necessary, click UPGRADE.

The function api will also need to be enabled; if so, click Enable API.

Once all of this is done, you should have a button that says Create function. Click that and then you’ll be able to provide settings for the function.

Settings include the following:

  • Name: How the function is called in the admin panel. 
  • Memory allocated: How much memory the function can consume.
  • Trigger: Most will use HTTP for our purposes.
  • URL: The URL you use to call the function. 
  • Source: The code (typically node.js) that is run.

Note: The package.json allows for us to leverage this function in a multi-tenant fashion. 

Once enabled, you can hit the endpoint. If there’s no header parameters you need to send, that could be as simple as:



A framework is a type of bundle that packages dynamic shared libraries with the resources that the library requires, including files (nibs and images), localized strings, header files, and maybe documentation. The .framework is an Apple structure that contains all of the files that make up a framework.

Frameworks are stored in the following location (where the * is the name of an app or framework):

  • /Applications/*contents/Frameworks
  • /Library/*/
  • /Library/Application Support/*/*.app/Contents/
  • /Library/Developer/CommandLineTools/
  • /Library/Developer/
  • /Library/Frameworks
  • /Library/Printers/
  • /System/iOSSupport/System/Library/PrivateFrameworks
  • /System/iOSSupport/System/Library/Frameworks
  • /System/Library/CoreServices
  • /System/Library/Frameworks
  • /System/Library/PrivateFrameworks
  • /usr/local/Frameworks 

If you just browse through these directories, you’ll see so many things you can use in apps. You can easily add an import followed by the name in your view controllers in Swift. For example, in /System/Library/Frameworks you’ll find the Foundation.framework. Foundation is pretty common as it contains a number of APIs such as NSObject (NSDate, NSString, and NSDateFormatter). 

You can import this into a script using the following line:

import Foundation

As with importing frameworks/modules/whatever (according to the language) – you can then consume the methods/variables/etc in your code (e.g.  let url = NSURL(fileURLWithPath: “names.plist”).

A couple one-liners for analyzing Mac app usage

Reporting on application usage is an interesting topic on the Mac. This is done automatically with a number of device management solutions. But there are things built into the OS that can help as well.

mdls "/Applications/" -name kMDItemLastUsedDate | awk '{print $3}'

Now, if you happen to also need the time, simply add ,$4 to the end of your awk print so you can see the next position, which is the time. Additionally, a simple one-liner to grab the foreground app via AppleScript is:

osascript -e 'tell application "System Events"' -e 'set frontApp to name of first application process whose frontmost is true' -e 'end tell'

That’s pretty much all I had to say about that.

A Service-By-Service Guide For Moving Away From macOS Server

I’ve been making guides to macOS Server since Server 2:
And along the way, I’ve also sold plenty of books on Mac Servers and gotten a lot of opportunities I might not have gotten otherwise. So thank you to everyone for joining me on that journey. After teaching so many how to use the services that Apple made available in their server operating system, when they announced they’d no longer be making many of the services my readers have grown dependent upon, I decided to start working on a guide on moving away from macOS Server. 
And then there are tons of all-in-one small business servers solutions, including Buffalo, Qnap, NetGear’s ReadyNAS, Thecus, LaCie, Seagate BlackArmor, and Synology. Because I happen to have a Synology, let’s look at setting up the same services we had in macOS Server, but on a cheaper Synology appliance:

Using Apple’s Built-In Malware Removal Tool (MRT)

macOS now comes with a vulnerability scanner called mrt. It’s installed within the bundle in /System/Library/CoreServices/ and while it doesn’t currently have a lot that it can do – it does protect against the various bad stuff that is actually available for the Mac. To use mrt, simply run the binary with a -a flag for agent and then a -r flag along with the path to run it against. For example, let’s say you run a launchctl command to list LaunchDaemons and LaunchAgents running:

launchctl list

And you see something that starts with Let me assure you that nothing should ever start with that. So you can scan it using the following command: 

sudo /System/Library/CoreServices/ -a -r ~/Library/LaunchAgents/

What happens next is that the bad thing you’re scanning for will be checked to see if it matches a known hash from MRT or from /System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.yara and the file will be removed if so. 

A clean output will look like the following:

2018-09-24 21:19:32.036 mrt[48924:4256323] Running as agent

2018-09-24 21:19:32.136 mrt[48924:4256323] Agent finished.

2018-09-24 21:19:32.136 mrt[48924:4256323] Finished MRT run

Note: Yara rules are documented at For a brief explanation of the json you see in those yara rules, see

So you might be saying “but a user would have had to a username and password for it to run.” And you would be correct. But XProtect protects against 247 file hashes that include about 90 variants of threats. Those are threats that APPLE has acknowledged. And most malware is a numbers game. Get enough people to click on that phishing email about their iTunes account or install that Safari extension or whatever and you can start sending things from their computers to further the cause. But since users have to accept things as they come in through Gatekeeper, let’s look at what was allowed.

To see a list of hashes that have been allowed:

spctl --list

When you allow an app via spctl the act of doing so is stored in a table in 

sudo sqlite3 /var/db/SystemPolicy

Then run .schema to see the structure of tables, etc. These include feature, authority, sequence, and object which contains hashes.

On the flip side, you can search for the attribute set to

xattr -d -r ~/Downloads

And to view the signature used on an app, use codesign:

codesign -dv

To sign a package:

productbuild --distribution mycoolpackage.dist --sign MYSUPERSECRETIDENTITY mycoolpackage.pkg

To sign a dmg:

codesign -s MYSUPERSECRETIDENTITY mycooldmg.dmg

However, in my tests, codesign is used to manage signatures and sign, spctl only checks things with valid developer IDs and spctl checks items downloaded from the App Store. None of these allow for validating a file that has been brought into the computer otherwise (e.g. through a file share). 

Additionally, I see people disable Gatekeeper frequently, which is done by disabling LSQuarantine directly:

defaults write LSQuarantine -bool NO

And/or via spctl:

spctl --master-disable

Likewise, mrt is running somewhat resource intensive at the moment and simply moving the binary out of the directory will effectively disable it for now if you’re one of the people impacted.