Skip to content

Instantly share code, notes, and snippets.

@talkingmoose
Last active October 6, 2022 12:04
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save talkingmoose/6b78ba3fc4a6623dbc8225e2df38d570 to your computer and use it in GitHub Desktop.
Save talkingmoose/6b78ba3fc4a6623dbc8225e2df38d570 to your computer and use it in GitHub Desktop.
Creates a launch daemon and script on target Macs in a Jamf Pro policy to download the specified macOS installer and update Jamf Pro's inventory. This is preferable to running a command directlt in policy, which can take 30+ minutes to complete, preventing other policies from running. The script self destructs once it sees the installer in the A…
#!/bin/zsh
:<<ABOUT_THIS_SCRIPT
-------------------------------------------------------------------------------
Written by:William Smith
Partner Program Manager
Jamf
bill@talkingmoose.net
https://gist.github.com/6b78ba3fc4a6623dbc8225e2df38d570
Originally posted: April 16, 2022
Purpose: Creates a launch daemon and script on target Macs in a Jamf Pro policy
to download the specified macOS installer and update Jamf Pro's inventory.
This is preferable to running a command directlt in policy, which can take 30+
minutes to complete, preventing other policies from running. The script self
destructs once it sees the installer in the Applications folder.
Instructions:
1. Create a new script in Jamf Pro named "Download macOS Monterey in Background".
2. Paste the entire contents of this script as-is into the Script field.
2. Under Options, set the following parameter labels:
Parameter 4 = "macOS Version (e.g., '12.3.1')"
Parameter 5 = "Organization Name" (e.g., 'Talking Moose Industries')
Parameter 6 = "Organization Reverse Domain" (e.g., 'net.talkingmoose')
3. Add the script to a policy and set the three parameters.
4. Enable the policy for Recurring Check-In Once Per Computer.
5. Scope the policy to target Macs that meet the specifications to run the
downloaded installer and exclude Macs that already have the installer downloaded.
As soon as a computer checks-in and completes the policy, the launch daemon
will start the download, which may take 20+ minutes to complete. The launch
daemon will attempt to download every hour until successful.
Except where otherwise noted, this work is licensed under
http://creativecommons.org/licenses/by/4.0/
"If you lie down with dogs, you get up with fleas."
— Lucius Annaeus Seneca the Elder
-------------------------------------------------------------------------------
ABOUT_THIS_SCRIPT
macOSVersion="$4"
organizationName="$5"
organizationReverseDomain="$6"
# create organization folder if necessary to house the script
/bin/mkdir -p "/Library/$organizationName"
# create fetch-full-installer.zsh script
tee /Library/$organizationName/fetch-full-installer.zsh << EOF
#!/bin/zsh
# if 'Install macOS Monterey.app' exists in the Applications folder, self destruct
if [ -e '/Applications/Install macOS Monterey.app' ]; then
# delete this script
/bin/rm "/Library/$organizationName/fetch-full-installer.zsh"
# attempt to delete enclosing directory
/bin/rmdir "/Library/$organizationName"
# delete the launch daemon plist
/bin/rm "/Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist"
# kill the launch daemon process
/bin/launchctl remove $organizationReverseDomain.fetch-full-installer
exit 0
fi
# download the specified version of "Install macOS Monterey.app"
/usr/sbin/softwareupdate --fetch-full-installer --full-installer-version "$macOSVersion"
# update Jamf Pro inventory after downloading 'Install macOS Monterey.app'
/usr/local/bin/jamf recon
exit 0
EOF
# report to policy whether script was created
if [ $? = 0 ]; then
echo "Creating script at \"/Library/$organizationName/fetch-full-installer.zsh\""
else
echo "Failed creating script at \"/Library/$organizationName/fetch-full-installer.zsh\""
fi
# set correct ownership and permissions on categorize-policies.bash script
/usr/sbin/chown root:wheel "/Library/$organizationName/fetch-full-installer.zsh" && /bin/chmod +x "/Library/$organizationName/fetch-full-installer.zsh"
# report to policy whether ownership and permissions were set
if [ $? = 0 ]; then
echo "Setting correct ownership and permissions on \"/Library/$organizationName/fetch-full-installer.zsh\" script"
else
echo "Failed setting correct ownership and permissions on\"/Library/$organizationName/fetch-full-installer.zsh\" script"
fi
# create $organizationReverseDomain.fetch-full-installer.plist launch daemon
tee /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist << EOF
<?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>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>Label</key>
<string>$organizationReverseDomain.fetch-full-installer</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-c</string>
<string>"/Library/$organizationName/fetch-full-installer.zsh"</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>
EOF
# report to policy whether plist was created
if [ $? = 0 ]; then
echo "Creating launch daemon at /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist"
else
echo "Failed creating launch daemon at /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist"
fi
# set correct ownership and permissions on launch daemon
/usr/sbin/chown root:wheel /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist && /bin/chmod 644 /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist
# report to policy whether ownership and permissions were set
if [ $? = 0 ]; then
echo "Setting correct ownership and permissions on launch daemon"
else
echo "Failed setting correct ownership and permissions on launch daemon"
fi
# start launch daemon after installation
/bin/launchctl bootstrap system /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist && /bin/launchctl start /Library/LaunchDaemons/$organizationReverseDomain.fetch-full-installer.plist
# report to policy whether launch daemon was started
if [ $? = 3 ]; then
echo "Starting launch daemon"
else
echo "Failed starting launch daemon"
fi
exit 0
@gilburns
Copy link

gilburns commented Jun 9, 2022

You set "$macOSVersion", but it never gets used. The place it should be used instead recalls $4 from the args.

@gilburns
Copy link

gilburns commented Jun 9, 2022

Maybe passing an empty value for $4 should cause it to call softwareupdate --fetch-full-installer without the --full-installer-version. That way it would simply grab the latest version.

@duff2481
Copy link

Is there a way we can tell if download is happening in the background? I'm noticing the launch daemon shows no PID # and has a error of 127.

@talkingmoose
Copy link
Author

@duff2481, look for the sofwareupdate command. The launch daemon is just a settings file and won’t have its own PID.

@mani2care
Copy link

I’m happy to c if in case old version exists I do not think so it’s validated with new or defined version?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment