First Boot Package Install Generator.app

With the release of Yosemite, Apple has apparently made an undocumented change to the way it allows packages to be added to the OS installer. If you add any additional packages for installation as part of the OS install/upgrade, they must all be distribution-style flat packages. You can convert a component flat package to be a distribution-style flat packages by running the command below:

productbuild –package /path/to/component.pkg /path/to/distribution.pkg

This change is a problem for First Boot Package Install.pkg and First Boot Package Install With Automated Apple Software Update.pkg, as they are both built as a bundle-style package and not as flat packages. While both First Boot Package Install.pkg and First Boot Package Install With Automated Apple Software Update.pkg run fine on Yosemite, they cannot be added to customized NetInstall images created with System Image Utility or to createOSXinstallPkg-built Yosemite OS installer packages.

First_Boot_Package_Install_Generator_Icon  

To address this issue, I’ve developed First Boot Package Install Generator.app, an Automator application that will allow the selection of a folder containing installer packages and then generate a distribution-style flat package that enables the selected packages to be installed at startup. It’s designed for use with createOSXinstallPkg with the goal of allowing installer packages that can’t run in the OS X Install environment to be used as part of a createOSXinstallPkg deployment workflow. See below the jump for the details.

OS Compatibility:

First Boot Package Install Generator.app has been tested and verified to run on the following versions of OS X:

OS X 10.8.x

OS X 10.9.x

OS X 10.10.x

First Boot Package Install Generator.app has been tested and verified that it does not run on the following version of OS X:

Mac OS X 10.7.x

Not tested:

Mac OS X10.6.x or earlier

The packages generated by First Boot Package Install Generator.app have been tested and verified to work with the following versions of OS X:

Mac OS X 10.7.5

OS X 10.8.5

OS X 10.9.5

OS X 10.0.0

Preparing installers for use with First Boot Package Install Generator.app

1. Set up a folder to hold your installers.

NOTE: createOSXinstallPkg has an upper limit of 350 MBs of available space for added packages. This is sufficient space for basic configuration, payload-free or bootstrapping packages, but it’s not a good idea to add Microsoft Office or similar large installers to this installer.

2. Create numbered directories inside that folder, with 00 being the first and proceeding on to as many as you need. For numbers less than 10, make sure to label the directory with a leading zero (For example, 06).

Screen Shot 2014-10-19 at 12.43.01 AM

3. Add one installer package to each numbered directory. The number of the directory indicates the install order, with 00 being the first.

Note: If installing more than 100 packages, be aware that this was beyond the scope of my testing. I recommend adding another leading zero where appropriate.

4. Once finished adding installers to the numbered directories, use First Boot Package Install Generator.app to generate a first boot installer package.

Using First Boot Package Install Generator.app

1. If needed, download the First Boot Package Install Generator.app installer from the installer directory in my GitHub repo and install the application on your Mac.

2. Once downloaded and installed, double-click on the First Boot Package Install Generator application. You’ll be prompted to select the directory that contains the installers you want to have installed at first boot.

Screen Shot 2014-10-19 at 12.43.32 AM

3. Once you’ve selected the folder with your installers, you’ll be prompted to name the installer package. By default, the name filled in will be First Boot Package Install, but this name can be changed as desired.

Screen Shot 2014-10-19 at 2.21.13 PM

4. Once you’ve entered a name for the installer package, you’ll be prompted for a package identifier. By default, the name filled in will be com.github.first_boot, but this name should be changed to be something unique.

Screen Shot 2014-10-19 at 2.21.34 PM

5. Once you’ve entered an identifier for the installer package, you’ll be prompted for a version number. By default, the value filled in will be 1.0, but this value can be changed as needed.

Screen Shot 2014-10-19 at 2.21.38 PM

6. You will be prompted to choose if you want to have all available Apple software updates applied before your packages are installed. Choose Yes or No as appropriate.

Screen Shot 2014-10-19 at 2.21.44 PM

7. Once the package name, package identifier, package version and software update choice have been set, First Boot Package Install Generator.app will prompt for an administrator’s username and password.

Screen Shot 2014-10-19 at 2.21.54 PM

8. Once the admin username and password are provided, First Boot Package Install Generator.app will create the installer package and prompt you when it’s finished.

Screen Shot 2014-10-19 at 2.22.22 PM

9. Click OK at the prompt and a new Finder window will open and display the newly-created first boot installer package.

Screen Shot 2014-10-19 at 2.25.05 PM

10. Once the new package has been displayed, First Boot Package Install Generator.app will automatically exit. The package is now ready for use.

Screen Shot 2014-10-19 at 2.22.47 PM

How First Boot Package Install Generator.app works

First Boot Package Install Generator.app is an Automator application that uses AppleScript, shell scripting, pkgbuild and productbuild behind the scenes to create installer packages that are designed to serve as a delivery mechanism to install other packages during a Mac’s startup process. When a script is selected, the following process takes place:

1. The directory with the user-selected packages is copied to /tmp as a zip archive named fb_installers, to give the package-building script a consistent value to work with.

2. After the package name, package identifier and package version are set, /tmp is checked to make sure that there is not an existing directory that is named the same as the chosen name. If a matching directory is found, it is removed.

3. A new directory is created in /tmp that matches the chosen name of the package. This directory will be used for building the first boot package.

4. Next, the installer_build_components.tgz and xmlstarlet.tgz tar files are copied into /tmp from the Contents/Resources directory inside First Boot Package Install Generator.app and then un-tar’d into the build directory inside /tmp.

5. Using the choice of whether to run Apple software updates or not, the appropriate script is moved into the build directory and renamed firstbootpackageinstall.sh.

6. The fb_installers directory with the user-selected packages is moved into the correct location in the build directory for inclusion in the package when it’s created.

7. The new first boot installer package is built first as a component flat package by pkgbuild.

8. A new distribution XML file is synthesized using productbuild for the first boot component package.

9. xmlstarlet is used to add a title field to the distribution XML file.

10. The component package is converted to a distribution-style flat package using productbuild and the edited distribution XML file

11. The installer_build_components.tgz and xmlstarlet.tgz tar files are removed from /tmp.

12. The finished installer package is stored in /tmp/package_name_here and the user is prompted that the process is finished.

13. Once the user is notified and clicks OK, a new Finder window opens for /tmp/package_name_here. The package is ready to be added to a createOSXinstallPkg-built OS installer.

How First Boot Package Install Generator.app-generated installer packages work

When the First Boot Package Install Generator.app-generated installer package is installed via createOSXinstallPkg, it does the following:

1. Installs the folder containing the user-selected installers to /var/fb_installers.

2. Installs /Library/LaunchDaemons/com.company.firstbootpackageinstall.plist

3. Installs /var/firstbootpackageinstall.sh.

4. Installs /Library/LaunchAgents/com.company.LoginLog.plist

5. Installs /Library/PrivilegedHelperTools/LoginLog.app

After OS X is installed by createOSXinstallPkg and reboots, the following process occurs:

1. The com.company.firstbootpackageinstall LaunchDaemon triggers /var/firstbootpackageinstall.sh to run.

2. /var/firstbootpackageinstall.sh stops the login window from loading and checks for the existence of /var/fb_installers.

If /var/fb_installers is not found, the following actions take place:

A. The login window is allowed to load

B. /Library/LaunchDaemons/com.company.firstbootpackageinstall.plist is deleted

C. /var/firstbootpackageinstall.sh is deleted

D. /Library/LaunchAgents/com.company.LoginLog.plist is deleted

E. /Library/PrivilegedHelperTools/LoginLog.app is deleted.

F. /var/firstbootpackageinstall.sh checks for an existing /var/log/firstbootpackageinstall.log logfile and renames the existing logfile to include the current date and time.

G. /var/firstbootpackageinstall.sh deletes itself.

If /var/fb_installers is present, the following actions take place:

A. If /var/fb_installers exists, the login window is allowed to load

B. A log is created to record the actions taken by /var/firstbootpackageinstall.sh. By default, this logfile named firstbootpackageinstall.log and is stored in /var/log.

C. /Library/LaunchAgents/com.company.LoginLog.plist loads and launches /Library/PrivilegedHelperTools/LoginLog.app.

D. /Library/PrivilegedHelperTools/LoginLog.app opens a window over the Mac’s login window and displays the logfile.

Screen Shot 2014-10-19 at 2.39.21 PM

E. A network check is run, to ensure that the Mac has a network address other than 127.0.0.1 or 0.0.0.0 (which are otherwise known as loopback addresses.) This network check will check every five seconds for the next 60 minutes for a working network connection.

Network check fails – If only loopback addresses are detected within 60 minutes, the script will take the following actions:

  • Log a failure message to the log
  • Delete /var/fb_installers
  • Restart

On restart, the “if /var/fb_installers is not found” actions occur.

Network check succeeds – If a non-loopback address is detected, the script will take the following actions:

  • Log a success message to the log and proceed with the rest of the script.

F. If the option to install Apple software updates was selected, all available Apple software updates are downloaded and installed prior to installing the user-selected packages.

G. The user-selected packages are installed, using the numbered subdirectories to set the order of installation

H. Once installation has finished, /var/fb_installers is deleted

I. The Mac is restarted

J. On restart, the “if /var/fb_installers is not found” actions occur and all remaining traces of the first boot package are removed from the Mac.

For those who want to build a customized First Boot Package Install Generator.app, the components and scripts are available on my Github repo.

  1. Mike Wilkerson
    November 5, 2014 at 7:08 pm

    Hi Rich. Thanks for this. As always, very good stuff. In our environment, we rely on a private network that is accessible via an 802.1X profile with user authentication.

    After the Yosemite install, the machine won’t be able to reconnect to our network until after login. If we don’t want to run Apple Software Updates, what is the purpose for requiring a network connection? As a work around, having the network connection check time out after a much shorter period of time, then simply proceeding with the package installs would get around this.

    Thanks again,
    Mike

  2. Mike Wilkerson
    November 5, 2014 at 8:37 pm

    Thanks for the quick response. I definitely plan on seeing how we can adapt this to our environment.

    My original question still stands, though. Is there a specific reason that the network check is included if you’re not running software updates? I’ve been trying to consider all use cases and want to make sure I don’t overlook something.

    • November 5, 2014 at 8:55 pm

      I added it because I may have packages that need network resources (like a payload-free package that is running a Casper policy via a manual trigger.) To avoid problems, I make sure that the network is available up front via that check.

  3. Mike Wilkerson
    November 11, 2014 at 6:13 pm

    Hi again Rich. I just ran into an issue that has stumped me. Over the past week I’ve been building a Yosemite installer with createOSXinstallpkg and your First Boot Package Install Generator.app. After working out my issues with network connectivity and payloads, it’s been working great. I’m almost ready to deploy… except…

    I’m now testing on machines with FileVault 2 enabled and now the process is breaking. The first part works as expected: The Yosemite installer downloads from Self Service, the machine reboots, I unlock the drive, then the Yosemite installation happens. Wait 10-15 minutes…

    On the next reboot, when I unlock the drive, instead of beginning your First Boot Package install process, it’s just booting right into Yosemite.

    This was working perfectly before I introduced FileVault into the mix. Everything I can find indicates that FileVault shouldn’t interfere with this. Got any ideas?

  4. November 11, 2014 at 6:14 pm

    Mike,

    Allen Golbig has a pair of scripts that should assist you here:

    https://github.com/golbiga/Scripts/tree/master/DisableFDEAutoLogin

  5. Mike Wilkerson
    November 11, 2014 at 6:25 pm

    Hmm. Our image has Automatic login disabled already.

    When I read the defaults on com.apple.loginwindow DisableFDEAutoLogin, though, that specific key doesn’t exist. I’ll go ahead and run Allen’s script prior to the install and see if that takes care of it.

    • Mike Wilkerson
      November 11, 2014 at 6:56 pm

      Ok, that seems to have done it! Thank you, Rich.

  6. Henning
    April 9, 2015 at 9:24 am

    Hello, any idea why converting a flat package to a distribution package doesn’t work for me with suggest command?

    • Henning
      April 9, 2015 at 9:29 am

      Hi, Sorry I just found the reason by myself. I just made a typo. How embarrassing ;-).

  7. May 4, 2015 at 4:15 pm

    Rich, this works awesome thanks very much. I have a couple of small issues I hope you can help me with. After the Yosemite update installs, even though I have the icloud and diag messages pkg as part of the first boot installer package, those messages still appear. In addition, the initial setup appears too, do you have a script that disables the setup of a new account etc? Any idea of why the the icloud and diag messages still appear? Finally, I have 2 hidden accounts on the current OS, pre-Yosemite upgrade, then after applying this upgrade, both of those accounts are no longer on the computer.

  8. laurentd
    November 18, 2015 at 10:58 am

    Hello,
    With OS X 10.11 the /Library/PrivilegedHelperTools/LoginLog.app seems to be hidden, or not to be launched. The Installer Assistant is on the front of the screen…
    Any solution to bring the LoginLog back ?

    • November 19, 2015 at 2:31 am

      @laurentd,

      The Setup Assistant appears to be using a process other than the LoginWindow process which the LoginLog tool is watching for. The firstboot script is still running in the background, but the log window does not appear.

      The best workaround I’ve found is to suppress the Setup Assistant before the firstboot process runs. Information on how to do this is available here:

      https://books.google.com/books?id=H3awpzaO7IwC&pg=PA161&lpg=PA161&dq=Setup+Assistant+/var/db/.AppleSetupDone&source=bl&ots=_Wh48Plz6z&sig=bE7D-kMWONtqRKuzpJqV3iCRufU&hl=en&sa=X&ved=0CGMQ6AEwCWoVChMIhufb1bibyQIVCkYmCh2hbQEQ#v=onepage&q=Setup%20Assistant%20%2Fvar%2Fdb%2F.AppleSetupDone&f=false

      • laurentd
        November 19, 2015 at 10:14 am

        @rtrouton,

        I tried to write the command : touch /var/db/.AppleSetupDone
        at the beginning of my firstbootscript … without success

        Trying to kill the assistant doesn’t work too : pkill signal HUP “Setup Assistant” also at the beginning of my script

        How to do this before the firstboot process runs ?

        How I proceed (without success) :
        – a package createAdminUser.pkg (made with CreateUserPkg-1.2.4)
        – a script firstBootSetup.sh (with touch /var/db/.AppleSetupDone at the beginning)
        – convert the script into a package (with Payload-Free Package Creator)
        – combine the 2 packages into 1 (with First Boot Package Install Generator)
        – use AutoDMG to make à DMG image of 10.11.1 with my “unified” package
        – use fuse-master to convert the DMG into a VMDK in order to open it as a VM …

        The problem is not major, since the “Setup Assistant” disappear after about 2 minutes, as my script after its work reboot the machine, and after the reboot, the Assistant is gone (due to the “touch /var/db/.AppleSetupDone” directive)

    • lolopb
      November 28, 2015 at 6:34 pm

      @laurentd

      You can’t create the .AppleSetupDone during first script, it’s too late. To workaround this I created a package that will create the file and installed this package during the creation of the DMG with AutoDMG, not in the first boot script.

      • laurentd
        December 2, 2015 at 11:19 am

        @lolopb

        Thanks, this solution works fine.

      • enohl
        December 30, 2015 at 8:08 am

        Hi lolopb

        can you please explain the steps how did you create this package?

      • laurentd
        December 30, 2015 at 9:48 am

        # first create the “working directory (WD)”
        mkdir ~/Desktop/Projet_Package_Disable_AppleSetup

        # go inside the “WD”
        cd ~/Desktop/Projet_Package_Disable_AppleSetup

        # create the hierarchy inside the “WD”
        mkdir -p Package_Disable_AppleSetup/private/var/db

        # create the file that will suppress the installation wizard
        touch Package_Disable_AppleSetup/private/var/db/.AppleSetupDone

        # use pkgbuild to generate the package, but could also be done with “Packages” (from Stéphane Sudre)
        pkgbuild –identifier com.company.Disable_AppleSetup –version 1.0 –root Package_Disable_AppleSetup Disable_AppleSetup.pkg

        ## => the package “Disable_AppleSetup.pkg” is ready inside the “WD”

  9. Tim Kimpton
    November 18, 2015 at 5:38 pm

    Hi there

    How do i remove the network check? I have tried but it seems the First Boot pkg is not installing

    Thanks

  10. Tim Kimpton
    November 19, 2015 at 5:51 am

    yes i tried that again and got The action “Run Applescript” encountered an error.

  11. Tim Kimpton
  12. Michael Karshuening
    March 2, 2016 at 10:30 am

    @rtrouton,

    I´m testing the hole scenario with the upcoming OS X 10.11.4.
    The component LoginLog will not work anymore, because it can´t be restricted to LoginWindow (LimitLoadToSessionType) and can´t be started while no user is logged in.
    With 10.11.3 everything works fine.
    Maybe Apple will fix it. Meanwhile you should archive an OS X 10.1.3 Install.app and use this for deployment.

  13. spockjenkins
    May 23, 2016 at 12:46 am

    @rtrouton,

    Thanks for the awesome first boot and for “documenting” the heck out of things for the rest of us.

    I was looking at the previous posts because I too wanted to make a modification. I was trying to get the script to point to my internal update server before it ran updates, but running into to a problem. I added line to call a casper policy which does the redirect. But when I try to run the Generator it throws the follow right after authenticating to build: “The action “Run AppleScript” encountered an error.”.

    I’m using command outlined in your github note when compressing the “installer_build_components” and the file is placed in “First\ Boot\ Package\ Install\ Generator.app/Contents/Resources”. I’ve extracted the .tar and the paths seems to match what’s natively in the First Boot Package Install Generator.app. Any thoughts on what I’m missing?

  14. Jared
    July 21, 2017 at 9:17 pm

    @rtrouton

    I realize this is a fairly old thread but I am curious about how to ensure network connection happens. As it is sometimes the device connects and proceeds and sometimes gets stuck looking for the network. My current options seem to be to remove the network check though I’d like to keep it, or connect with ethernet… Are there options I should be looking at?

  1. No trackbacks yet.

Leave a comment