Working at Jamf…

On a personal note: today is my first day working at Jamf as a Consulting Engineer.

I have been working with Jamf for more than a decade. Back then it was called Casper. Over the years, I have experienced the product and the company as a partner, as a customer and admin, and as a consultant. Working from the inside seemed like a logical next step. I will be joining a great team where I already know many people and I am looking forward to getting to know everyone else!

But don’t be afraid, this weblog and the weekly newsletter will continue as usual!

Weekly News Summary for Admins — 2021-09-17

So, we got a surprise update this week. macOS 11.6 and iOS 14.8 and despite the version numbers it does look as if they are “merely” security updates. They patch fairly serious vulnerabilities and there seem to be no other fixes or features, but the version numbering seems odd for a security update.


(Sponsor: Mosyle)

The Fusion of Apple MDM, Identity, Patching & Security.

Mosyle Fuse logo

Mosyle Fuse is the first and only product to bring a perfect blend of an Enterprise-grade MDM, an innovative solution for macOS Identity Management, automated application installation and patching, and purpose-built multi-layer endpoint security, all specially designed for Apple devices used at work at a price point that’s almost unexplainable.

Click here to learn more!


Even worse, there was no full installer, even after waiting a day or so. At first the communication from Apple was that there would be no full installer. This is problematic because the full installer is the best or only way to automate updates on Big Sur. Surprisingly, that message changed, “due to overwhelming feedback.” So great job on the feedback, everyone! (And keep providing it through all your available channels.)

Also in security, a malware-laden version of iTerm2 appeared this week. Apple has since revoked the certificate in question and most Malware tools should recognize it. This is a reminder that it can be fairly easy to be tricked into installing something malevolent.

Oh, and yes, there was an Apple Event with new iPhones, Watch, and iPads. Is it weird that the new iPad mini excites me most!?

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

News and Opinion

macOS 12 Monterey and iOS 15

macOS and iOS Updates

MacAdmins on Twitter

  • Darren Wallace: “TIL if you have two Jamf Pro instances linked to the same Intune instance, and enrol a device fully via Jamf Pro ‘A’ you need to trash the computer record in Jamf Pro ‘A’ before you can register the device in Intune properly through Jamf Pro ‘B'”
  • Peter Bukowinski: “Working in a remote shell with a tool that writes binary files (e.g. tcpdump) and don’t have an easy way to transfer files locally? bzip2 -9 filename; base64 filename.bz2 Copy the resulting text. Then in a local shell, echo "[PASTED_TEXT]" | base64 -d > filename.bz2
  • Howard Oakley: “Also worth noting that, among others, SMB is updated from 3.6 to 3.6.1. How significant that might be is something Apple doesn’t seem to want to explain.”
  • Felipe Baez: “If you try installing an application that requires Rosetta on a M1 Mac, make sure you’re online otherwise you’ll get a very deceiving message from Apple. They should definitely rephrase that error.” (Image)
  • John Opdenakker: “The plural of regex is regrets.” (via Andrew Laurence)
  • Derek Parker: “I once read a tweet which explained tar commands in the form of two mnemonics: Need to untar? -xzf— “extract ze files” Need to tar? -czf— “compress ze files” And I think about it every single time I use tar. Wish I knew who to attribute this to, but it’s really great.”

Security and Privacy

Support and HowTos

Scripting and Automation

Apple Support

Updates and Releases

To Listen

Just for Fun

Support

If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!

If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!

Weekly News Summary for Admins — 2021-09-10

Quiet week… There was Labour Day in the US. Hope you all had a great and quiet week-end! I have also been distracted preparing my presentation for MacSysAdmin 2021.

Apple did announce their first event since WWDC for next week Sep 14! I guess everyone is holding their breath for this.


(Sponsor: Mosyle)

The Fusion of Apple MDM, Identity, Patching & Security.

Mosyle Fuse logo

Mosyle Fuse is the first and only product to bring a perfect blend of an Enterprise-grade MDM, an innovative solution for macOS Identity Management, automated application installation and patching, and purpose-built multi-layer endpoint security, all specially designed for Apple devices used at work at a price point that’s almost unexplainable.

Click here to learn more!


With the event next week, the release of the next major Apple OS upgrades is imminent and the beta season is coming to a close. (Though, not really. Apple will continue to release betas of the updates through out the year, some of which will add more new features, and Apple admins will should keep testing and filing feedback continously.) This year was a strange beta season, with a three week break in macOS releases, and an even longer break in Xcode releases. It will be interesting to see how this reflects in the timing of the releases. Remember, last year macOS 11 was not released until November.

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

macOS 12 Monterey and iOS 15

Security and Privacy

Support and HowTos

Scripting and Automation

Updates and Releases

To Listen

Just for Fun

Support

If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!

If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!

Weekly News Summary for Admins — 2021-09-03

It is September now, and we finally got Monterey beta 6!

It is unclear when exactly iOS 15 (and siblings) and macOS 12 Montery will be released, but it might be less than a month now. How is your testing and feedback going?


(Sponsor: Mosyle)

The Fusion of Apple MDM, Identity, Patching & Security.

Mosyle Fuse logo

Mosyle Fuse is the first and only product to bring a perfect blend of an Enterprise-grade MDM, an innovative solution for macOS Identity Management, automated application installation and patching, and purpose-built multi-layer endpoint security, all specially designed for Apple devices used at work at a price point that’s almost unexplainable.

Click here to learn more!


If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

News and Opinion

I moved the last post up to the news section, because I think it is very relevant for MacAdmins. The Mac App Store is still fundamentally broken for macOS developers and vendors, but also for MacAdmins. Managed deployment and updates through VPP (sorry, “Apps and Books”) is still fundamentally unreliable. There may be improvement in sight with the new declarative MDM, but it is still uncertain when that may roll out to all kinds of deployments and include App Store deployment.

Even when the actual deployment eventually becomes reliable, there are so many applications, like Fission, that are not available in the Mac App Store because of the restrictions, rules, and their seemingly arbitrary enforcement by Apple review. Other applications might be in the Mac App Store, but VPP (sigh… “Apps and Books”) cannot be used to purchase, manage, and deploy in-App-Purchases or App Store subscriptions.

There is certainly some “Catch 22” situation here. Since deployment through VPP (grrr… “Apps and Books) is so horrible, no-one is using it, so there is likely little feedback, and hence no resources are put towards it by Apple. But VP… “Apps and Books” is the only method to deploy apps to iOS, and there you cannot manage in-App-Purchases or subscriptions either.

Until these problems are fixed on the developer and the deployment side, the Mac App Store is not a valid tool for MacAdmin purposes.

The new features, fixes, and updates for macOS Monterey are encouraging that Apple is listening to the issues that MacAdmins have with Apple’s vision of deployment. But not everything is good yet, there is still a lot of improvements to be made.

macOS 12 Monterey and iOS 15

MacAdmins on Twitter

  • Thomas Reed: “We’re starting to see the inevitable angry customer support tickets from people wanting to know why “Malwarebytes” is blocking their legitimate software. (For those unaware, some old apps are causing this due to macOS no longer trusting an old certificate authority.)”
  • mikeymikey: “Important call out in beta 6 on Monterey for macadmins” (Installation of PAMs now require user authorization or PPPC-approval)

Security and Privacy

Support and HowTos

Scripting and Automation

Apple Support

Updates and Releases

To Listen

Support

If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!

If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!

Scripting macOS, part 7: Download and Install Firefox

This series is an excerpt from the first chapter of my upcoming book “Scripting macOS” which will teach you to use and create shell scripts on macOS.

I will publish one part every week. Enjoy!

Follow this blog or the Twitter account for updates on the book’s progress!

Download and Install Firefox

To further illustrate the progress from the idea of a workflow to a working script, let us look at another, more involved example.

To download and install the latest version of Firefox a user has to go to the Firefox website and download the latest version, which will come as a disk image (dmg) file. Then the user needs locate the dmg in the ~/Downloads folder and open it to mount the virtual disk image. Finally, they need to copy the Firefox application from the virtual disk to the Applications folder.

When we want to automate the task ‘Download and Install Firefox,’ we have the following steps:

  • download latest Firefox disk image
  • mount downloaded disk image
  • copy Firefox application to /Applications
  • unmount disk image

From this list of steps, we can build the first ‘frame’ of our script:

#!/bin/zsh

# Download Firefox
#
# downloads and installs the latest version of Firefox


# download latest Firefox disk image

# mount downloaded disk image

# copy Firefox application to /Applications

# unmount disk image

This breaks the workflow into smaller pieces, that we will now tackle individually.

Download from the Command Line

You can use the curl command to download data in the command line. The curl command is very complex and has many options. We will only discuss the few options that we require for our task here. As always, you can find a detailed description of the curl command and its options in the curl man page.

The URI to download the latest Firefox is
https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US

However, when you try to curl this URI, you only get the following:

> curl "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US"
<a href="https://download-installer.cdn.mozilla.net/pub/firefox/releases/86.0.1/mac/en-US/Firefox%2086.0.1.dmg">Found</a>.

This is a re-direction, that is commonly used to have a single URI, that is redirected to different final URIs, so that when the software updates, the same URI always returns the latest version.

We can tell curl to follow these redirections with the --location option.

By default, the curl command will output the download to standard out. To save the download to a file, we can use the --output option with a file name.

> curl --location "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US" --output Firefox.dmg

This command will download the latest Firefox disk image to a file named Firefox.dmg in your current working directory. We can use this as our first step:

#!/bin/zsh

# Download Firefox
#
# downloads and installs the latest version of Firefox


# download latest Firefox disk image
curl --location "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US" \
     --output Firefox.dmg

# mount downloaded disk image

# copy Firefox application to /Applications

# unmount disk image

Note: Like many other command line tools, curl has short and long options. The short options for –location and –output are -L and -o.
Short options are convenient in the interactive shell, as they save typing and reduce the potential for typos. But they are much less readable, and you usually have to look up their function in the documentation. For that reason, I recommend using the long, descriptive options in scripts.

Working with Disk Images

The command line tool to work with disk image (dmg) files on macOS is hdiutil. This is also a very powerful command with many verbs and options. You can find all the detail in the hdiutil man page.

To mount a disk image, use the attach verb:

> hdituil attach Firefox.dmg

This will output some information and mount the virtual disk. The last line ends with the path to the mounted virtual disk /Volumes/Firefox.

By default, you can see the mounted volume in Finder. We do not really need the disk image to appear in Finder while the script is running. We can suppress this behavior with the -nobrowse option.

Since we are only going to read from the disk image, we can tell hdiutil to mount the dmg in readonly mode with the -readonly option. This speeds things up a bit.

> hdiutil attach Firefox.dmg -nobrowse -readonly

You can unmount or eject the virtual disk with

> hdiutil detach -force /Volumes/Firefox

The -force option will unmount the disk image, even when another process is still using it.

Thehdiutil command covers two of our steps, so we can fill them in:

#!/bin/zsh

# Download Firefox
#
# downloads and installs the latest version of Firefox


# download latest Firefox disk image
curl --location "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US" \
     --output Firefox.dmg

# mount downloaded disk image
hdiutil attach Firefox.dmg -nobrowse -readonly

# copy Firefox application to /Applications

# unmount disk image
hdiutil detach /Volumes/Firefox -force

Copying the Application

When you manually install Firefox the disk image shows you a nice graphic that reminds you to drag the app to the Applications folder. Once the disk image is mounted, the cp command can be used to do this in the shell:

> cp -R /Volumes/Firefox/Firefox.app /Applications/

This provides the last missing step in our script:

#!/bin/zsh

# Download Firefox
#
# downloads and installs the latest version of Firefox


# download latest Firefox disk image
curl --location "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US" \
     --output Firefox.dmg

# mount downloaded disk image
hdiutil attach Firefox.dmg -nobrowse -readonly

# copy Firefox application to /Applications
echo "copying Firefox to /Applications"
cp -R /Volumes/Firefox/Firefox.app /Applications/

# unmount disk image
hdiutil detach /Volumes/Firefox/ -force

You can now test the script. If Firefox is running, you want to quit it before you run the script. You may also want to delete the existing copy of Firefox from the Applications folder, to be sure that your script is doing the work.

Lists of Commands—Conclusion

We have been able to automate a fairly complex workflow with a script of four commands.

To be perfectly honest, this script (as well as all the others we have built so far) is not complete yet.

A ‘proper’ script needs to be able to react to errors that occur. In our example, imagine the download fails. The script should be able to detect the failure before it overwrites the installed, functional Firefox application.

We will get to this kind of error handling later.

Nevertheless, this script is already useful in its current form. You can try to adapt this script to work with some other software you can download as a disk image.

You can also add extra commands that

  • delete the downloaded disk image at the end
  • open the newly installed Firefox app after installation
  • quit or kill the Firefox process before copying the new version

In the book “Scripting macOS”, you will learn more scripting techniques, and we will re-visit some of these sample scripts and keep improving them.

Follow this blog or the Twitter account for updates on the book’s progress!

Note: After using different variations of these kinds of workflows, I did put together a more generic script to download and install various kinds of software, called ‘Installomator.’ You can see the script at its open source repository on GitHub.

Suspicious Package 4.0 Update

I recently posted about some Suspicious Package Power User Features, which was a follow-up to my MacDevOps YVR presentation “The Encyclopedia of Packages.”

As a follow-up to that follow-up, Suspicious Package was updated to version 4.0 today. (Yesterday? Time zones are strange.) The update to brings compatibility with macOS Monterey and some really nice refinements to these power user features.

First and foremost, Suspicious Package will now show the kind of package, or “package format” in the Package Info tab. This makes me very happy, not just because the FAQ references my presentation. As the FAQ correctly states, most users of packages or even the Suspicious Package application will not care much about the differences between the package formats, but for system administrators, this can determine the difference between a functional deployment or a broken workflow.

The previously ‘secret’ option to show the PackageInfo xml file is now also exposed in the preferences window, next to the option to show the Distribution XML.

It is now also easier to search for the contents of a particular component in a distribution package.

You can download the latest version of Suspicious Package and get the update notes here.

Many thanks to Randy Saldinger of Mothers Ruin Software for providing this amazing tool and further refining it!

Randy was also recently a guest on the MacAdmins Podcast. You check it out if you have not yet listened to that episode.

Weekly News Summary for Admins — 2021-08-27

Welcome back! Hope you had a good vacation break.

While the news was slower than usual, a lot of great posts accumulated over five weeks, so this is a long news summary. Settle down for some extended reading.


(Sponsor: Mosyle)

Mosyle Fuse logo

The Fusion of Apple MDM, Identity, Patching & Security.

Mosyle Fuse is the first and only product to bring a perfect blend of an Enterprise-grade MDM, an innovative solution for macOS Identity Management, automated application installation and patching, and purpose-built multi-layer endpoint security, all specially designed for Apple devices used at work at a price point that’s almost unexplainable.

Click here to learn more!


(I learned that there is a limit to how many links you can add to a single note in Notes.app, which is where I gather the links for this newsletter. In case you are wondering, the limit is 100 links or “attachments” per note.)

The beta process continues. iOS 14 and siblings are now on beta 7. macOS 12 Monterey has stalled on beta5 for a while now. SharePlay has been pushed to a later update release. iCloud Private Relay will start with as a public beta in the fall. We also got some security updates for Big Sur, 11.5.1 and 11.5.2.

In case you missed it: I published an excerpt of my upcoming book “Scripting macOS” on my weblog as a series of posts over the break. You can catch up by starting at the first part: “First Script” (There will be one more installment next week.)

If you would rather get the weekly newsletter by email, you can subscribe to the Scripting OS X Weekly Newsletter here!! (Same content, delivered to your Inbox once a week.)

News and Opinion

macOS 12 Monterey and iOS 15

macOS and iOS Updates

MacAdmins on Twitter

  • Ryan Moon: “TIL about “Allow full disk access for remote users” and that solved the mystery of why I couldn’t access folders via SSH. A sneaky add to 11.5 that I hadn’t heard about previously.” (Image)
  • Ben Bajarin: “I have long held an Apple Mac in the enterprise growth story. Apple has slowly chipped away at barriers around deploying and managing Macs in the enterprise. With M1 Macs, Apple is better positioned than ever to grow Mac enterprise share.” (Thread)
  • Csaba Fitzl: “The most useful feature I learned this month: CMD+K in Terminal clears everything, including all output, it’s like opening a fresh, new shell.”
  • mikeymikey: “If you’re having RSA SecureID issues, please contact RSA via support contract & let them know their QtCore 5 bundled framework inside stauto32.framework is verifying a signature chain in QtCore.cire that passes through a Symantec CA- they need to update it” (Thread)

Security and Privacy

Support and HowTos

Scripting and Automation

Apple Support

Updates and Releases

To Listen

I will only link to those podcasts that I found most interesting over the past few weeks. Please lookup all missed episodes in your favored podcast application or on their websites.

Just for Fun

Support

If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!

If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!

Scripting macOS, part 6: Turn it off and on again

This series is an excerpt from the first chapter of my upcoming book “Scripting macOS” which will teach you to use and create shell scripts on macOS.

I will publish one part every week. Enjoy!

Turn it off an on again

A common strategy to solve problems with computers is ‘turning it off and on again.’ For example, when you have Wi-Fi connectivity problems, one of the first things you should try it to turn the Wi-Fi off, wait a few seconds, and then turn it on again.

Let’s write a script to do that.

Create the ‘frame’

When you start out writing a script, you will usually have only a vague idea of what needs to be done, and even less an idea of how to actually do it. In this case is helps to write out the steps that your script should perform:

  • turn off Wi-Fi
  • wait a few seconds
  • turn on Wi-Fi

With this list we have broken down the problem into smaller, more manageable steps, which we can each solve on their own.

I usually take this list of steps and build a script ‘frame’ from them:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi

# wait for a few seconds

# turn on Wi-Fi

We just copied our list of steps into the text file for our script and made them comments by adding the # character at the beginning of the line. We also added the shebang in the first line and two more comment lines at the beginning, which name the script and have short description on what it is supposed to do.

Since the script in this form only consists of the shebang and comments, it does nothing. But it provides a frame to fill in. Now we can tackle these steps one at a time.

Control Wi-Fi

When you want to control network related settings on macOS, the networksetup command is the first place you should look. The networksetup command allows you to configure the settings in the ‘Network’ pane in ‘System Preferences’— and a few more. The networksetup command has dozens of options. You can get a list and descriptions by running networksetup -help or in the networksetup man page.

To turn off Wi-Fi, you can use this option:

> networksetup -setairportpower <hwport> off

The value you need to use for <hwport> depends on what kind of Mac you are working on. For MacBooks, it will be en0 (unless you have a very old MacBook with a built-in ethernet port). For Macs with a single built-in ethernet port, it will be en1. For Macs with two built-in ethernet ports it will be en2.

You can also use the networksetup command to list all available hardware ports and their names:

> networksetup -listallhardwareports

Hardware Port: Wi-Fi
Device: en0
Ethernet Address: 12:34:56:78:9A:BC

Look for the Hardware Port named Wi-Fi. The value shown next to Device is the one you have to use. So, for me, on a MacBook, I will use:

> networksetup -setairportpower en0 off

We will use en0 in our sample script going forward. If your Wi-Fi port is different, remember to change it in your script going forward

Note: Apple used to brand Wi-Fi as ‘Airport’ and this naming still lingers in some parts of macOS. Changing networksetup’s options to match the new branding would break all existing scripts.

When you replace the off with on it will turn the Wi-Fi back on:

> networksetup -setairportpower en0 on

We have solved the first and third step for our script and tested them in the interactive shell. Now, we can fill them into our script frame:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi
networksetup -setairportpower en0 off 

# wait for a few seconds

# turn on Wi-Fi
networksetup -setairportpower en0 on

You can now save the script as reset_wifi.sh, set its executable bit and run it:

> chmod +x reset_wifi.sh
> ./reset_wifi.sh

This should already work. You should see the Wi-Fi icon in the dock switch to the animation indicating that it is re-connecting with your network.

Taking a break

We still want the script to ‘take a break’ and wait for a few seconds between the turning off and turning back on commands. This will allow other parts of system to ‘settle’ and react to the change.

In the shell you can use the sleep command to achieve this. It takes a single argument, the time in seconds it should pause before continuing:

> sleep 5

When you enter this command in the interactive shell, you should notice that it takes 5 seconds for the next prompt to appear. The sleep command is delaying progress for the given time.

When you watch the CPU load in Activity Monitor while you run the sleep command, you will not see a spike in load. The sleep command merely waits, letting other processes and the system do their thing.

Let us insert a ten second break into our script between the commands to turn Wi-Fi off and on:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again

# turn off Wi-Fi
networksetup -setairportpower en0 off 

# wait for ten seconds
sleep 10

# turn on Wi-Fi
networksetup -setairportpower en0 on

Now, when you run the script. You can see that Wi-Fi icon in the menu bar should switch to ‘disabled’ and then return to the ‘searching’ animation and eventually reconnect after ten seconds.

Feedback

While you are running this script, there is no feedback in the Terminal though. It just takes a disconcerting time for the prompt to return. We can add some output to let the user of the script know what is happening:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi
echo "Disabling Wi-Fi"
networksetup -setairportpower en0 off 

# wait for a ten seconds
echo "Waiting..."
sleep 10

# turn on Wi-Fi
networksetup -setairportpower en0 on
echo "Re-enabled Wi-Fi"

Now, the user will get some feedback in Terminal that lets them know what is going on.

>  ./reset_wifi.sh
Disabling Wi-Fi
Waiting...
Re-enabled Wi-Fi

Script Building Process

We formed an idea or a goal: ‘Turn Wi-Fi off and back on’

Then we described the steps necessary to achieve that goal:

  • turn off Wi-Fi
  • wait a few seconds
  • turn on Wi-Fi

We used these descriptive steps to create a frame or scaffolding script to ‘fill in’ with the proper commands.

Then we explored commands that would achieve these steps in the interactive terminal.

Once we determined the correct commands and options we placed them into our script ‘frame’ in the correct order.

As you add the commands, test whether the script shows the expected behavior.

Then we also added some output, to provide user feedback.

This is a really simple example script to illustrate this process. Nevertheless, we will re-visit these process steps with every script we build and you should follow this process (or a similar flow) when building your own scripts.

The process will not always be quite so clearly defined and you may have to iterate or repeat some of these tasks multiple times, before you find a combination of commands that do what you want. Less experienced scripters will naturally spend more time on ‘exploring commands.’ This is part of the normal learning process.

With larger, more complex scripts, each descriptive step may need to broken into even smaller sub-steps to manage the complexity. Again, experienced scripters will be able tackle more complex steps faster. Do not let that intimidate you when you are just beginning! Experience has to be built ‘the hard way’ by learning and doing.

In many situations you can learn from other people’s scripts that solve a similar problem. This is a well-proven learning strategy. I would still recommend to ‘explore’ the commands used in other people’s scripts before adding them to your scripts, as it will deepen your knowledge and experience with the commands. Sometimes, you may even be able to anticipate and avoid problems.

Next Post: Download and Install Firefox

Installomator v0.7b1 – Prerelease

We have posted a new version of Installomator. This one brings with it major changes in how we assemble the actual script. Since this is such a big change, we decided to do a beta release first.

The changes in detail:

  • script is now assembled from fragments. This helps avoid merging conflicts on git and allows the core team to work on the script logic while also accepting new labels. See the “Assemble Script ReadMe” for details.
  • Change in finding installed apps. We now look in /Applications and /Applications/Utilities first. If not found there, we use spotligt to find it. (We discovered a problem when a user has Parallels Windows installed with Microsoft Edge in it. Then Installomator wanted to update the app all the time, becaus spotligt found that Windows version of the app that Parallels created.)
  • Added bunch of new labels
  • Improved buildCaseStatement.sh a lot. It is a great start when figuring out how to create a new label for an app, or a piece of software.
  • Mosyle changed their app name from Business to Self-Service

Why the changes?

Since the Installomator.sh script has grown to over 3000 lines, its management on git has become very unwieldy. The single file with all the logic and the data required to download and install the applications creates constant merge conflicts which add to the workload of the repo admins, especially when part of the team is working on the logic of the script while we still get PRs to add labels.

Because of that we have split the main script into multiple files which are easier to manage. Having multiple files results in less merge conflicts.

What changes when I use the script?

Nothing. When you just use the Installomator.sh, you still copy its contents from the Installomator.sh script at the root of the repository into your management service (don’t forget to change the DEBUG value). Or you install the script to the clients using the installer pkg from the Releases.

The changes will only affect you when you want to build your own application labels, modify existing labels or other wise modify the script.

How do I build my own labels now?

This is where you need to learn about the new system. To reduce merge conflicts, we have broken the big Installomator.sh script into smaller pieces. There is a utility script that can assemble the script from the pieces and even run it right away fro testing. You can get the details in the “Assemble script ReadMe”

We hope that these changes will make it easier for the Installomator team and other contributors to keep growing and improving the script.

Scripting macOS, part 5: Lists of Commands

This series is an excerpt from the first chapter of my upcoming book “Scripting macOS” which will teach you to use and create shell scripts on macOS.

I will publish one part every week. Enjoy!

Beyond Hello, World

Now that you have a minimal working script, let’s extend it a bit.

Create a copy of the hello.sh script file, set its executable bit, and open it in your favored text editor:

> cp hello.sh hello_date.sh
> chmod +x hello_date.sh
> bbedit hello_date.sh

A script is a list of commands that the interpreter will process sequentially. Up to now, we only have a single command, the line with echo, in our script. We will add another one:

Change the text in the script file:

#!/bin/zsh

# Greetings
echo "Hello, World!"
date

We have added a line to the script with the date command.

If you are unfamiliar with this command, you can try it out in the interactive command line:

> date    
Tue Feb 23 10:23:05 CET 2021

When you invoke date with out any arguments it will print out the current date and time. The date command has many other functions for doing date and time calculations which we will not use right now, but you can read about in the date man page.

Save the modified script and execute it:

> ./hello_date.sh
Hello, World!
Tue Feb 23 10:27:06 CET 2021

As we can tell from the output, each command in the script was executed one after the other and the output of each command was shown in Terminal.

You can insert more echo commands before the date to make the output prettier:

#!/bin/zsh

# Greetings
echo "Hello, World!"

# print an empty line
echo

# print without line break
echo -n "Today is: "

date

As we have learned earlier, empty lines and lines starting with a # character will be ignored, but can serve to explain and clarify your code. I will be using comments in the example scripts for quick explanations of new commands or options.

Here I added the -n option to the third echo command. This option suppresses the new line character or line break that echo adds automatically at the end of the text. This will then result in the output of the date command to print right after the ‘Today is:’ label, rather than in a line of its own.

Take a look:

> ./hello_date.sh
Hello, World!

Today is: Tue Feb 23 10:30:44 CET 2021

The date command allows for changing the format of the date and time output. It uses the same formatting tokens as the C strftime (string format time) function. You can read the strftime man page for details. The %F format will print the output as ‘year-month-date:’

> date +%F
2021-02-23

You can combine place holders:

> date +"%A, %F"
Tuesday, 2021-02-23

You can experiment with the date formatting placeholders from the strftime man page in the interactive shell. Once you have built a formatter that you like, you can add it to the date command in your script.

#!/bin/zsh

# Greetings
echo "Hello, World!"

# print an empty line
echo

# print without line break
echo -n "Today is: "

date +"%A, %B %d"

It is very common that you will test and iterate a command and arguments in the interactive shell before you add or insert it into your script. This can be a much easier and safer means of testing variations of commands and options than changing and saving the entire script and running it repeatedly.

Scripts are basically ‘lists of commands.’ Once you know the steps to perform a workflow in the interactive terminal, you can start building a script. Let’s look at another example.

Desktop Picture Installer

When you copy an image file to /Library/Desktop Pictures, it will appear in the list of pictures in the ‘Desktop & Screen Saver’ pane in System Preferences. On macOS 10.15 Catalina and higher you may have to create that directory.

You can easily build an installer package (pkg file) that installs an image file into that location with the pkgbuild command.

First, create a directory to hold all the sub-directories files we will need. There needs to be a payload directory in the project directory. Copy the image file into the payload directory:

> mkdir BoringDesktop
> cd BoringDesktop
> mkdir payload
> cp /path/to/BoringBlueDesktop.png payload

You can then build an installer package with the following command:

> pkgbuild --root payload --install-location "/Library/Desktop Pictures/" --identifier blog.scripting.BoringBlueDesktop --version 1.0 BoringDesktop-1.0.pkg
pkgbuild: Inferring bundle components from contents of payload
pkgbuild: Wrote package to BoringDesktop-1.0.pkg

This will create a file BoringDesktop-1.0.pkg. When you double-click this file, it will open the Installer application and, when you proceed with the installation, put the image file in /Library/Desktop Pictures.

Note: To learn more about using and building installer package files for macOS, read my book “Packaging for Apple Administrators.”

The pkgbuild command has a lot of arguments and when you get any of them just slightly wrong, it may affect how the installer package works. This is a very simple example, but when you build more complex installer packages, you may be building and re-building many times and you want to avoid errors due to typos.

We can copy this big command and place it in a script file:

#!/bin/zsh
pkgbuild --root payload --install-location "/Library/Desktop Pictures/" --identifier blog.scripting.BoringBlueDesktop --version 1.0 BoringDesktop-1.0.pkg

Then make the script file executable:

> chmod +x buildBoringDesktopPkg.sh

Now you can just run the script and not worry about getting the arguments ‘just right.’

But we can go one step further and make the script more readable. We can add a comment describing what the script does.

The shell usually assumes the line break to be the end of the command. But when you place a single backslash \ as the last character in a line, the shell will continue reading the command in the next line. That way, you can break this long, difficult to read command into multiple lines:

#!/bin/zsh

# builds the pkg in the current directory

pkgbuild --root payload \
         --install-location "/Library/Desktop Pictures/" \
         --identifier blog.scripting.BoringBlueDesktop \
         --version 1.0 \
         BoringDesktop-1.0.pkg

The arguments are now more readable. When you want to change one of the values, e.g. the version, it is easier to locate.

Even though this script only contains a single command, it improves the workflow significantly, as you do not have to remember a long complex command with many arguments.

Of course, you can copy and modify this script for other package building projects.

Next Post: Turning it off an on again