Scripting macOS, part 4: Running the Script

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 over the summer. Enjoy!

Running the Script

Now that we have the code for a functional (even though minimal) script, you can run it from the command line with:

> ./hello.sh

(Verify that the current directory is your script project folder.) You probably have wondered why you need the ./ before the script name. When you type the script name without the ./ it will fail:

> hello.sh
zsh: command not found: hello.sh

What does the ./ mean and why do we need it?

Current Working Directory

In the shell, the . character represents the current working directory or the directory that you ‘cd-ed’ to. Usually, the working directory is shown in the window title bar of Terminal and in the shell prompt (the status text shown before your cursor in the Terminal window). You can also have the system show your current working directory with the pwd command:

> pwd
/Users/armin/Projects/ScriptingMacOS

When you type ./hello.sh the shell will substitute the current working directory for the . character to get

/Users/armin/Projects/ScriptingMacOS/hello.sh

Your path will of course look different.

This means that when I use the ./hello.sh form, the shell knows exactly which file I want to execute and where to look for it. There is no ambiguity.

Now we know what the ./ means, but why is it necessary?

Finding Commands

A command you enter in the shell is just a string of text to begin with. The shell has to parse this text into pieces to determine what needs to be done.
We will use the chmod command from earlier as an example:

> chmod +x hello.sh

The text you entered is ‘chmod +x hello.sh’. The shell will split this text into pieces on the spaces (or tab characters). This will yield three elements:
chmod,’ ‘+x,’ and ‘hello.sh

The shell is only really interested in the first element. The shell will try to interpret the first element of your entry as a command.

Note: Many programming languages start counting at zero. This first element is also called ‘argument zero’ or $0.

The remaining elements are arguments, which the shell will pass on to the command. Arguments are optional. Not all commands require or even have arguments.

Note: This is a simplified description of the parsing process in shells. The reality is quite a bit more complex. But this description is ‘close enough’ for most situations. We will explore some of the nuances later.

If you are interested, you can get all the details in the shell’s documentation:

  • Zsh Documentation: Shell Grammar
  • bash man page, search for ‘Command Execution’

When there is a ‘/‘ character anywhere in the first element, the shell will interpret the first element as a full or relative path to an executable file and attempt to run that.

This is the behavior we are using when we type ./hello.sh. Since that contains a ‘/‘ the shell will resolve the path and execute our script.

We are intentionally using the seemingly redundant ./ prefix to tell the shell to run the script from the current working directory.

When the first element does not contain a ‘/,’ the shell will check if it is one of the following:

  • a shell function
  • a shell built-in command or reserved word
  • an external command

Shell Functions

Shell functions are (mainly) customized shell behavior declared by the user. They look and work like commands.

Note: If you are interested in customizing your shell environment, you can find details in my books “Moving to zsh” and “macOS Terminal and Shell.”

Shell Built-ins

Shell built-in commands cover tasks that are either inherent to the shell or can be performed much faster within the shell than as an external command. These are commands that affect the internal state of the current shell process like cd, alias, or history, or commands that are simpler and faster to implement as built-ins like echo or read.

You rarely need to worry about whether a command is a built-in.

Many built-in commands will have an executable external command file as well. This serves as a ‘fallback’ for the rare situation that the shell built-in is not available.

You can use the (aptly, but confusingly, named) command built-in to determine if a command is built-in or external:

> command -V cd
cd is a shell builtin
> command -V sw_vers
sw_vers is /usr/bin/sw_vers

External Commands

When the command entered is neither a function, nor a built-in, and does not contain a ‘/,’ then the shell will go search for an executable file with that name.

The PATH environment variable determines the locations in the file system and the order in which to search them.

The default PATH on macOS in an interactive shell is:

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

The PATH variable contains a colon-separated list of directories. When you have third-party software installed, or customized your shell configuration, your shell may have additional directories. The default PATH splits into the following five directories:

/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

Note: Variable names in the shell are case-sensitive. The variable names MY_VAR and my_var represent different variable and values.
Zsh, however, has the concept of ‘connected variables.’ In zsh, PATH and path are connected variables. The upper-case PATH contains the colon-separated list of directory paths, while the lower-case path is an array of paths. The actual list of directories will be the same and changing one variable will change the other. Zsh has this concept to maintain compatibility with other shells with the PATH, while also allowing you to use array operators on the path.
I will use the colon-separated PATH, because it is more compatible with other shells.

When a user enters a command like this:

> system_profiler

This is neither a function or alias, nor a built-in command. It also does not contain a ‘/.’

The shell will check for the presence of an executable file with the name system_profiler in all the directories given in the PATH. It will start with /usr/local/bin, then /usr/bin, then /bin, until it finally finds a matching file in /usr/sbin.

Then the shell will attempt to execute /usr/sbin/system_profiler.

When no matching files can be found in any of the directories listed in the PATH, the shell will present a ‘command not found’ error.

> cantFindMe
zsh: command not found: cantFindMe

If you are curious which file the shell will use for a given command you can use the command or the which tool:

> command -V system_profiler
system_profiler is /usr/sbin/system_profiler
> which system_profiler
/usr/sbin/system_profiler

PATH precedence

Once the shell finds a matching file, it will stop searching the remaining paths. If there were a second matching executable in /sbin, the shell would never find and execute it. The order of the directory paths given in the PATH variable determines the precedence.

We can test this by placing an executable with a file name matching an existing command in /usr/local/bin. Since /usr/local/bin comes first in the default interactive PATH, the shell should prefer our executable over the default command.

> sudo ditto hello.sh /usr/local/bin/system_profiler

You need administrator privileges to modify the contents of /usr/local/bin. The ditto command preserves all the file’s metadata (like privileges and extended attributes), which makes it preferable to cp for this task.

Then open a new Terminal window. You need to do this because every shell instance will cache or ‘remember’ the lookup for a command to speed up the process later. The shell instance in your current terminal window will remember the last lookup for the system_profiler command. A new Terminal window will start a new ‘fresh’ shell instance, forcing a new lookup:

> which system_profiler
/usr/local/bin/system_profiler
> system_profiler
Hello, World!

Obviously, overriding a system provided command this way can break your workflows and scripts. To be safe, remove our script from /usr/local/bin right away:

> sudo rm /usr/local/bin/system_profiler

There are some situations where overriding a system-provided command is desirable, though. For example, you could install the latest version of bash 5 as /usr/local/bin/bash. And then, when you invoke bash from your interactive terminal, you will launch that version, instead of the outdated version that comes with macOS.

Note: You cannot simply overwrite /bin/bash with the newer version on macOS. The /usr/bin, /bin, /usr/sbin, and /sbin folders are protected by System Integrity Protection and the read-only system volume.

When bash is invoked with the absolute path /bin/bash, the path will need to be updated to use the newer version, though. This includes the shebangs in scripts, and the UserShell attribute in a user’s account record for their default shell.

Extending your tool set

As you get more confident and experienced with scripting, you will assemble a set of scripts that you will use regularly. When you use a script often, it would be nice if the shell recognized them as commands, without having to type the path to them.

To achieve that you can add the directory containing the scripts to the PATH variable. I put my frequently used tools in ~/bin. The name is chosen to be somewhat consistent with the four standard locations for tools, but really does not matter. You can append your tool directory to the PATH with:

> export PATH=$PATH:~/bin

This reads as: replace the value of the environment variable PATH with its current value and append :~/bin. You can verify the new value with

> echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/armin/bin

We added our custom directory to the end of the PATH variable, so you cannot accidentally override system tools.

To prevent other local users from changing your command files, you should set the directory’s privileges, so that only you can access:

> chmod 700 ~/bin

Now you can copy our hello.sh script to that folder. We will rename it to just hello, so it looks more like a command:

> ditto hello.sh ~/bin/hello

Then you can run your script just by typing

> hello
Hello, World!

Most of the scripts you build will not need to be as accessible as this.

Since you do not want to manually change the PATH every time you create a new Terminal window, you should add this line to your shell configuration file:

export PATH=$PATH:~/bin

Context Matters

Leveraging PATH to find and possibly override commands can be a useful and powerful tool. However, when scripting, you have to always remember, that the interactive Terminal environment may not be the environment that your script will run in ‘production.’

This is especially important for scripts run by

  • LaunchDaemons or LaunchAgents
  • AppleScripts
  • applications other than Terminal (such as Xcode)
  • installer packages
  • management systems

When run from any of these environments, the environment the script runs in will be different from your interactive shell environment. Most likely the PATH in any of these environments will be set to the minimal four system folders:

/usr/bin:/bin:/usr/sbin:/sbin

This should work well for most commands and tools. But when you are working with third party software, especially newer versions, then you need to pay very close attention.

When you build scripts for these environments, I recommend setting the PATH at the beginning of your script explicitly to the value you need:

export PATH=/usr/bin:/bin:/usr/sbin:/sbin

When your scripts require tools, include their locations in the PATH. This way, the PATH environment is declared explicitly at the beginning of the script and there can be no confusion.

For the scripts in this series, the default PATH will be sufficient, so we will not need to worry about this.

Next: Lists of Commands

Scripting macOS, part 3: The Code

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 over the summer. Enjoy!

The Code

A script file is a text file with the executable bit set.

You can set the executable bit on any file. That alone does not turn it into a working script file. To get a working script file, the contents need to have the right structure or ‘syntax.’

Our example above is close to the minimum you need to have a working script file. We will look at the contents one line at a time.

#!/bin/zsh

# Greetings
echo "Hello, World!"

Shebang

The first line in our script is:

#!/bin/zsh

The first two characters #! form a special file signature or ‘magic number.’ They tell the shell and the system that this is not just any file, but a script file that should be interpreted.

These two characters have special names. The number sign is called the ‘hash’ and the exclamation mark is called the ‘bang.’ Together they are the ‘hashbang’ or the ‘shebang.’

The shebang characters have to be followed by the full path to the interpreter binary. There are no spaces in between the shebang characters and the interpreter path.

In this file, we have designated the zsh binary /bin/zsh.

When you type ./hello.sh to execute your script in Terminal, the shell will check if the file is executable. If it is executable, the shell will look at the first characters of the file. It ‘sees’ the shebang #! characters, and determines from them that this is a script file. Then it will read the rest of the first line to determine the interpreter. It will then hand over the entire script file to that interpreter binary.

This will have the same effect as running your script like this:

> /bin/zsh hello.sh

A new zsh process starts which reads and interprets the script file.

It does not matter which shell you use as your interactive shell. The shebang determines the interpreter for the script. That means you can run bash and sh scripts from zsh and vice versa.

When you are writing your scripts against sh or bash, you will have a shebang line of #!/bin/sh or #!/bin/bash, respectively.

The three shells are pre-installed as part of macOS and protected by System Integrity Protection and the read-only system volume. When you install newer versions of the interpreters, such as bash v5, then that binary will be in a different location. Most commonly /usr/local/bin.

If, for example, you have bash v5 installed as /usr/local/bin/bash, the shebang lines in the scripts that should use bash v5 will be:

#!/usr/local/bin/bash

When you then try to run these scripts on a mac that does not have bash v5 installed (or installed in a different location) then the scripts will fail.

> ./hello.sh
zsh: ./hello.sh: bad interpreter: /usr/local/bin/bash: no such file or directory

This can also happen when you run your script on a different platform. Even though the other platform may have the bash or zsh binary installed, it could be at a different path than on macOS. And the interpreter binary may be a different version than on macOS (especially with bash) which can lead to the script being interpreted differently.

For scripts that need to work in many different environments you will often see a shebang that uses the env command:

#!/usr/bin/env bash

The env command will use the current user’s environment, especially the PATH, to determine where the bash binary is and passes the script on to that. This will make your shebang more flexible, but you also give up some control as the environment will differ from system to system and from user to user.

For situations where you need control—such as management scripts—a fixed path for the shebang should be preferred, but then you also have ensure that the interpreter binary will be available at that path.

Whitespace

The line right after the shebang is empty. In shell scripts (and most other programming languages) empty lines are just ignored. Adding empty lines will make your code more readable.

Comments

The third line in our script starts with a number character or ‘hash.’

# Greetings

In shell scripts, lines that start with the hash character are ignored by the interpreter. You can and should use this to leave explanations and comments in your code.

Use comments in your code to leave explanations and notes.

echo Command

Now, finally, we will get to the actual code. The part of the script that does something.

echo "Hello, World!"

The echo command is one command that you rarely use in the interactive shell, but very frequently within scripts. It tells the shell to print (repeat or ‘echo’) text to the terminal’s output.

As usual in shells, the text we pass in to echo as an argument is ‘held together’ by quotes. This kind of text used in code is also called a ‘string’ because it is a ‘string of characters.’

Next: Running the Script

Scripting macOS, part 2: The Script File

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 over the summer. Enjoy!

The Script File

In the previous part, we created a text file and named it hello.sh. As we have mentioned before, all shell script files are text files.

File Extension

The file extension .sh is entirely optional. When you rename the file to merely hello it will remain a functional script:

> mv hello.sh hello
> ./hello
Hello, World!

When you use the script frequently as a command line tool, typing the additional .sh is cumbersome and does not ‘fit in’ very well with all the other command line tools. It is very common to remove the file extension in these cases.

However, the .sh file extension tells Finder and other applications what kind of file this is. You can assign the .sh file extension to be opened in your favored text editor when you double-click the file in Finder.

To do this, rename the file so it has the extension again:

> mv hello hello.sh

Then select the script file in Finder and open its Info panel (⌘I).

In the ‘General’ section of the info panel, you can see that Finder recognizes this file extension as a shell script.

In the ‘Open with’ section you can tell Finder which application to use to open this file. The popup list will show all applications you have installed that can open .sh files. Select your favorite text editor.

To tell the system to open all files with a .sh extension with your favorite text editor, click on the ‘Change All…’ button here. This will set your favorite text editor as the default application for the .sh file extension.

Some people like to use .bash and .zsh file extensions to further distinguish scripts written specifically in bash or zsh. While this can be useful in some workflows—especially when translating scripts from bash to zsh—it is generally not necessary. The .sh file extension works well for all these scripts. The .bash and .zsh file extensions are also not automatically recognized by the Finder or text editors as shell scripts.

Executable Bit

Aside from the actual script code, a shell script requires one more thing that distinguishes it from any other text file. You have to the tell the system that this file can be executed as a command.

This information is stored in the executable bit of the file privileges or file mode. You can see this information with the long form of the ls command:

> ls -l hello.sh 
-rwxr-xr-x@ 1 armin  staff  hello.sh

The file mode is displayed in the first ten characters in this output: -rwxr-xr-x.

The leading dash designates this item as a file. (A directory will show d, a symbolic link will show l, etc.)

The file access privileges are shown next. There are three sets of three flags or bits. The first three (in this case rwx) are the privileges for the file’s owner. The second set (r-x) are the privileges for group access and the last set (also r-x) shows the privileges for all other user on this system.

The three flags in each set are r, w, and x, in that order. They stand for read (r), write (w) and execute (x) and show the actions the users associated with each set can perform.

The file’s owner can read, write (or change), and execute (or run) this file. Users who are a member of the staff group, can read and execute this file, as well as every other user on this system.

Most documents and files merely contain text and data. The execute bit is not required. When you create a new file, the executable flag is disabled by default:

> touch newfile.txt
> ls -l newfile.txt
-rw-r--r--  1 armin  staff  newfile.txt

Having the execute bit disabled by default is a sensible security measure. You will have to explicitly enable it when building scripts or other executables.

When you are writing shell scripts, you eventually want to execute them. To do this you have to enable the execute bit. When then execute bit is unset, you cannot run the script from the command line.

To demonstrate this—and to gain some familiarity with the command line tools required to manipulate the file mode—disable the executable bit of our hello.sh script:

> chmod -x hello.sh

You can verify that the executable bit has been removed with the ls -l command:

> ls -l hello.sh
-rw-r--r--@ 1 armin  staff  45 Feb 17 14:36 hello.sh

When you now attempt to run the command, it will fail and the shell will tell you the reason: you do not have the right permissions. Without the executable script, your shell script is merely a text file.

> ./hello.sh
zsh: permission denied: ./hello.sh

You can re-set the executable bit with

> chmod +x hello.sh

You do not need write (w) permissions to execute a script, but you require read (r) permissions.

You can remove the executable privilege for group and/or other users for security. Since most Macs are used as single user systems this is not really relevant here. When you create, install, and run shell scripts on shared servers with other Unix or unix-like servers with many users, the proper access privileges may be extremely important. Please consult with the system administrator.

You will usually have to remember to set the executable bit when you create a new script. Some text editors may set it for you when they recognize you are working on a shell script.

Note: The executable bit has a different meaning for directories than it does for files. You can find the details in the chmod man page or in my book ‘macOS Terminal and Shell

Next: The Code

Weekly News Summary for Admins — 2021-07-23

Apple realeased iOS 14.7, with watchOS and tvOS updates as well. Later in the week, on Wednesday we got macOS 11.5 and iPadOS 14.7. iOS 14.7 brings support for the new battery pack. For MacAdmins, macOS 11.5 finally delivers an option to lock booting to Recovery and a device lock for Apple Silicon Macs.


(Sponsor: SentinelOne)

Bypassing macOS TCC User Privacy Protections By Accident and Design

For Mac Admins, TCC presents a host of challenges. Keeping users and admins productive can unexpectedly lead to undermining these protections. Learn about TCC ‘gotchas’, known bypasses and how to stay safe.

Continue reading on SentinelLabs


Anthony Reimer wrote a greate piece called “Recognition, Retirement, and Remembrance” which resonated with many other admins.

When I started out the news letter, the goal was to feature the work that so many people in the Apple Administrator community publish on their weblogs, social media, YouTube, podcasts, and open source repositories. It is really hard to keep track of everything that is going on when you are not a news junkie.

I love when people ping me on Slack to point out an interesting post (please keep them coming). I love it even more when someone sends me their first post on a new blog or their first post in a long time. (Congratulations!)

This discussion has made me even more aware of this role. When I curate the list of links I gathered over the week, I have always tried to be more inclusive, especially on the blog posts.

I have been working most of my professional career in or at least adjacent to the MacAdmin community. I have no comparison how this works in other professional communities. But this willingness to communicate and share, this notion of being in this together feels special.

This news letter would not exist without all you people willing to share their knowledge, experiences, and, yes, frustrations. You take time out of your work and volunteer it to the community, so that all our work, lives, and experiences become just a bit easier.

Thank you!


This news letter is going on vacation break! The next one will be sent out on August 27, 2021, with all the things that happened in the mean time.

So you still have something to read, I have scheduled a series of posts to be published on my website every week until I get back. The series is an excerpt from the first chapter of my upcoming book “Scripting macOS.” The first part is up already, I hope you like it!


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 and iOS Updates

Note: I am linking to the US support pages, as the updates may not have been published to all localized pages yet.

Reactions

MacAdmins on Twitter

  • Sören: “Want old-style proxy icons and a bigger grabbable title bar back? defaults write http://com.apple.finder NSWindowSupportsAutomaticInlineTitle -bool false and killall Finder!”
  • mikeymikey: “I don’t know who needs to hear this, but shift option double click on the corner of a window makes it fill the whole screen top to bottom and left to right without going fullscreen app (or triggering “zoom”, which never does what I want).”
  • Anthony Reimer: “You don’t need Shift from my experiments today. Double-click any window edge: window expands in that direction as far as possible. Double-click any window corner: window expands in 2 directions. Add Option key when double-clicking: opposite side(s) of window also expands.”

Security and Privacy

Support and HowTos

Updates and Releases

To Watch

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!

Scripting macOS, part 1: First Script

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 over the summer. Enjoy!

First Script

When learning programming languages it is tradition that the first program you write displays ‘Hello, World!’

Printing these words to the screen is usually a really simple task. In most programming languages it requires just a single line. Nevertheless, creating a simple program or script like this will teach you a lot about all the other tasks you need to create and run a script.

Before you start, you should create a folder where you store all the scripts you will create. A Documents subfolder is a good location. I have a Projects folder in my home directory where I create subfolders for all my scripting and programming projects. You may already have some structure like this that makes sense for you.

You can create this in Finder and the navigate there in Terminal. But, just to practice working in Terminal, you can create your script project folder in the command line:

> cd ~/Documents
> mkdir ScriptingMacOS
> cd ScriptingMacOS

Where- and however you create this folder, we will refer to it as your script project folder from now on. When you interact with the scripts from the command line, always remember to change the working directory there.

Note: When you know how to use a version control system to manage code, such as git, you can set up or initialize this project folder as repository now. Shell scripts are well suited to be managed with version control systems and I would recommend to use it when building scripts. But explaining the details of git as well as teaching shell scripting would be overwhelming and beyond the scope of this series.

Create your first script

Create a new text file in your favored text editor.

Note: If you do not have a favorite text editor yet, I recommend BBEdit. You can use it for free or pay the license fee to unlock the full feature set. After installing BBEdit, be sure to run ‘Install Command Line Tools…’ from the BBEdit menu.

I will be using the bbedit command line tools in my examples, but other text editors have similar commands.

When you are using a text editor with a command line tool, you can create a new empty file from the command line and open it in the text editor like this:

> bbedit hello.sh

Enter the following text into the text document:

#!/bin/zsh

# Greetings
echo "Hello, World!"

Tip: You can copy and paste the code from this post into the text editor. In general, I approve of this, since it speeds up the process and avoids typing errors. But in the beginning, I would recommend typing out the commands and modifying the script manually. This will engage your brain and memory differently and help you memorize some of the standard steps and commands.

Save the text file you created to a file named hello.sh in the script project folder.

In Terminal, ensure that the working directory is your script project folder. Then enter the following:

> chmod +x hello.sh

This will make your script file executable. You are telling the system this file has code that can be run as a program rather than just data. We will look at what this means in detail later.

Now you can run or execute your script:

> ./hello.sh
Hello, World!

If you get a different result, please verify that you typed the script exactly as given above. Pay extra attention to spaces, quotes and other special characters. Then save the text file and try running the script again:

> ./hello.sh
Hello, World!

Even for a script as simple as this, there is a lot that happened here. We will look at the pieces and steps in detail in the next part.

Next: The Script File

Suspicious Package Power User Features

As many MacAdmins, I work a lot with installer packages. You can say I wrote the book about it. When you get an installer package from some vendor website, you will want to inspect it before you install it anywhere, let alone deploy it to dozens, hundreds, or even thousands of Macs in your fleet.

You can use the pkgutil tool to do this in the command line, but there are package inspector tools with a graphical interface that are very useful and popular.

One of these tools is Suspicious Package from Mothers Ruin Software. It displays all of the content and resources of a pkg file in a very nice user interface. Many people love Suspicious Package from Mothers Ruin Software. I have always had reservations about Suspicious Package, though, because I thought there were a few missing features.

Update (August 2021): The app has gotten a new major update (4.0) which makes these “power user features” even more accessible!

The missing features were in connection with distinguishing “normal” or “component” packages (which have a single payload) from “distribution” or “meta” packages (which don’t have a payload of their own, but contain one or more component packages).

I have explained the differences in a bit more detail in my MacDevOps YVR presentation “The Encyclopedia of Packages” where I (once again, ignorantly) stated that you can’t really tell them apart in the UI of Suspicious Package.

After that presentation, Mat X, one of the organizers of the conference got me in touch with the developer of Suspicious Package, Randy Saldinger, who graciously and patiently demonstrated that I was wrong.

In my defense, you really cannot tell normal packages from distribution packages in the default configuration of Suspicious Package, but if I had bothered to read the manual and/or explore the Preferences window, I would have found this option:

This will show the Distribution xml file at the top of the list of the ‘All Scripts’ pane for distribution packages. When you see no Distribution file there, the package is a component package.

The second checkmark in that preference window is also very useful. With “Component package and bundle info” enabled you can see which component contains the selected file in the info pane:

You can also search in the “All Files” tab with command-F and use the component package ID as a search criteria.

All of this is already well enough to remove the reservations I have had on Suspicious Package. But Randy shared another preference with me which puts it over the top. It is not exposed in the UI (yet) but when you run:

% defaults write com.mothersruin.SuspiciousPackage ShowRawPackageInfo -bool YES

in Terminal and re-launch Suspicious Package, you will see the raw PackageInfo xml in the “All Scripts” tab. Together with showing the Distribution xml, this allows you to inspect all the raw metadata that can be inside a pkg file.

I have also learned that you can use the search functionality in the “Help” menu of Suspicious Package which will link directly to the online documentation. Not many apps leverage this functionality, so we often forget to check for it. Kudos to Suspicious Package for using this.

Many thanks to Randy for all his work and help and for providing an excellent tool! I am very much looking forward to the next version.

Weekly News Summary for Admins — 2021-07-16

In a break from our usual blogging, Anthony Reimer and I did a product review. He will explain the background and the tracking part, and I reviewed the receiving end.


(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!


And we got macOS 11.5 and iOS 14.7 release candidates, as well as macOS 12 and iOS 15 beta 3. Keep testing and feeding back!

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

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!

Installomator v0.6

We have posted an update for Installomator, which brings it to v0.6.

The changes are as follows:

  • several new and updated labels, for a total of 302
  • versionKey variable can be used to choose which Info.plist key to get the version from
  • an appCustomVersion() {} function can now be used in a label
  • with INSTALL=force, the script will not be using updateTool, but will reinstall instead
  • added quit and quit_kill options to NOTIFY
  • updated buildCaseStatement.sh
  • updated buildInstallomatorPkg.sh to use notarytool (requires Xcode 13)
  • several minor fixes

There have been some other organizational changes as well. We have moved the repo to its own team on GitHub: Installomator/Installomator. This should reflect that I am no longer the sole, or even the main contributor. Many thanks to Søren Theilgaard, Isaac Ordonez, and Adam Codega for helping maintain this!

And many thanks to everyone else who contributed!

An AirTag Adventure, Part 2—Receiving an AirTag

Anthony Reimer and I had a lot of fun sending an AirTag across the Atlantic. Now we get to the experience of being on the receiving side.

“AirTag Found Moving With You”

The “Find My” network warns you when an unknown AirTag is moving with you. This is to prevent tracking people without their approval. Since Anthony had registered the AirTag on his account to track its travel, this was a perfect opportunity to test this situation.

I just dropped the AirTag in the front pocket of my backpack and went about my business. This is the backpack I use to transport odds and ends, especially groceries, so it nearly always goes where I go. At first the backpack remained immobile in my house for the afternoon and then overnight. The next morning, we took a trip to the Leiden Farmers’ Market when I got the warning that an AirTag was moving with me.

It is interesting (but makes sense) that the warning didn’t come until I actually started moving with the AirTag. The tag is not really tracking you when it is just sitting around. But once I was on the go (together with the “strange” AirTag) I was warned fairly quickly: after about 2.5 hours. My wife also got the same warning on her iPhone, which should not be surprising, since we were walking together.

The AirTag is supposed to eventually make a sound when it is separated from its owner, but it never got to that phase in our testing, or I did not hear it.

The iPhone showed me a map where my iPhone had detected the “strange” AirTag and offered the option to play a sound on the AirTag to help locate it. Presumably, when someone tracks you without your knowledge, the AirTag would be hidden somewhere nearby and the sound will help you find it.

You can tell your phone to ignore this particular AirTag, presumably after you have checked with your companions who are travelling with you or because you are carrying a borrowed, tagged item.

The app also shows the serial number of the AirTag and the last four digits of the phone number it is registered to. These digits should allow you to identify the owner, when you know them, but maintain their anonymity when you don’t.

You can also get instructions to disable the AirTag. This will show instructions to open it and remove the battery with a simple but effective animation. (AirTags open real easy, given how small they are and how solidly sealed they seem when closed. This is really impressive engineering.)

I can see a possible downside here. The disabling process requires you to actually find the AirTag. If someone manages to hide the AirTag in way that you cannot find or access it physically, you cannot disable it. This might be harder than I imagine, because shielding the AirTag in a way that muffles the sound sufficiently might also shield the Bluetooth transmissions, which prevent the tracking in the first place. More experimentation will be needed here.

Lost Mode

Now that the covert tracking had been tested, Anthony set the AirTag to lost mode on his account. It took a few minutes for that change to propagate through the network. With lost mode enabled, I could call up his contact information (the owner can choose whether to show an email or the phone number) from the AirTag on my phone, just by tapping my phone to the AirTag.

Anthony also tried to play a sound on the AirTag, which was more than 7000km away from him. This did not work. It seems that playing the sound requires a local bluetooth connection to the AirTag. Since you would likely not be able to hear the sound when you are out of bluetooth range, and could use this to ‘terrorize’ someone (intentionally or not) in the middle of the night, I think this a reasonable limitation.

Transferring the AirTag

With all our testing done it was time for Anthony to remove the AirTag from his account, so that I could add it to my account. The interface for that in the Find My application is very straightforward.

He did, however, get an error that the iPhone could not “find” the AirTag. We presume his iPhone tried to connect to the AirTag over local bluetooth to let it “know” it was removed.

After Anthony had removed the device from his account, I tried to set it up on mine. This did not immediately work. Even after waiting for a few hours, my phone would not recognize the AirTag as new.

I then followed the instructions in this support article to reset the AirTag. It’s a bit tedious as you have to remove and replace the battery five times in a row. I figured out you don’t have to actually close the lid five times, just taking out the battery and putting it back in its place is sufficient. (there are magnets in the AirTag that seem to hold the batttery in place) After the reset process, the AirTag appeared immediately for setup on my phone and I could add it to my iCloud account.

Conclusion

Overall, the user experience for both the “Moving with you” and “Lost Mode” workflows are well thought through and kept clear and simple. Apple has good support articles for reference.

Many thanks to the comittee of MacDeployment and their sponsors that provided AirTags to all the speakers. And thanks to Anthony, who was game when I suggested that sending and tracking an AirTag across the Atlantic would be the “most fun” way to get them to me. Hope you found our experiments interesting, as well!

Right now, the AirTag has returned to my backpack. This seems reasonable since it stores my wallet and keys when I leave the house. I also want to test attaching an AirTag to my bike. I believe that bike thieves will quickly catch on to AirTags, so I don’t have high hopes for it to be useful as theft prevention. But an AirTag on the bike should be very useful to find my bike again in one of the typical Dutch bike parking areas among thousands of other bikes.

Scripting OS X — Weekly News Summary for Admins — 2021-07-09

Summer doldrums are here! This is a good thing, because it gives us MacAdmins more time to test the upcoming betas. You are testing and providing feedback, right?

Since I mentioned betas, macOS 11.5 and iOS 14.7 beta5 came out this week, as well!


(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!


In other news, I got my second Corona vaccination shot today. Hooray for science and technology! You might enjoy imagining this newsletter getting loopier and loopier as I progress into immune reaction stupor… 😉

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

MacAdmins on Twitter

  • mikeymikey: “Take the amount of time it would take to manually install and configure critical apps and tools for an employee role and multiply it out by how much of their payroll you’d be wasting without IT ensuring it’s in self-service”

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!