24 Jan Reverse Engineering Jamf Admin
Overview
If you are using Jamf Pro to manage your macOS client systems, the “default” option to upload, delete & modify properties of software installer packages & disk images, printer configurations, dock items, directory bindings, and scripts to your Jamf Pro infrastructure is using the native macOS Graphic User Interface (GUI) application called Jamf Admin. With Jamf supporting (and promoting) using and moving your Jamf Pro infrastructure to the cloud, some of the functionality of Jamf Admin application has moved to the web interface. And they have hinted at the plan to move its functionality entirely to the web interface, but currently, most of this administrative functionality is “only” available in Jamf Admin.
Jamf Admin provides decent functionality for managing installer packages & disks, but there are some bugs and poor implementation that can be annoying and painful for Jamf Pro administrators. When you want to streamline the steps of the process and move it into a framework to provide consistency & automation it does not meet this demand and requirement. Also, you can work around some bugs and poor implementations by using more efficient code and discover hidden options that aren’t exposed in Jamf Admin native macOS Graphic User Interface (GUI) application using your own or others code or processes. Jamf does not provide any documentation on using APIs to provide Jamf Admin functionality using your own code and we have actually been told by Jamf technical support that it’s currently not possible but from the existence of tools like JSSImporter, Jamf Pro Upload Web Form, etc. and from our research and development that is far from the truth.
Setup
To prepare to reverse-engineer the “Jamf Admin” application, you will need to set up the following configuration modifications.
To provide minimal access setup the following privileges for the user account or API user that you will be used to reverse engineer the “Jamf Admin” application. An API user is set up and tied to a script or process vs a particular user. Having a dedicated user-specific to a service also allows you to easily shutdown that application or script by disabling the user. Jamf provides a variety of tools to allow for programmatic access to data within the system and to allow for integrations with other systems. The primary tool is the Classic API. The base URL for the Classic API is located at
/JSSResource
on each Jamf Pro server.- Use Jamf Admin
- Save With Jamf Admin
Settings > Jamf Pro User Accounts & Groups > [USERNAME] > Privileges > Jamf Admin
Debugging Proxy
Next, you will need to install and set up a proxy to analyze communication from Jamf Admin to the Jamf Pro and/or Jamf Distribution Point. What’s a Proxy? In this simple example, communication between the two computers (shown in grey) connected through a third computer (shown in red) which acts like a proxy server. Alice isn’t talking directly to Bob and Bob doesn’t see the request directly from Alice. The proxy is acting as a relay. Proxy & Other Options
There are multiple options to set up a debugging proxy or similar methodologies for example:
Wireshark
Wireshark is a free and open-source packet analyzer. It is used for network troubleshooting, analysis, software and communications protocol development, and education.
tcpdump
tcpdump is a data-network packet analyzer computer program that runs under a command-line interface. It allows the user to display TCP/IP and other packets being transmitted or received over a network to which the computer is attached. Here is an article that covers the process of “Recording a Packet Trace” with tcpdump on the Apple Developer site.
For this blog article, we will be covering using Charles debugging proxy application to reverse engineer the Jamf Admin application.
Charles Debugging Proxy Application
Next, you will need to download and configure a debugging proxy to analyze connections to and from the “Jamf Admin” application. One great solution that runs on Mac client systems is Charles. Charles is a cross-platform HTTP debugging proxy server application written in Java. It would relay the communication between Jamf Admin and the Jamf Pro server. It enables the user to view HTTP, HTTPS, HTTP/2 and enabled TCP port traffic accessed from, to, or via the local computer. This includes requests and responses including HTTP headers and metadata (e.g. cookies, caching and encoding information) with functionality targeted at assisting analyzing connections and messaging.
Grant Privileges
When you first launch Charles, you’ll see the message below appear where you can Grant Privileges and then enter your administrator user password to confirm.
Charles Root Certificate
Next, you will need to install the Charles root certificate on the Mac system running Charles as well as the Jamf Admin application. This will allow us to access the SSL traffic that is being proxied through Charles. Download and import the Charles root certificate into your Keychain on macOS by selecting:
Help > SSL Proxying > Install Charles Root Certificate
Next, add the certificate to the current user or System keychain.
This certificate is not trusted by default so you will need to modify the trust settings.
Expand the “Trust” disclosure triangle and select “Always Trust” from the “When using this certificate” pop-up list. Close the certificate details window and enter the password to confirm these modifications.
Enable SSL Proxying
To enable SSL Proxying, navigate to the “Proxy” menu and select the “SSL Proxying Settings…” command and make sure that the “Enable SSL Proxying” checkbox is selected.
Enable SSL Proxying for all locations by clicking “Add” button, then enter a single wildcard character ( * ) in the Host field, leave the Port field empty, and then click the “OK” button.
After finishing the steps above, the “SSL Proxying Settings” window should appear like the following:
Allow Jamf Admin Use Invalid Certificate
Next, you need to modify settings to allow Jamf Admin to use an invalid certificate. This is required to allow Jamf Admin to use the Charles Root Certificate to view the SSL traffic from Jamf Admin, Jamf Pro Server, and the Jamf Distribution Server. Using the Jamf Admin, select the “Preferences…” command from the “Jamf Admin” menu.
Then unselect the checkbox to allow the untrusted SSL certificate.
Or using the command line you can enter the following command:
defaults write com.jamfsoftware.jss allowInvalidCertificate -bool yes
This modifies or creates the property list file located here:
~/Library/Preferences/com.jamfsoftware.jss.plist
With the following contents:
<?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>allowInvalidCertificate</key> <true/> <key>url</key> <string>https://your.jss.domain/</string> </dict> </plist>Supposedly this flag is deprecated but still works in our testing, but keep this in mind if it stops working in the future.
Jamf Distribution Point Credentials
Note, if you have other admins in your organization using Jamf Admin, your file distribution points username & password will be in the clear and readable. So, keep this in mind if you want to limit access to this username/password in your organization or include consider including it in a password policy when a former employee leave your organization.
Jamf Admin
Next, launch Jamf Admin and Charles should collect the traffic for https:// your.jss.domain:8443 .
curl -H 'Host: your.jss.domain:8443' -H 'Content-Type: application/xml; charset=utf-8' -H 'Accept: */*' -H 'User-Agent: Jamf%20Admin/3.2.2.3.0 CFNetwork/978.2 Darwin/18.7.0 (x86_64)' -H 'Accept-Language: en-us' --data-binary "&username=${USERNAME}&password=${PASSWORD}%21&casperAdminVersion=10.7.0&skipComputers=true" --compressed 'https://your.jss.domain:8443//casper.jxml'
However, the Jamf Admin application tends to be verbose and we have found only the following is necessary:
curl --data-binary"&username=${USERNAME}&password=${PASSWORD}&casperAdminVersion=&skipComputers=true" 'https://your.jss.domain:8443//casper.jxml'
Analyze Jamf Admin Processes
Next, step is to pick processes in Jamf Admin that you want to analyze and reverse engineer the process and then test & implement with your own code. For example, here are Jamf Admin processes we analyzed and reverse engineered.
function urlencode { echo $(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$1") } open smb://$(urlencode "$USERNAME"):$(urlencode "$PASSWORD")@${FILESHARE}
#!/bin/bash USERNAME="username" password="password" URL=$(defaults read com.jamfsoftware.jss url) PACKAGE="/path/to/package.pkg" # Add Installer Package curl --data-binary "&username=$(urlencode "$USERNAME")\ &password=$(urlencode "$PASSWORD")\ &type=package\ &packageName=$(urlencode `basename "$PACKAGE"`)\ &packageFileName=$(urlencode `basename "$PACKAGE"`)\ &adobeInstall=false\ &osInstall=false\ &osInstallerVersion=\ &parentPackageID=-1\ &checksum=$(openssl dgst md5 "$PACKAGE")\ &hashType=1\ &hashValue=$(openssl dgst sha512 "$PACKAGE")\ &reboot=false\ &packagePriority=10" "${URL}/casperAdminAddObject.jxml"Update Installer Package Information
#!/bin/bash USERNAME="username" PASSWORD="password" URL=$(defaults read com.jamfsoftware.jss url) PACKAGE="/path/to/package.pkg" # UPDATE A PACKAGE curl --data-binary "&username=$(urlencode "$USERNAME")\ &password=$(urlencode "$PASSWORD")\ &allScriptsMigratedToJSS=true\ &packageID=${JSS_PACKAGE_ID}\ &packageName=$(urlencode `basename "$PACKAGE"`)\ &packageFileName=$(urlencode `basename "$PACKAGE"`)\ &checksum=$(openssl dgst md5 "$PACKAGE")\ &hashType=1\ &hashValue=$(openssl dgst sha512 "$PACKAGE")\ &packageGroupID=${JSS_CATEGORY_ID}\ &packagePriority=10\ &packageInfo=$(urlencode "$INFO")\ &packageNotes=$(urlencode "$NOTES")\ &packageFormat=Apple%20Package\ &packageSize=n%2Fa\ &packageRequirements=\ &bootVolumeRequired=false\ &fut=false\ &feu=false\ &ifswu=false\ &reboot=false\ &uninstall=false\ &packageRequiredProcessor=None\ &packageSwitchWithPackageID=-1\ &selfHealingAction=nothing\ &selfHealingNotify=false\ &adobeInstall=false\ &adobeInstallerImage=false\ &adobeUpdater=false\ &osInstall=false\ &osInstallerVersion=\ &packageSerialNumber=\ &parentPackageID=-1\ &basePath=\ &ignoreConflictingProcesses=false\ &suppressFromDock=false\ &suppressEULA=false\ &suppressRegistration=false\ &suppressUpdates=false\ &installLanguage=en_US" "${URL}/casperAdminAddObject.jxml"
#!/usr/bin/env python3 import requests import xml.etree.ElementTree as ET username = 'username' password = 'password' # set to False if Charles Proxy is running verify = True # AUTHENTICATE SESSION session = requests.Session() AUTH = {'username': username, 'password': passwd, 'casperAdminVersion': '', 'skipComputers': 'true'} # verify=False allows the post to run while Charles Proxy is running (cookie is automatically handled) auth_response = session.post(f"https://{hostname}:8443//casper.jxml", data=AUTH, verify=verify) # raw xml data for authentication xml = auth_response.text # CREATE PACKAGE IN JSS CREATE = {'username': username, # 'password': password, # not required if cookie is still valid 'type': 'package', 'packageName': 'package_name.pkg', # `/usr/bin/basename </path/to/package.pkg>` 'packageFileName': 'package_name.pkg', # `/usr/bin/basename </path/to/package.pkg>` 'adobeInstall': 'false', 'osInstall': 'false', 'osInstallerVersion': '', 'parentPackageID': '-1', 'checksum': md5_checksum, # `/usr/bin/openssl dgst md5 </path/to/package.pkg>` 'hashType': '1', 'hashValue': sha512_checksum, # `/usr/bin/openssl dgst sha512 </path/to/package.pkg>` 'reboot': 'false', 'packagePriority': '10'} create_response = session.post(f"https://{hostname}:8443//casperAdminAddObject.jxml", data=CREATE, verify=verify) jss_package_id = ET.fromstring(create_response.text).find('new_id').text # UPDATE PACKAGE INFORMATION IN JSS SAVE = {'username': username, # 'password': password, # not necessary if cookie still valid 'allScriptsMigratedToJSS': 'true', 'packageID': jss_package_id, # ID of the newly created package 'packageName': 'package.pkg', 'packageFileName': 'package.pkg', 'checksum': md5_checksum, # md5 digest 'hashType': '1', 'hashValue': sha512_checksum, # sha512 digest 'packageGroupID': group_id, # package category id 'packagePriority': '10', 'packageInfo': 'Package Info Text', 'packageNotes': 'Packge Notes Text', 'packageFormat': 'Apple Package', 'packageSize': 'n/a', 'packageRequirements': '', 'bootVolumeRequired': 'false', 'fut': 'false', 'feu': 'false', 'ifswu': 'false', 'reboot': 'false', 'uninstall': 'false', 'packageRequiredProcessor': 'None', 'packageSwitchWithPackageID': '-1', 'selfHealingAction': 'nothing', 'selfHealingNotify': 'false', 'adobeInstall': 'false', 'adobeInstallerImage': 'false', 'adobeUpdater': 'false', 'osInstall': 'false', 'osInstallerVersion': '', 'packageSerialNumber': '', 'parentPackageID': '-1', 'basePath': '', 'ignoreConflictingProcesses': 'false', 'suppressFromDock': 'false', 'suppressEULA': 'false', 'suppressRegistration': 'false', 'suppressUpdates': 'false', 'installLanguage': 'en_US'} update_response = session.post(f"https://{hostname}:8443//casperAdminSave.jxml", data=SAVE, verify=verify) # DELETE PACKAGE RECORD FROM JSS DELETE = {'username': username, 'password': passwd, 'allScriptsMigratedToJSS': 'true', 'deletedPackageID': jss_package_id} delete_response = session.post(f"https://{hostname}:8443//casperAdminSave.jxml", data=DELETE, verify=verify)Delete an Installer Package
#!/bin/bash USERNAME="username" PASSWORD="password" URL=$(defaults read com.jamfsoftware.jss url) JSS_PACKAGE_ID="100000" # jss id of package # Delete a package curl --data-binary "&username=$(urlencode "PASSWORD")\ &password=$(urlencode "PASSWORD")\ &allScriptsMigratedToJSS=true\ &deletedPackageID=${JSS_PACKAGE_ID}" "${URL}/casperAdminSave.jxml"
Indexing like Rabbits & Such
Indexing an installer package with Jamf Admin creates a log of all the items contained within the installer package. This is supposed to allow you to uninstall the installer package contents and view the contents from Jamf Pro web interface. This option uploads a list of the contents of the installer package to your Jamf Pro database.
Jamf Pro Installer Package Contents
For example, in Jamf Pro select the following to display contents:
Jamf Pro > Settings > Computer Management > Packages > [INSTALLER PACKAGE NAME].pkg
Then click the “Contents” button to display the installer package contents.
Expanding Installer Packages?
On the Mac client system, you are running Jamf Admin to perform the indexing of an installer package, you will get expanded install on the system and if you are using the optioninstall-location using a tool like pkgbuild where you are specifying a payload of single application bundle like Atom.app with an install path like /Applications/Programming. Jamf Admin’s indexing process will expand the installer package at the root (/) of your file system and you will get multiple versions of your installer packages contents on the Mac system. Or if you include the full path of your installer package’s payload, it will get expanded based on your payload path structure on the Mac system doing the indexing with Jamf Admin.
Why is Jamf Admin expanding in production areas of the Mac system vs using /private/tmp and cleaning up after? If this is a Jamf Pro administrator’s production Mac system, it could cause issues with the client system by expanding in these production areas or causing unnecessary duplication & cleanup tasks. Jamf Admin and all the administrative tools include a copy of the jamf binary, maybe in case, an administrator system doesn’t have the default jamf binary installed or is a dependency that previously existed with the administrative tools.
Jamf Pro/Jamf Admin.app/Contents/Support/jamf
One method to get more insight, into the process that Jamf Admin is using with the indexing process is to use a command-line tool like filemon which displays real-time file system activity on macOS and iOS. This utility relies on the FSEvents device, present in macOS, to follow file system-related events, such as creation and deletion of files. Or a GUI tool like FSMonitor, a macOS application that can monitor and report all modifications to your file system as they are happening. Tracked changes include file creation, deletion, change of content, renames, and change of attributes (i.e. modifications to permissions or owner).
For example, here is file system activity gathered using FSMonitor:
Jamf Admin Indexing Process:
- Creates [NAME].tmp file in /Library/Application Support/JAMF/tmp
- Runs defaults command and stores to [NAME].tmp
- Runs pkgutil and expands into /Library/Application Support/JAMF/tmp/expandedPackage with Bom, Payload and PackageInfo.
- Runs lsbom and outputs /Library/Application Support/JAMF/tmp/index.bom
- Runs gunzip and creates /Library/Application Support/JAMF/tmp/Archive.pax
- Runs shell command/script and expands/installs installer package contents, maybe via Archive.pax
- Creates /private/tmp/indexes directory and creates & updates “1-10” named files, /private/tmp/indexes/1-10
You could use the strings command on the jamf binary and other components of the Jamf Admin bundle to get hints of other functions and processes. The strings command returns each string of printable characters in files. Its main uses are to determine the contents of and to extract text from binary files (i.e., non-text files). A string is any finite sequence of characters, and it can be as few as one character.
strings "/Applications/Utilities/Admin/Jamf Pro/Jamf Admin.app/Contents/Support/jamf" > /path/to/jamf_strings_output.txt
For example, here are some notable strings…
Creating uninstall file... uninstall.xml <Action>remove</Action> Error: The payloads directory does not exist at the specified base path. Process blocking /Setup.app/Contents/Info Uninstalling /Setup.app/Contents/MacOS/Setup Results of installation: packageContents/packageContent/fileName The JSS did not return information to uninstall this package Creating uninstall BOM... uninstall%@.bom Uninstalling... Uninstalled index.bom packageTemp Archive.pax packageName= Save location not valid. expandedPackage Indexing a Flat-File Apple Package... Expanding to directory... /usr/sbin/pkgutil --expand / -name Bom /bin/mkdir Payload Reading /usr/bin/lsbom -p fugMTc >> Extracting Contents of /usr/bin/cd ; /bin/pax -r -f Indexing an Apple Package... -name *.bom .bom .pax.gz
You could take this investigation much deeper using a disassembly tool like Hopper, but that is out of the scope of this blog post.
Jamf Admin Indexing – Such Size Bug
Here is an example of the Jamf Admin’s indexing process using the cURL command (formatted for clarity):
curl -H 'Host: ${JSSHOSTNAME}:8443' -H 'Content-Type: application/xml; charset=utf-8' -H 'Accept: */*' -H "Cookie: JSESSIONID=${JSESSIONID}" -H 'User-Agent: Jamf%20Admin (unknown version) CFNetwork/978.0.7 Darwin/18.7.0 (x86_64)' -H 'Accept-Language: en-us' --data-binary "&username=${USERNAME} &password=${PASSWORD} &packageID={$JSSID} &path=%2Fdirectory &owner=0 &group=0 &mode=drwxr-xr-x &date= &size=such &checksum= &path=%2Fdirectory%2Ftest &owner=0 &group=0 &mode=-rw-r--r-- &date=Dec%203%2014:43:07%202019 &size=such &checksum=935282863 &path=%2Fdirectory%2Ftest_hard_link &owner=0 &group=0 &mode=-rw-r--r-- &date=Dec%203%2014:43:07%202019 &size=such &checksum=935282863 &path=%2Fdirectory%2Ftest_symlink &owner=0 &group=0 &mode=lrwxr-xr-x &date=Dec%203%2014:43:30%202019 &size=such &checksum=3076352578" --compressed "https://${JSSHOSTNAME}:8443//packageIndex.jxml"
Interestingly, there is a bug where size equals “such” (&size=such)? See the example lines above. Creating our own methodology of indexing outside Jamf Admin didn’t have this issue and worked properly.
Enable Debug Mode for Jamf Admin
To log more in-depth and details logs of Jamf Admin create a directory or file named “debug” within the following directory:
/path/to/Jamf Admin.app/Contents/Support
For example, then create a file named “debug”:
touch "/Applications/Jamf Pro/Jamf Admin.app/Contents/Support/debug"
Or create a directory named “debug”:
mkdir "/Applications/Jamf Pro/Jamf Admin.app/Contents/Support/debug"
The output for the Jamf Admin debug log is named CasperAdminDebug.log and will be created in the user’s directory launching Jamf Admin ~/Library/Logs/JAMF/” You can use a terminal command-line utility like tail , cat , less, etc. to view the log:
tail ~/Library/Logs/JAMF/CasperAdminDebug.log
Or use the macOS Console GUI application to view the debug log.
When you launch Jamf Admin, you will see the following mount log information:
'/private/var/folders/ft/jtkcdd4r8xgcty0059_sts980000gq/T/AppTranslocation/663D1E32-A662-4536-9CF8-17A10357B601/d/Jamf Admin.app/Contents/Support/jamf' mount -type afp -server '[JDS HOSTNAME]' -share '[JDS SHARE NAME]' -username '[USERNAME]' -passhash '[PASSWORD HASH]' -visible 1/20/20 10:34:55 AM - -----------------------------------------------------------------------------------------------------------------------Mounting [PASSWORD HASH] Mounted file server <mountpoint>/Volumes/[JDS SHARE NAME]</mountpoint>
Since the debug logs are verbose and can take up unnecessary disk space, it is recommended to disable debug logging after you have completed troubleshooting Jamf Admin removing the following directory or file. Example of remove debug file:
rm "/Applications/Jamf Pro/Jamf Admin.app/Contents/Support/debug"
Example of removing debug directory:
rmdir "/Applications/Jamf Pro/Jamf Admin.app/Contents/Support/debug"
Then index a package in Jamf Admin and you will see something like the following in the log output:
'/private/var/folders/ft/jtkcdd4r8xgcty0059_sts980000gq/T/AppTranslocation/4EEEA080-140C-4DD2-896D-A0A3506B3D5D/d/Jamf Admin.app/Contents/Support/jamf' 'index' '-path' '/Volumes/[JDS SHARE NAME]/Packages/' '-package' '[PACKAGE NAME].pkg' '-saveTo' '/private/tmp/indexes/'
Uninstalling Contents with Jamf Pro
In our testing, using a Jamf Pro policy or Jamf Remote to uninstall didn’t work properly due to its handling of links and installer packages fully indexed wouldn’t uninstall properly.
Build a Test Installation Package
To test Jamf Admin indexing we can build a test installation package with the following command:
$> mkdir -p test_package/Payload/directory $> echo "test" > test_package/Payload/directory/test $> ln test_package/Payload/directory/test test_package/Payload/directory/test_hard_link $> ln -s test_package/Payload/directory/test test_package/Payload/directory/test_symlink $> pkgbuild --root test_package/Payload --identifier my.domain.name.test.package.simple --version 1.0 test_package.pkg
Expand Contents of Test Installation Package
Next, expand the contents of the test installation package to output the PackageInfo contents:
$> pkgutil --expand test_package.pkg example $> cat example/PackageInfo <?xml version="1.0" encoding="utf-8"?> <pkg-info overwrite-permissions="true" relocatable="false" identifier="my.domain.name.test.package.simple" postinstall-action="none" version="1.0" format-version="2" generator-version="InstallCmds-681 (18G103)" auth="root"> <payload numberOfFiles="5" installKBytes="2"/> <bundle-version/> <upgrade-bundle/> <update-bundle/> <atomic-update-bundle/> <strict-identifier/> <relocate/> </pkg-info>
Upload & Index Test Installer Package
Upload & index this test installation package to your Jamf Pro instance using Jamf Admin and install it on a Mac client system.
For example, here are the Jamf Pro contents for our test installer package:
This is what you should see on your client that the installer package was installed…
Uninstall Installer Package Contents
Next, you can use the jamf binary command-line tool to uninstall the test installer package:
First, you want to get the package ID in Jamf Pro by going here:
Settings > Computer Management > Packages > [PACKAGE NAME].pkg
Then get the address of the URL, should look something like the following:
https://your.jss.domain:8443/packages.html?id=598&o=r
You want to look for the id=[PACKAGE ID NUMBER] and get the package ID.
Then you want to run the following command to uninstall the installer package contents with the jamf command-line tool:
sudo jamf uninstall -id [PACKAGE ID NUMBER] -verbose
For example…
# sudo jamf uninstall -id 598 -verbose verbose: Parsing uninstall information... Getting package details from https://your.jss.domain:8443/... verbose: Creating uninstall BOM... Uninstalling... Looking for Applications... Deleting files... verbose: Deleting file /directory/test... verbose: Deleting file /directory/test_hard_link... Uninstalled .
You will notice that the uninstall process left the directory and symlink contents from the install…
We ran into the same issue using Jamf Remote to uninstall, which appears to use the jamf command-line tool anyway.
So, long-story-short, you currently can’t rely on Jamf Pro built-in functionality to properly remove installer package contents and must use other methods like custom scripts that handle different types of installer package configurations like applications that live entirely within /Applications folder or sub-folder only; trusting & running a vendor-supplied uninstaller applications, binaries or scripts; deleting installer package contents based on its installer receipts, or a custom uninstaller script. Depending on installer receipts to completely remove contents means that all file system modifications are contained in the installer package payload and not via pre or post-install scripts. Many vendors use and depend on pre or post-install scripts that are unnecessary and could be done via the standard installer payload methods and be tracked with the installer receipts.
In the end, its too bad Jamf Pro customers need to reverse engineer its process and provide documentation when ideally it should be coming from Jamf. Hopefully, this will change someday.
Automation Framework – Coming Soon…
We are working on a framework that will implement Jamf Admin functionality, Jamf Pro policy, patch and external patch for complete automation that can granularly be configured for your environment and individual needs. If you only want Jamf Admin feature(s) you can implement just those features without implementing policy, path and external patch. You can pick and choose which feature you want and don’t want to use based on your own environment needs and customize the feature based on your own configuration needs. We hope to have a publically digestible code available in the next month or two.
Check out our GitHub Repository for its future release and other projects.
No Comments