-
-
Save talkingmoose/e9ed319226c6da30dd633725e48a97b0 to your computer and use it in GitHub Desktop.
#!/bin/zsh | |
:<<ABOUT_THIS_SCRIPT | |
------------------------------------------------------------------------------- | |
Written by:William Smith | |
Professional Services Engineer | |
Jamf | |
[email protected] | |
https://gist.github.com/e9ed319226c6da30dd633725e48a97b0 | |
Originally posted: October 15, 2020 | |
Updated: December 2, 2020 | |
Updated: December 11, 2020 | |
Purpose: Creates a deployable PKG file from an app whose app bundle | |
contains one or more files larger than the 8 GB limit supported by pkgbuild | |
or Jamf Composer. | |
Instructions: | |
1. Save the script to a file named MegaPKGr.zsh on your Mac. | |
2. If necessary, run 'chmod +x /path/to/MegaPKGr.zsh' to make it execu- | |
table. | |
3. To run the script, open Terminal and enter: | |
/path/to/MegaPKGr.zsh /path/to/large.app | |
Except where otherwise noted, this work is licensed under | |
http://creativecommons.org/licenses/by/4.0/ | |
"If you try to save wisdom until the world is wise, Father, | |
the world will never have it." | |
------------------------------------------------------------------------------- | |
ABOUT_THIS_SCRIPT | |
function logmessage() { | |
echo -ne "$1\r" | |
/bin/sleep 1 | |
} | |
function logresult() { | |
if [ $? = 0 ] ; then | |
echo "$1" | |
/bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" | |
/bin/sleep 1 | |
else | |
echo "$2" | |
/bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" | |
echo "Aborting script" | |
/bin/date "+%Y-%m-%d %H:%M:%S Aborting script" >> "$logFile" | |
cleanup | |
exit 1 | |
fi | |
} | |
function cleanup() { | |
logmessage "Removing temporary items..." | |
/bin/rm -Rf "$tempDirectory" | |
logresult "Succeeded removing temporary items" "Failed removing temporary items" | |
} | |
# need to run this script with elevated privileges | |
if [ $EUID -ne 0 ]; then | |
echo | |
echo "This script requires elevated privileges. Run it again with \"sudo\"." | |
echo | |
exit 0 | |
fi | |
# define log file location | |
logFile="/Library/Logs/MegaPKGr.log" | |
# choose app for packaging | |
appPath="$1" | |
while [[ "$appPath" = "" ]] | |
do | |
echo | |
echo "Drag the app for packaging into this Terminal window and press return." | |
echo "To abort this script, press Control-C." | |
echo | |
read -p "App path: " appPath | |
done | |
app=$( /usr/bin/basename "$appPath" ) | |
echo | |
# the time right now | |
startTime=$( /bin/date '+%s' ) | |
# prompt for folder for the final package | |
theCommand='set chooseFolder to POSIX path of (choose folder with prompt "Save package to this folder...")' | |
chooseDirectory=$( /usr/bin/osascript -e "$theCommand" ) | |
# verify chosen directory is writable | |
logmessage "Verifying chosen folder..." | |
/usr/bin/touch "$chooseDirectory/.test" | |
logresult "Chosen folder is writable" "Chosen folder is not writable" | |
/bin/rm "$chooseDirectory/.test" | |
# verify disk space needed to package app | |
appSize=$( /usr/bin/du -md 0 "$appPath" | /usr/bin/awk '{ print $1 }' ) | |
logmessage "Size of \"$app\" in MB: $appSize" | |
availableSpace=$( /bin/df -g /System/Volumes/Data | /usr/bin/grep dev | /usr/bin/awk '{ print $4 }' ) | |
logmessage "Available disk space: $availableSpace GB " | |
neededSpace=$(( appSize * 3 / 1024 )) | |
logmessage "Disk space required to build package: $neededSpace GB " | |
[ $availableSpace -gt $neededSpace ] | |
logresult "Disk has enough free space to build \"$app.pkg\"" "Disk does not have enough free space to build \"$app.pkg\"" | |
echo "Log file is located in /Library/Logs/MegaPKGr.log" | |
echo | |
# create temporary working directory | |
logmessage "Creating temporary working directory..." | |
tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/MegaPKGr.XXXXXX" ) | |
logresult "Succeeded creating temporary working directory" "Failed creating temporary working directory" | |
# create dmg from the app to create a single file | |
logmessage "Creating disk image (DMG) archive of \"$app\"..." | |
/usr/bin/hdiutil create -quiet "$tempDirectory/$app.dmg" -ov -volname MegaPKGr -fs APFS -srcfolder "$appPath" | |
logresult "Succeeded creating DMG archive of $app" "Failed creating DMG archive of $app" | |
# create folder structure for pkgbuild | |
logmessage "Ceating pkgbuild ROOT directory..." | |
/bin/mkdir -p "$tempDirectory/ROOT/private/tmp/MegaPKGrFileParts" && cd "$tempDirectory/ROOT/private/tmp/MegaPKGrFileParts" | |
logresult "Succeeded creating pkgbuild ROOT directory" "Failed creating pkgbuild ROOT directory" | |
logmessage "Creating pkgbuild Scripts directory" | |
/bin/mkdir -p "$tempDirectory/Scripts" | |
logresult "Succeeded creating pkgbuild Scripts directory" "Failed creating pkgbuild Scripts directory" | |
# split archive file into 500 MB file chunks | |
logmessage "Creating 500 MB file chunks from archive file..." | |
/usr/bin/split -b 500m "$tempDirectory/$app.dmg" | |
logresult "Succeeded creating 500 MB file chunks from archive file" "Failed creating 500 MB file chunks from archive file" | |
# create postinstall script for pkgbuild | |
logmessage "Creating pkgbuild postinstall script..." | |
/bin/cat << 'EOF' > "$tempDirectory/Scripts/postinstall" | |
#!/bin/bash | |
function logresult() { | |
if [ $? = 0 ] ; then | |
echo "$1" | |
else | |
echo "$2" | |
exit 1 | |
fi | |
} | |
function cleanup() { | |
/bin/rm -Rf "$tempDirectory/" "/private/tmp/MegaPKGr"* | |
logresult "[RESULT: $?] Succeeded removing temporary items" "[ERROR: $?] Failed removing temporary items" | |
} | |
# create temporary working directory | |
echo "Creating temporary working directory" | |
tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/MegaPKGr.XXXXXX" ) | |
logresult "[RESULT: $?] Succeeded creating temporary working directory" "[ERROR: $?] Failed creating temporary working directory" | |
# change directory to temporary working directory | |
echo "Changing directory to working directory '$tempDirectory'" | |
cd "$tempDirectory" | |
logresult "[RESULT: $?] Succeeded changing to temporary working directory" "[ERROR: $?] Failed changing to temporary working directory" | |
# recombine file parts | |
echo "Recombining file parts" | |
/bin/cat /private/tmp/MegaPKGrFileParts/x* > "$tempDirectory/MegaPKGrFileParts.dmg" | |
logresult "[RESULT: $?] Succeeded recombining MegaPKGrFileParts file parts" "[ERROR: $?] Failed recombining MegaPKGrFileParts file parts" | |
# copy the application to original location | |
echo "Extracting archived file" | |
# mounting recombined DMG | |
/usr/bin/hdiutil attach -nobrowse "$tempDirectory/MegaPKGrFileParts.dmg" | |
logresult "[RESULT: $?] Succeeded mounting DMG" "[ERROR: $?] Failed mounting DMG" | |
# dittoing DMG contents to local disk | |
/usr/bin/ditto -rsrc "/Volumes/MegaPKGr/" /Applications | |
logresult "[RESULT: $?] Succeeded dittoing files to specified location" "[ERROR: $?] Failed dittoing files to specified location" | |
# unmounting recombined DMG | |
/sbin/umount "/Volumes/MegaPKGr" | |
logresult "[RESULT: $?] Succeeded unmounting DMG" "[ERROR: $?] Failed unmounting DMG" | |
# delete temporary files | |
echo "Deleting temporary items" | |
cleanup | |
exit 0 | |
EOF | |
/bin/chmod +x "$tempDirectory/Scripts/postinstall" | |
logresult "Succeeded creating pkgbuild postinstall script" "Failed creating pkgbuild postinstall script" | |
# create installer package | |
logmessage "Creating package \"$app.pkg\"..." | |
/usr/bin/pkgbuild --quiet --identifier net.talkingmoose.MegaPKGr --version "1.0.0" --scripts "$tempDirectory/Scripts" --root "$tempDirectory/ROOT" "$chooseDirectory/$app.pkg" | |
logresult "Succeeded creating package \"$app.pkg\" in $chooseDirectory" "Failed creating package \"$app.pkg\" in \"$chooseDirectory\"" | |
# remove temporary files | |
logmessage "Removing temporary items..." | |
cleanup | |
echo | |
# calculate and report script run time | |
stopTime=$( /bin/date '+%s' ) | |
seconds=$(( $stopTime-$startTime )) | |
formattedTime=$( /bin/date -j -f "%s" "$seconds" '+%M minutes and %S seconds' ) | |
logresult "Packaging time: $formattedTime" | |
echo | |
exit 0 |
Hi Bill!
We've met before when you came onsite to Cadence Design Systems (in San Jose,Ca) years ago to help with my environment back then, just wanted to say hi again, how you doing?!
Anyhow, this might be a small syntax error somewhere but I am getting the following error when running your script:
% sudo ./MegaPKGr.zsh /Applications/Install\ macOS\ Big\ Sur.app
35:93: execution error: User canceled. (-128)
touch: /.test: Read-only file system
Chosen folder is not writable
Aborting script
Succeeded removing temporary items
Let me know if you can shed a light, thanks and stay safe!
-Dave
Never mind what I said, for some reason, I couldn't even run ls -la in any of my directories, changed to a clean system and was able to run the command just fine:
Desktop % ls -la
ls: .: Operation not permitted
Sorry for the noise...thank you and have a good year!
thank you writing this script, this really helps us.
My question, can we put the .app under /private/var ? instead /Application directory.
if yes, then where we need to make change in script.
Actually, I am trying to deploy the package via Jamf and want to cache the package under /private/var/ ,so that, its not visible for users to do any thing.
replace the only reference to "/Applications" with the new destination; i just tested with /private/var/tmp and it placed the installer there for me instead.
Thank you, @dev-yeet.
Yes it drops the location where we want by just replacing "/Application" to new_path
@talkingmoose
Thanks for this, I was able to get around the error "Failed creating DMG archive of Install macOS Big Sur.app" by uninstalling the Jamf Pro tools and re-installing it. However, I am now getting the error: "Installation failed. The package could not be verified." I have tried this on multiple devices, on different networks but the issue still persists. I am going to try the Armin Briegel's fetch-installer-pkg script you suggested. I will provide updates. Thanks for your help.