Get the “Marketing Name” for a Mac

I am working on making our onboarding/installation process nicer. For that I decided it would be nice for SplashBuddy to say “Welcome to your ’MacBook (Air|Pro)/iMac/Mac (mini|Pro)”.

You can get the Mac model name easily enough from System Profiler:

$ system_profiler SPHardwareDataType
Hardware:
    Hardware Overview:
      Model Name: MacBook Pro
      Model Identifier: MacBookPro14,3

However, this is only the “model family.” When you go into “About this Mac” it give you a more detailed “name” like “MacBook Pro (15-inch, 2017).”

Friendly people on the MacAdmins Slack pointed me towards a property list file in the ServerInformation framework:

/System/Library/PrivateFrameworks/ServerInformation.framework/Resources/English.lproj/SIMachineAttributes.plist

This contains the “Marketing Model Name” among other information for each type of Mac, sorted by the model identifier, which you can also get from system_profiler or with sysctl -n hw.model. Even better this plist is localized, so you can get the marketing name in the current user’s preferred language.

The easiest way to get the correct localization is to use the system’s NSBundle class and methods and the read the property list. I chose Python to do this, since it offers access to NSBundle with the Cocoa-bridge and reading and working with property lists is very easy. (Learn more about working with property lists in Python in my book: ‘Property Lists, Preferences and Profiles for Apple Administrators’)

You can run this script with a parameter:

$ ./modelinfo.py MacBookAir7,2
13" MacBook Air (Early 2015)

When you don’t give a parameter, it will use sysctl -n hw.model to determine the current Mac’s model identifier and use that:

$ ./modelinfo.py
15" MacBook Pro with Thunderbolt 3 and Touch ID (Mid 2017)

Since the script uses NSBundle and does not go directly to a specific localization of the property list file, it will give different language results depending on the preferred language of the user:

$ ./modelinfo.py     # (Dutch)
15-inch MacBook Pro met Thunderbolt 3 en Touch ID (medio 2017)

$ ./modelinfo.py     # (Japanese)
15インチMacBook Pro、Touch Barを搭載(Mid 2017)

Imaging is Dead… Long Live the Installer!

The writing has been on the wall for a long time. With the release of macOS High Sierra, Apple has finally confirmed that imaging is dead.

Apple doesn’t recommend or support monolithic system imaging for macOS upgrades.

The Final Nail

The final nail in the coffin for imaging is this support article: Upgrade macOS on a Mac at your institution

It states the limitations to installing and upgrading macOS with High Sierra:

  • the Mac being installed or updated must be connected to the internet
  • installations and updates cannot be done on external devices, like those connected via Target Disk Mode, Thunderbolt, USB, or Firewire
  • there are four supported methods of installing macOS High Sierra

These methods are also re-iterated in this section in the macOS Deployment Reference

Why?

Apple’s stated reason for requiring the installer is to ensure that a Mac’s firmware is all up to date and matches the OS installed on it.

Only the macOS Installer can download and install the firmware update. Firmware updates can’t be done on external devices, like those connected via Target Disk Mode, Thunderbolt, USB, or Firewire.

This is especially important in High Sierra, because to boot into a system on an APFS formatted (or converted disk) the Mac’s firmware needs to be able to mount and read APFS. The firmware that was installed with 10.12 or earlier is not able to read APFS volumes and. When you image a Mac with High Sierra and APFS without updating the firmware, you will get the question mark at boot, because the firmware cannot find a system.

However, the EFI, which manages (among other things) the boot process is not the only “firmware” that needs to be managed on your Mac. Many of the hardware components in your Mac, such as the SSD, the power controller (SMC) and the TouchBar controller on the new MacBooks Pro, have their own firmware that needs to be installed and updated.

Apple has been increasing the protection of the vital parts of the system and hardware. The firmware in these components cannot just be changed by any process. Only the Apple macOS Installer application has sufficient privileges and entitlements to perform these updates. The installer process has to run on the Mac itself, it cannot run over target disk mode.

Future Mac hardware might introduce even more components that require firmware.

On iOS, a secure boot chain prevents tampering with the system on a device after it has been installed. The secure boot chain also prevents replacing the system with an image from another device.

It is conceivable that Apple wants to implement a secure boot system on future Macs as well. Current Macs probably do not have the hardware required to implement this. (The TouchBar MacBooks Pro have a Secure Enclave chip like the iPhone and iPad and might already have the necessary pieces in place.)

So now what?

This has been coming for a long time. Even though APFS is not, as originally predicted, the direct culprit. It is still end-of-the-line for imaging.

However, the news is not entirely dire. Apple has been surprisingly forthright about the direction they want to go. While the documentation is a bit lacking, there are instructions on what the solutions for Mac System Adminstrators should be.

The four supported means of installing and upgrading macOS and the firmware for Macs are a clear direction of what needs to be done. However, Apple is a bit shy on how administrators can and should implement them.

There are a few options:

Put the Burden on the Users

This will work in some deployments where users are in control of their Macs. Either a full BYOD (Bring Your Own Device) scenario, or one where devices provided by the organisation are in full control of the user.

Even when the devices are enrolled in an MDM, users are still administrators and in control. Administrators can use reporting tools, to determine which Macs are capable of installing High Sierra and not upgraded yet.

You can even use reporting tools to gather information on the firmware and whether it matches the latest version.

You can then instruct users with email or notifications to download the High Sierra installer and initiate the upgrade themselves. You should warn them to have a current backup and that the process might take some time, so it should be run overnight.

If you have a software management system in place, you can use that to load the macOS Installer application on the clients and notify the user when it is ready.

The Mac App Store only downloads a “stub” installer application which is then filled in with an extra download. If you have blocked access to Apple Software Update Servers or redirected clients to a local, managed Software Update Server, clients might not get the complete installer application. Greg Neagle has a great post on this.

To save download time for the users, you can also provide USB/Thunderbolt drives with a bootable installer drive. This might speed things up a bit, though it does not really change the process.

How do we Automate this?

As system administrators we want to automate the process, so that it ideally does not require any human interaction. That way we can replicate the process hundreds and thousands of times.

Ideally, we also want to inject some custom steps into the process. Apple provides two means of achieving both of these steps, and some open source tools are providing solutions as well.

NetInstall

A custom NetInstall set built with Apple’s System Image Utility is one of the supported means of installing and updating macOS (and the firmware) to High Sierra.

You can find System Image Utility in /System/Library/CoreService/Applications. You can customize the process and even add your own installer packages, scripts or profiles. Packages used in System Image Utility have to be Distribution Packages.

Since a NetInstall system is like a Recovery system, you can use scripts to control behavior of your Mac like allowed NetBoot IPs, or ‘User-Approved Kernel Extension Loading’ (UAKEL) here as well.

You can even automate the NetInstall process to a point where, once you have chosen the NetInstall volume (when holding the the option key at boot) the remaining process is without interaction. (Though this is a dangerous choice, as it might simply wipe and re-install Macs. Use the other limitation options such as by MAC address or hardware type to keep this safe.)

NetInstall requires Mac running macOS Server. However, BSDPy can replace a NetBoot/NetInstall server and runs on many platforms, including VMs.

Note: as of 10.13.0 there still seem to be a few bugs with NetInstall on HighSierra. It works mostly but seems exceedingly slow. Also some admins have reported problems with adding mulitple packages, profiles or scripts for configuration. 10.13.1 is already in beta and seeding and you should be testing that.

NetInstall on USB

If you do not have the infrastructure to run a NetInstall or BSDPy server, you can also restore the NetInstall.dmg image that System Image Utility creates to an external drive. When mounted on a Mac, it will the High Sierra installer applications, and double-clicking it will start the proper installation process.

Any additional packages, profiles or scripts will be included with this custom external install application as well.

The startosinstall Command

When you already have a management system (Munki, Jamf, Filewave, etc.) you want to initiate the update process with rules or policies. At first glance the supported means of installing macOS seem to be at odds with managed client workflows, since they require user interaction.

However, there is a tool hidden inside the macOS Installer application (since macOS 10.12 Sierra) called startosinstall. The full path to the tool is

/Applications/Install macOS High Sierra.app/Contents/Resources/startosinstall

Note: I believe it was Rich Trouton who first documented this tool in his notes for WWDC 2016. Since then many admins and open source projects have worked to figure out how to use this tool in the best way.

When you run it with the --usage argument you get the following:

$ /Applications/Install\ macOS\ High\ Sierra.app/Contents/Resources/startosinstall --usage
Usage: startosinstall

Arguments
--applicationpath, a path to copy of the OS installer application to start the install with.
--license, prints the user license agreement only.
--agreetolicense, agree to license the license you printed with --license.
--rebootdelay, how long to delay the reboot at the end of preparing. This delay is in seconds and has a maximum of 300 (5 minutes).
--pidtosignal, Specify a PID to which to send SIGUSR1 upon completion of the prepare phase. To bypass "rebootdelay" send SIGUSR1 back to startosinstall.
--converttoapfs, specify either YES or NO on if you wish to convert to APFS.
--installpackage, the path of a package to install after the OS installation is complete; this option can be specified multiple times.
--usage, prints this message.

Example: startosinstall --converttoapfs YES 

There is also an undocumented --nointeraction flag which can be used to run the tool without any user interaction. This is obviously useful for management systems.

Once you have used to your management system to make sure the macOS Installer application is on the client system, you can execute a script with the startosinstall command to initiate the installation process. Remember that the installation process can take a long time, so it should be initiated by the user in a Self Management portal or run during off-hours for kiosk like Macs in labs or classrooms.

startosinstall --applicationpath /Applications/Install\ macOS\ High\ Sierra.app \
    --agreetolicense \
    --nointeraction

The --converttoapfs [YES|NO] argument allows you to suppress automatic APFS conversion on SSD Macs.

There is also a --volume argument to target the non-boot volume. However, this will only work when SIP is disabled or when you run startosinstall from a Recovery/NetInstall disk.

The --installpackage option allows you to add one or more custom packages that will be installed after the OS installation is complete. This is very useful for customization and cleanup. Packages used with startosinstall --installpackage also have to be Distribution Packages.

Note: even though the usage states that you can repeat the --installpackage argument, as of 10.13.0 only the first package given will run the installation with fail with more than one package. Make that one package count. (Note: edited this paragraph. Thanks to Greg for clarifying.)

Tool Support

Is Imaging completely dead?

The imaging tools (like Disk Utility, hdiutil and asr) will work with APFS volumes. However, the support article states:

You can use system images to re-install the existing operating system on a Mac.

So when you need a workflow that requires quick re-imaging, you can use one of the supported methods to install or update the Mac (Firmware and OS) and then use monolithic (or thin) imaging over network or thunderbolt for fast restores. This is useful for scenarios where fast imaging turnaround is required, such as classrooms and labs or loaner laptop setups. However, you have to use extra care to make sure the image system version matches the version that was installed.

Going forward, I expect imaging to be less and less feasible as future Mac hardware and security features will make it harder and harder to use. The times where we could have just one image which will run on all supported Macs might be over as hardware (and the software required to run the hardware) becomes more and more fractured. Note that there is not a unified single ‘iOS’ image/installer for all iOS devices.

Summary

macOS High Sierra 10.13.0 works well for individual users. However, there still are quite a few issues that are relevant for managed deployments. There are many problems with Active Directory and Filevault, NetInstall is slow and adding multiple packages to an installation is broken. Just to mention a few.

Even though it makes sense for some deployments to hold back from High Sierra right now, you will want or have to upgrade soon.

Apple said at WWDC the iMac Pro will ship in December 2017. Its tech specs page, states it will run High Sierra. You can expect it to require High Sierra.

Also, critical security patches might only be pushed for High Sierra.

Imaging is dead. In an unusual move Apple has come right out and said it loud and clear. If you have not done so already, start testing and implementing one of the above strategies right now, so you are ready to move to High Sierra.

On Distribution Packages

Distribution packages are a special format of installer packages. Distribution packages can contain one or more normal or component packages. They can also contain extra resources to customize and control the user interface in the Installer application.

In most cases administrators prefer component packages since they are easier to create and maintain. However, there are a few cases where distribution packages are necessary:

  • add a package to a custom installation in NetInstall, AutoDMG or a system installer created with createOSXinstallPkg
  • combine multiple component pkgs into a single installer
  • restrict hardware and system requirements
  • modify the interface presented in Installer.app
  • push the package with MDM’s InstallApplication command

Building Distribtution Packages

You can easily convert an existing component package, built with pkgbuild to a distribution package with the productbuild command:

$ productbuild --package component.pkg dist.pkg

You can also combine multiple components into a single distribution package:

$ productbuild --package A.pkg --package B.pkg combined.pkg

You can add the --sign option to the productbuild command when the distribution package needs to be signed:

$ productbuild --sign "Installer: Armin" --package component.pkg dist.pkg

You can find valid identities with

$ security find-identity -p basic -v

The string you pass with the --sign parameter can be a partial match to the full identity name.

Note: munkipkg has a flag to build a distribitution package instead of a component package.

Extracting Component Installers from Distribution Packages

Sometimes you may want to extract a component installer pkg from a distribution package.

First you need to expand the distribution pkg with pkgutil:

$ pkgutil --expand dist.pkg dist_expanded

When you use the --expand option on a distribution package, components will also be expanded into subfolders that end in .pkg. Because of this Finder will erroneously display them as installer bundle files. This is misleading, since the components are not functional in this form.

When you want to use the component package without any modifications, you can quickly recompress or ‘flatten’ the expanded component:

$ pkgutil --flatten dist_expanded/component.pkg component.pkg

The process of expanding and flattening a component will of course remove any signature the original pkg might have had. You can re-sign the flattened package with productsign:

$ productsign --sign "Installer: Armin" component.pkg component_signed.pkg

Note: Obviously, when you are tearing a distribution package apart you need to know what you are doing. Components in a distribution package may depend on other components or on scripts and tools in other components. As always: test, test, test.

Packaging Book

You can learn more on building installer packages in my book: “Packaging for Apple Administrators”

Post WWDC Summary

Earlier this year I wrote a post on whether packaging is dead. Since I wrote a book on Packaging and have also invested much of my career in macOS I do have quite some interest in the topic.

(Please buy the book! If you have bought and read it, please leave a review!)

After that post I made myself a reminder to re-visit the topic post WWDC. I was very much expecting to be proven wrong or hopelessly optimistic. This reminder has been bugging me for a while. I have had a hard time to consolidate my thoughts into writing.

It’s not that this year’s WWDC was boring. Quite the opposite. The new iPads Pro look wonderful and I want one. Apple also announced great new iMacs and MacBooks and a space-grey iMac Pro, demonstrating they still care about the Mac line. (The Mac mini, however, got no love this time around. I do hope the line gets at least a speed bump and we don’t have to wait for a the new Mac Pro to get a decent option for screenless Macs. I’ve given up on servers…) And finally, both iOS 11 and macOS High Sierra (10.13) look like solid updates with lots of new features for users and developers. This was a great WWDC!

Mac admins were concerned that this update would lock down macOS in a similar fashion to iOS. The worst case scenarios painted a picture where not even admin users would be able to get root privileges and you couldn’t install third party daemons and agents any more, fundamentally breaking the way all management systems work. Admins would have to re-work their workflows to work through MDMs, which are not yet capable to bear this burden. The new Apple File System APFS would break NetBoot and all the tools admins use to image Macs.

What happened was… well… nothing much really.

Mac-narök has been postponed.

(Excellent talk by Micheal Lynn at MacDevOps YVR, just a few minutes before the WWDC Keynote. Go watch it.)

There will be changes in High Sierra that affect admins. APFS on macOS is definitely going to happen. In the current (first) beta there is an option to disable the filesystem conversion during upgrade, but it is unknown wether that option will still exist in the release. You can now add iOS devices to DEP even if they were not registered at purchase. You can control a firmware password on Macs with profiles. There are some (minor) changes to files and folders protected by SIP.

I don’t believe or want to suggest the posts above and many other people who predicted the end of Mac Administration as we know it were hysterical or unnecessarily panicked. When they were written there were strong indications and hints that Apple was planning a lockdown of some form soon. MDM only Mac administration might still happen in a future update. However, we seem to have gotten an reprieve, which is good.

Why did the lockdown not happen now? Excellent question, which I do not know the answer to. There was a big outcry from the Mac admin community and many used their official channels (Apple reps and support, Radar, Feedback) to tell Apple what a huge imposition such a quick and drastic change would be. Also many third-party application developers are reluctant to (or cannot) move to the Mac App Store, which would be a requirement in an MDM only world.

For now it seems that common admin tools will run on High Sierra and APFS with just some minor adjustments. This includes packages! Packaging is not dead! Long live Packaging! …and all the other tools!

(On the other hand, some things may still break or be removed during the beta phase.)

Does that mean we should just happily keep doing what we are doing? No. Even if Apple does not yet enforce ‘MDM-only’ they are clearly moving towards ‘more MDM.’ We still have to re-evaluate every setting and workflow with MDM in mind. There are some great solutions already that can combine MDM with e.g. Munki, Chef or Puppet.

Even though imaging, whether you choose the “thick” or “thin” approach, will probably still work in High Sierra, you should be thinking about alternative strategies. DEP plus application installs and updates are more flexible and powerful than full disk imaging.

There are certain setups, such as classrooms and training centers, which require frequent re-imaging with short turnaround times. Ironically, the tech that was predicted to kill imaging might provide a solution. APFS disk snapshots could provide a solution for fast system restores. The tools for this do not seem to be fully in place yet, but the time to test and file bugs is now.

The MDM ‘InstallApplication’ command, which installs the agent software, such as the Munki or Jamf client, should be supported by management systems. This would allow clients to be connected to the management system without user interference and the client software to add to the limited functionality of MDM with tools that admins already have solutions and expertise for.

So the post WWDC summary: the ‘End of Things as We Know Them’ has been postponed. Imaging will still work, but you want to start examining and testing alternatives. Packages and scripts remain relevant, but there are interesting new means of distributing them.

It is already apparent the next WWDC will have more exciting news ready for Mac and iOS Admins. Until then we will be busy learning the new features and tools in High Sierra and iOS 11 and laying the groundwork to the future.

Tab Completion for autopkg

Tony Williams aka ‘honestpuck’ has built a script to enable tab-completion for autopkg in bash.

This means that you can type

$ autopkg s⇥

(where ⇥ is the tab key) and it will autocomplete to

$ autopkg search 

This will also work for recipe names:

$ autopkg run BBEdit⇥⇥
BBEdit.download  BBEdit.jss       BBEdit.pkg       
BBEdit.install   BBEdit.munki     

This is really useful. Auto-completion not only saves on typing, but helps to avoid errors.

Installing autocompletion in your profile

Tony has provided instructions on how to install the script with brew. However, it not hard to install this manually in your .bash_profile or .bashrc. First, clone the github repository on to your system (I keep all projects like this in an un-creatively named ‘Projects’ folder):

$ cd ~/Projects
$ git clone https://github.com/Honestpuck/autopkg_complete.git

This will download the project to autopkg_create. The file we need is the autopkg file inside that folder.

Then add the following lines to your .bash_profile or .bashrc:

if [[ -r "$HOME/Projects/autopkg_complete/autopkg" ]]; then
    source "$HOME/Projects/autopkg_complete/autopkg"
fi

You will need to adjust the path if you are using a different location. Basically these lines say: if this file exists and is readable, then read and interpret it as bash source. Since you need to define functions in the context of the shell, you need to `source` the file, rather execute it as script. (When you run the the file as a script, the functions will be defined in the context of the script, and then ‘forgotten’ when the script ends.)

Save your new profile and open a new Terminal window or type

$ source ~/.bash_profile

to update an existing shell.

Thanks again to Tony Williams, this is very useful!

Where PATHs come from

In an earlier post we talked about how to append to the PATH variable, so you can add your own directories to bash’s search path.

In macOS the default PATH on a ‘clean’ installation is:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

However, if you have installed some tools (such as the macOS Server.app, Xquartz or Munki) you will see those in the PATH as well:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin:/usr/local/munki:

Where does this pre-set PATH come from?

Since the PATH is pre-set on a clean new account without a .bashrc or .bash_profile, we have to look in a central location which applies to all users. In another earlier post, we saw that /etc/profile is run for every user shell, even before a .bash_profile is executed. When you look into this file, you see that the very first set of commands look like this:

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

This looks very promising. The path_helper tool has a man page. This tool does a few things to assemble the PATH. First it reads the file /etc/paths which on macOS looks like this:

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

So this is where the default ‘clean’ macOS PATH comes from. Then path_helper will read every file from /etc/paths.d and append each line of each file in that directory to the PATH as well. This is where optional and third party applications and tools, like Xquartz or Munki, can install their own additions to the PATH for all users.

(Files in this folder will be read in alpha-numerical order of the filename. Some tools, like Xquartz, attempt to influence the order by preprending a number, e.g. 40-XQuartz.)

Finally, if path_helper runs in an environment where PATH is already set, it will append that PATH value to what it built from the files and then remove duplicates.

path_helper does not change the environment variable directly, but it generates the commands necessary to set the PATH correctly. It will generate the right commands wether it is called from a bourne type shell (on macOS: sh, bash, ksh and zsh) or a csh type shell (on macOS: csh and tcsh). You can see the output of the two styles by running path_helper with the -s or -c options:

$ /usr/libexec/path_helper -s
PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"; export PATH;
$ /usr/libexec/path_helper -c
setenv PATH "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";

(You have to type the full path to path_helper because, ironically, but intentionally, /usr/libexec is not in the standard PATH.)

To actually execute the commands generated by path_helper you can use the eval command, like the /etc/profile does:

$ eval $(/usr/libexec/path_helper)

Don’t touch my Profile!

Some command line tool installers understandably feel the need to add their tools to the default PATH. Since there is no unified approach among different flavors of UNIX and Linux on how to do this, you will find several different approaches. Some tools will edit /etc/profile and others will look for the various profile files in a user’s home directory and edit those. Usually the installation process will append a line that appends their tools directory to the PATH.

One example for this is the Python 3 installer. It contains a compnent package that will attempt to determine which profile file you are using and appends a line to append to the PATH.

However, this is not only highly intrusive but also quite fragile. Changes to /etc/profile might be overwritten by a future macOS update. Changes to a user’s profile file, might be overwritten by the user. Also the installer will only append their setting to the current user, not other users that may be present or created in the system.

Sample paths.d installer package

On the other hand, dropping a file into /etc/paths.d with a package installer will affect all users on a system. The file in paths.d can be updated for future updates if necessary and is also easily identified and removed by an admin. It will work wether it is installed to the startup volume or another volume. It can be pushed with management tools.

Building an installer for a file in /etc/paths.d is very simple:

$ mkdir CustomToolPathInstaller
$ cd CustomToolPathInstaller
$ mkdir payload
$ echo "/usr/local/customtool" >> payload/customtool
$ pkgbuild --root payload --install-location /private/etc/paths.d --version 1.0  --identifier com.example.customtool.path CustomToolPath.pkg
pkgbuild: Inferring bundle components from contents of payload
pkgbuild: Wrote package to CustomToolPath.pkg

Only five commands, three of which create the folder structure. You can find this sample project (which is slightly more elaborate) on my GitHub.

If you want to learn more about building installer packages for macOS, please read my book “Packaging for Apple Administrators”.

What about MANPATH?

This is usually not used on macOS since the the default settings for the man tool are quite flexibel. (Look at the man page for man and the file /etc/man.conf for details.) However, if a MANPATH environment variable is set when path_helper runs, it will also assemble the command to set the MANPATH built in a similar way to the PATH from the files /etc/manpaths and the directory /etc/manpaths.d.

Usually the MANPATH is not set on macOS so you will not see this. But if you want to manage your MANPATH and want to leverage path_helper all you have to do is set the MANPATH.

$ export MANPATH=/usr/share/man
$ /usr/libexec/path_helper
PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"; export PATH;
MANPATH="/usr/share/man:/usr/local/share/man"; export MANPATH;

Re-order the PATH

We have seen path_helper is extremely useful. There is one caveat, however. path_helper may reorder your PATH. Imagine you are pre-pending ~/bin to your PATH because you want to override some standard tools with your own. (Dangerous, but let’s assume you know what you are doing.) Then some process launches a subshell which can call path_helper again. path_helper will ‘find’ your additions to the defined PATH, but it will append to the list of default paths from /etc/paths and /etc/paths.d, changing your order and thus which tools will be used.

$ export PATH=~/bin:$PATH
$ echo $PATH
/Users/armin/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
$ /usr/libexec/path_helper 
PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/armin/bin"; export PATH;

You can see behavior like this when you use Xterm (The X11 based terminal in Xquartz) which does not execute .bash_profile but still picks up the PATHenvironment variable from somewhere…

# in Xquartz Terminal:
bash-3.2$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin:/usr/local/munki:/Library/Frameworks/Python.framework/Versions/3.5/bin:/Users/armin/bin:/opt/X11/bin

A better way to override built-in commands which is not affected by path_helper would be to use bash aliases or functions in your profile.