Skip to content

The .pkg File Format Has an 8Gb Size Limit

I just spent the better part of a day trying to figure out why Composer (part of the Casper Suite) was failing to output a .pkg file. Composer is usually rock solid; it’s the best part of Casper Suite and the industry leader in OS X packaging. Stephan Sudre’s Packages is good too, but Composer has an ease-of-use and feature set that is unrivaled.

So when it failed to create my .pkg I was at a bit of a loss as to how to troubleshoot. I tried it on a 2nd and then a 3rd Mac. Three different OS’s, three different versions of Composer. All failed.

Then I tried Packages. It too failed. This pointed the finger at my contents. One of the files was an 8.7Gb .dmg that had been output by AutoDMG. I tried renaming the file. No go. Then, at the suggestion of JAMF support, I tried having Composer output a (Casper-specific*) .dmg instead of a .pkg.

That was it. Now everything pointed to .pkg not being able to handle the large file I was stuffing into it.

Persistent Googling yielded this obscure reference in the Munki documentation that .pkg files can’t be larger than 8Gb. Ok, that’s not exactly correct. The default max. size for a .pkg is 8Gb if no changes are made to the “distribution.dist” file. Thing is, most packaging tools don’t let you alter this value.

Why was this so hard to figure out? Because when you hit the limit, no error is generated. Neither Composer nor Packages knew they were failing. They simply output a .pkg that didn’t contain everything I’d instructed them to include. There were no logs to view, no clues to follow.

So keep your .pkg files below 8Gb, or, if the file is for use in Casper Suite (see below), use .dmg format. If you’re distributing operating systems, modularize to keep sizes smaller. Everyone will be happier.

* Composer-created .dmg files are of a JAMF-specific file format. They work in Casper Suite but not in any other utility that handles .dmg files. Have Composer output .pkg format if you need to interact with anything outside of Casper.

Auto-run VMWare VM’s On Boot

We had a request to deploy two dozen VM’s to datacenters running on headless Mac Pros. If the Pros ever got shut down or rebooted, the VM’s needed to come back up automatically without requiring anyone to log in to the Mac Pros. Here’s how we did that:

You would think you could create a .plist that runs VMWare using the vmrun command:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.yourcompanyhere.vmware</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/logger "=================================="</string>
<string>/usr/bin/logger "Trying to start vmware VM's now..."</string>
<string>/Applications/VMware\ Fusion.app/Contents/Library/vmrun -T fusion start "/Users/Shared/v1.vmwarevm/v1.vmx" gui</string>
<string>/Applications/VMware\ Fusion.app/Contents/Library/vmrun -T fusion start "/Users/Shared/v1.vmwarevm/v2.vmx" gui</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/var/log/jpmcvmware.log</string>
<key>StandardErrorPath</key>
<string>/var/log/jpmcvmware.log</string>
</dict>
</plist>

However, launchd only allows one argument per “ProgramArguments” key. Thus you need to move your commands to a script, and have the .plist reference that script. So do this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.yourcompanyhere.vmware</string>
<key>ProgramArguments</key>
<array>
<string>/Library/Scripts/vmwarescript.sh/string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/var/log/jpmcvmware.log</string>
<key>StandardErrorPath</key>
<string>/var/log/jpmcvmware.log</string>
</dict>
</plist>

Deploy this .plist to the Mac Pros into the /Library/LaunchDaemons directory. Ensure it has 644 permissions.
Then create the script that the .plist references:

#!/bin/sh

/usr/bin/logger "Trying to start vmware VM's now..."
/Applications/VMware\ Fusion.app/Contents/Library/vmrun -T fusion start "/Users/Shared/v1.vmwarevm/v1.vmx" gui
sleep 5
/Applications/VMware\ Fusion.app/Contents/Library/vmrun -T fusion start "/Users/Shared/v2.vmwarevm/v2.vmx" gui
sleep 5

Save the script in the path you set in the .plist above (/Library/Scripts/vmwarescript.sh).

Notes:

  • The VM’s are located in a central location, not in any particular user’s home directory.
  • The VM’s are set to run with a GUI. If you never want your users to access the host Mac’s Virtual Machine Library, change “gui” to “nogui”. The VM’s will still be accessible over VNC and ssh.

Finally, enable the launchd event with the command:

launchctl load /Library/LaunchDaemons/com.jpmc.yourcompanyhere.plist

Most recent users on your Mac, the “asl” directory, and permissions

If you want to find out who the most recent users on your Mac have been, there are ways to do that. Maybe you want to see if someone has been using your Mac. Or how many times you’ve logged in. Or, if it’s your employer’s Mac, who has been using it. You might also want to reliably know who the current user is. (Hint: “whoami” is unreliable, for if you’re in as sudo or root, it will report that, not the current console user.)

The typical way to scrape the current and most recent users list is the command “last -t console”. You will find many websites saying this is definitively the way to find this information, and that if you wanted to pore over that data manually, it’s in /var/log/wtmp.

Not so.

First, you will find that a non-admin user in OS X will get no output from the “last -t console” command.

And when you go poking around wtmp, you’ll find it empty.

You see, Apple moved away from using wtmp after Mac OS X 10.4. That was a while ago. But many websites claim to this day that it’s still in use.

Where did Apple move this information? To /var/log/asl. That’s a directory containing binary files with all the login information you are seeking.

The problem? It’s restricted with 600 permissions. This is why “last -t console” fails for non-admin users.

As you can guess the solution here is easy; relax those permissions. Do a “chmod -R 666 /var/log/asl”. And bingo, your users can run the “last” command without issue.

Unenrolling a Mac from your Casper Suite JSS

We have two JSS’s, one for Development/Testing and one for Production. We want to be able to swap our test Macs back & forth as needed. Unfortunately, JAMF doesn’t provide an “unenroll” switch for the jamf command line tool. You can “removeFramework” but that deletes everything JAMF-related from the workstation so you cannot enroll programmatically and are stuck obtaining a new QuickAdd package and running from the GUI. So I wrote a script to get around that.

There are only two files you need to preserve prior to removing the JAMF framework so that you can re-enroll later:

/Library/Preferences/com.jamfsoftware.jamf.plist
/usr/sbin/jamf

Once those are saved, you’re good to roll. Here is the script:

#!/bin/sh
# January 17, 2014, Kurt Tappe
# This script will swap JSS'

# Set server addresses
prod="https://your.server.here:8443/"
dev="https://your.otherserver.here:8443/"

# Which JSS are we running from?
jss=`/usr/sbin/jamf checkJSSConnection | grep https | cut -d "/" -f3`
if [ "$jss" = "" ]; then
   echo "Error: JSS could not be determined. You may need to first enroll this Mac in a JSS using QuickAdd."
   exit
elif [ "$jss" = "your.server.here:8443" ]; then
   echo "Currently connected to $jss. Switching to Dev..."
   newjss=$dev
else
   echo "Currently connected to $jss. Switching to Prod..."
   newjss=$prod
fi

# Preserve prefs & binary
cp /Library/Preferences/com.jamfsoftware.jamf.plist /Library/Preferences/com.jamfsoftware.jamf.backup
cp /usr/sbin/jamf /usr/sbin/jamfbackup

# Disconnect
echo "Removing framework..."
/usr/sbin/jamf removeFramework
sleep 5

# Restore old prefs and modify them with the new JSS URL
echo "Restoring prefs & enrolling..."
cp /Library/Preferences/com.jamfsoftware.jamf.backup /Library/Preferences/com.jamfsoftware.jamf.plist
cp /usr/sbin/jamfbackup /usr/sbin/jamf
defaults write /Library/Preferences/com.jamfsoftware.jamf allowInvalidCertificate -boolean true
defaults write /Library/Preferences/com.jamfsoftware.jamf jss_url -string $newjss
defaults delete /Library/Preferences/com.jamfsoftware.jamf last_management_framework_change_id

# Reconnect
/usr/sbin/jamf enroll -noRecon

One thing required for this to work is for you to not be forcing the use of certificates. Yes, we use them, but for ease of management we don’t require them for enrollment, so that we can do things like run these scripts.

Hope this helps,
-Kurt

Programmatically Scraping Data From your Casper Suite JSS

So let’s say you’re writing a bash script and need to glean data from your JSS about a particular Mac workstation. In this case, you have the workstation name and you want to know the Mac’s IP address. Well, JAMF has provided a means to do that via the REST API.

If you contact JAMF, they’ll show you a way to obtain info about any Mac workstation in the JSS if you already know its computer ID in the JSS:

curl -v -u USERNAME:PASSWORD https://JSS.URL:8443/JSSResource/computers/id/###/subset/general -X GET | xpath //computer/general/ip_address | sed -e 's/\<ip_address>//g; s/\<\/ip_address>//g'

This is hardly useful though, as who knows each workstation’s ID? (The ID happens to be pretty much random; it’s a chronological increment based on when the Mac was enrolled in the JSS. Your 9th Mac is “9”, your 47th is “47”, etc.)

The other problem is that both ‘curl’ and ‘xpath’ are very verbose in their output. If you’re writing a command-line utility, you don’t want them mucking up the user’s screen. Luckily there’s a better way.

curl -v -u USERNAME:PASSWORD https://JSS.URL:8443/JSSResource/computers/name/NAME/subset/General | grep -Eo '<ip_address>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | cut -d ">" -f2

(Note: I attempted to use ‘sed’ instead of ‘grep’ & ‘cut’ above, but ‘sed’ just wouldn’t parse the tag-laden output. Ping me if you have a solution.)

In both examples above, you of course need to substitute your authentication into USERNAME and PASSWORD, your JSS address into JSS.URL, and in the bottom example the workstation name you’re referencing into NAME.

If you try the commands directly in Terminal you’ll see the entire transaction with the server, but don’t worry; if you pipe the output to a file or use it in a full script, the output will be clean.

I’ll post more code snippets as I develop them. Specifically, I’m trying to do the reverse of the above; take an IP address and convert it into a workstation name or (better yet) serial number. Watch this space.

Error While Updating Enterprise-packaged Adobe Creative Suite

If you’re trying to install updates or upgrades to Adobe Creative Suite, you may run across a refusal of the updater to run. The error will resemble:

Update failed, updates have been suppressed by the Administrator

Funny thing is, you actually are the likely cause of this error. Remember back when you were packaging Creative Suite using Adobe Application Manager Enterprise Edition (AAMEE)? Near the end of the series of dialog boxes you went through, you clicked “Prevent Updates”.

And there we are. Adobe remembered this and is continuing to suppress updates. It doesn’t care if you’re the admin; updates are suppressed!

The fix is easy even if the path to it is long. What you need to do is edit or delete this file:

/Library/Application Support/Adobe/AAMUpdaterInventory/1.0/AdobeUpdaterAdminPrefs.dat

Removing it is draconian but quick & easy. All you need gone / changed is the line within it that reads:

 <Suppressed>"1"</Suppressed>.

Make the “1” a “0” or just delete that line.

This is all documented by Adobe here, but Googling or Binging the subject is often fruitless. So I’m reposting here to make it easier for all to find.

Keeping 10.x Updates

Update April 2015: I was able to retain a copy of the Yosemite 10.10.3 Beta update via this same method. The trick is the updates do get erased if you let App Store install and reboot. You generally have 60 seconds after the download completes and before Finder shuts down to locate the update file and copy or duplicate it.

Back before all Apple updates came to be distributed through the App Store, it was easy to retain software updates. You just told Software Update app to Keep Updates through its menu system.

There are distinct advantages to retaining updates instead of redownloading them every time. Bandwidth, which Apple seems to think we all have in abundance, is a large one, especially considering many updates are measured in gigabytes these days. But perhaps you also want to keep an update for use in AutoDMG, InstaDMG, Munki, or Casper Suite.

With the advent of App Store, these updates are notably harder to retain. But if you’re quick, you can still keep them. Follow these steps:

1) Initiate the download of the update using App Store.

2) Once the download is complete, look in /Library/Updates/[random #]

OK, the number probably isn’t random, but you’re unlikely to find out Apple’s numbering system, so just look at the most recently updated numerical folder inside /Library/Updates. Your .pkg will be there waiting for you.

 

Follow

Get every new post delivered to your Inbox.