Don’t have permission to create a file in Whitebox

If you get an error that you cannot create a file inside a folder when building in Whitebox Packages, take a look at where the original file is located.

If the file is located within your user folder, you might check and see if you’ve given permission to your ~/Documents or ~/Downloads folder. Or perhaps you’ve given Full Disk Access even.

Somehow, even with these permission set I continue to get this error. I am currently running Big Sur 11.2 and Packages 1.2.9, current as of this writing. I have found that a good workaround is to stage the files I am using in my package in the /Users/Shared folder. The permissions are more open in that folder as its intended for multiple users to access. If I shift the location of the files to be used into that folder I can successfully build.

Deleting user folders in labs on a schedule

In multiuser labs on campus we often have people log in once, and never log in again. Sometimes they pick a machine and always use that, sure, but inevitably at some point in the semester we start to run low on disk space. For that reason I have a policy to run once a week on our lab systems that runs a script to check if a user profile has been logged into within a variable number of days. For most systems I’ll use 28 days.

All lab systems are subject to replacement in the event of hardware or software failure, and as such generally a student (or faculty member) should be using network storage or google drive. At the same time we want to provide the convenience to users who may use the same system every class or study period.

This script is based on a script from a coworker (who appears to have pulled it from a GitHub and modified it). Its fairly simple but searches based on the last modified and excludes any user currently logged in. I use a variable (#4) to assign different ages based on the locations.

## Checks if the variable has been provided
if [[ -z $days ]]; then
	read -p "Profile Age:" days
## new shorter bash method to get logged in user
loggedInUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name ꞉/ && ! /loginwindow/ { print $3 }' )
## Do not delete the current user or the shared folder, add additional users if needed
permanent=("Shared" "$loggedInUser")
## Verify script is being run as root
if [[ $UID -ne 0 ]]; then echo "$0 must be run as root." && exit 1; fi
## users that have not been active in the specified number of days
allusers=`/usr/bin/find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -mtime +$days`
echo "deleting inactive users"
## iterate through each inactive user, check if they are in the permanent list, then delete 
for username in $allusers; do
	if ! [[ ${permanent[*]} =~ "$username" ]]; then
		echo "Deleting inactive (over $days days) account" $username
		# delete user
		/usr/bin/dscl . delete $username > /dev/null 2>&1
		# find and delete home folder (in case it is not in /Users/)
		home=$( dscl . read /Users/${username} NFSHomeDirectory )
		/bin/rm -r $home
		echo "skip" $username
echo "complete"
exit $error

Edit: I made some changes to the above script, including using a method to get the current logged in user via bash found here,-in-Bash/ and some errors pointed out in a comment in my logic where I conflated username and home folder in a variable.

Edit 2: it seems the codeblock above had a strange WordPress induced bug in line 10 where it was displaying a colon backslash as an emoji. I have worked around this to display correctly, but please make sure you copy from the correct script located on GitHub here.

Loaner and Lab “Reimage”

We have found ourselves in need of more loaner laptops than ever before with growing numbers of students and faculty attending class remotely. In an effort to come up with a simple way to prepare these laptops after they are returned and sanitized I went looking for how I can set up with the least interactivity required.

After some research, I found this JamfNation thread. I can launch Jamf’s jamfhelper application and run at the login window, but only if its opened from a launchdaemon. That led me to this script which builds a launchdaemon to run jamfhelper and run through our prep workflow.

Luckily, as I described in this post from my JNUC2020 presentation, I have most of our software set up with policies on custom triggers to run with DEPNotify for our standard and zero touch deployment strategy. I took above script and customized it, and created a new prestage enrollment to skip account creation then run this script on enrollment. Of course I had to assign each serial number to this prestage enrollment so I utilized the MUT‘s Groups and Prestages template to upload the list of serial numbers to the newly created prestage for this refresh process.

With that configuration, we can have a student or help desk associate go through the setup on a lab or prepare a recently returned loaner using an erase install progress in Self Service. This allows us to set things up quickly without needing any passwords shared or requiring someone to go through the user setup process.

While not as pretty as DEPNotify, this does show a useful progression

Setting Zoom Preferences

Zoom has made lots of changes recently, both for security and management. In management we’ve seen some nice things including the ability to set preferences as preferred but not enforced. These are now set under a new key of PackageRecommend.

The article from zoom is quite helpful as it gives detail on settings and their use. First you’ll need to download the IT installer for distribution, and you’ll need to create a plist file to distribute. In our case, I made a package to drop it in the required location. Currently, the article specifies /Library/Preferences as the location to put this file.

This is a sample of the settings you can configure with the plist using PlistEdit Pro

I used PlistEdit Pro to edit this, though as they are XML files a number of programs will work just fine.

From Hands-on to Zero Touch (JNUC2020)

Hi folks! If you’ve found your way here for more detailed information from my session at JNUC 2020, From Hands-on to Zero Touch, welcome! I’ve detailed the steps here outlining the process that took us to being able to support zero touch when suddenly everyone was remote.

Initially we were using DeployStudio to image our Macs. The workflow was to erase the machine and push down static image known as a Gold Master. DeployStudio worked with netboot, which is no longer available as an option on new Macs. It was also able to install packages, and truthfully we were installing many items from packages for multiple workflows. Most of you know that this is no longer the preferred method, and hasn’t been for some time due to changes in Apple’s security and macOS. We initially were modifying the Default User Template and found that certain things were no longer working when customized. We started seeing permissions issues crop up, and with certain updates machines weren’t getting firmware updates.

One of the biggest reasons to move was the changes with User Approved Kernel Extension Loading (UAKEL) and User Approved Mobile Device Management (UAMDM). These two settings specifically require approval at each machine unless you enroll with DEP/ADE. We migrated to using Jamf Imaging, which was similar in some ways. We wiped the drive, but used a blank OS image created with AutoDMG and installed all applications and settings individually with packages. This was an important setup step to allow us to more easily move to a Device Enrollment Program, or DEP, (now known as Apple Device Enrollment or ADE) workflow. By having a workflow with packages we were able to migrate and test easily a new automated workflow.

But this spring, suddenly everyone was remote. We still had new employees starting who needed computers. I made sure our package repository was available in the cloud by replicating our on-prem repo to Jamf cloud. I ensured that new users would have NoMAD and VPN installed to make sure they could access network resources and sync their password to their AD credentials even when off campus.

Here’s a short list of the major steps needed to make sure we were ready to deploy zero touch:

  • Sign up for Apple’s Device Enrollment
  • Ensure our JSS and package repo is available off campus
  • Configure Prestage Enrollment
  • Utilize Inventory Preload
  • Configure setup with DEPNotify and
  • Use NoMAD to sync a local password with the user’s AD password
  • A backup plan in Self Service in case our DEPNotify workflow doesn’t start because of the enrollmentComplete trigger failing

And here is a list of important tools I used in the process:

  • DEPNotify: a great utility to make it look nice while installing your standard software
  • DEPNotify-Starter: A bash script you can customize to run an array of policies and display output to DEPNotify
  • NoMAD: An alternative to binding to AD, allows a local user account maintain a kerberos ticket and sync your password with an AD account password.
  • Outset: A utility that allows scripts to be run at various times, login or boot and with options for running once or every time. Useful to set some specific user settings without modifying the user template.
  • Dockutil: Allows for modification of the dock using a script.
  • Desktoppr: Allows changing the user’s desktop background without asking for additional permissions as osascript does.
  • Whitebox Packages: A GUI application to build package installers. Alternately, you can use Jamf’s Composer.
  • Profile Creator: A GUI application to build granular profiles and optionally sign them.
  • the MUT: This is a GUI tool for uploading information to Jamf using the API. Allows you to move devices between different Prestage enrollments, update device inventory information and clearing inventory or EA data for specific machines.
  • Jamf API: scripts written using this to grab inventory data to customize the system

Signing Up for Apple’s Device Enrollment

Setting up an account on Apple School Manager or Apple Business Manager is the first step. I found it to be generally stress free. A simple form to fill out, followed by a call to my boss to verify things. Once enrolled, I was able to link our Apple Customer Number to the account and import all our purchases to assign to our Jamf Pro instance.

A fairly simple form to fill out

Apple Business Manager and Apple School Manager recently changed their interface, but I initially was able to upload and assign machines using a csv exported from my inventory system.

Ensuring Jamf is Available Everywhere

We had migrated to Jamf Cloud some time ago already, but were still using a local package repository. I was able to take that repository and replicate it to our cloud storage and set that cloud storage as our main repository. While time consuming, it worked eventually. I just had to ensure my machine did not fall asleep during that initial replication, for this I used the caffeinate command.

Just one button to click in Jamf Admin

I followed this with keeping our on campus distribution, and and I created a Network Segment to direct traffic to the local package repository. I also found that you cannot immediately replicate a package you’ve uploaded, and you must wait for a short while before a cloud package can be replicated.

Network segment for on campus addresses directed to the on campus server.

Configure Prestage Enrollment

There are a few things to keep in mind here, if you apply a profile at this point you’ll need the machine to still be in scope. If you deploy a package with prestage enrollment you initially needed a cloud repository as your main, and it needs to be signed. This has since been amended to allow on-prem to host a prestage package, but this could be problematic if a machine is powered on and connected off campus.

There are customizations you can make to the setup assistant like skipping options, or adding profiles and packages.

Skipping options to speed up setup.

Utilize Inventory Preload

First you’ll need to make sure you have Buildings and Departments populated. This can be done manually, or with an API script to upload. I use these to scope specialized software and printers based on location or department (as some departments may be in more than one building on campus). You will get an error if you try to use a building or department that does not yet exist.

There are many fields available for Inventory Preload

Once the file is prepared you can upload it, in the settings area. After uploading you can view your data.

Your view will include the fields you choose, but this is a good way to verify your data.

Configure setup with DEPNotify and DEPNotify-Starter

I configured DEPNotify with a series of policies to install software scoped to all machines, or some to just specific departments or buildings.

Most importantly here is making sure you have policies for all the software and user customization you will apply. I deploy outset, dockutil and desktoppr and scripts utilizing them with the outset logon-once folder so they run once to create a basic setup for each user. Edit: here is a post with some sample scripts to set user settings with outset, dockutil and desktoppr.

Policies sorted with a name for DEP and a trigger with DEP to make it easier to see

The main customization with DEPNotify-Starter was to create my own array of policies and display text. I have one version of this script and each policy is scoped based on things like the department and building that we set in inventory preload.

Array of policies with custom triggers, and display text for DEPNotify

I also deploy software for things like security, our basic applications like web browsers and Microsoft office. I have multiple policies so they can be scoped as needed to departments, academic facilities, or specific labs. I utilize the Jamf API with scripts to customize, as detailed here. These API scripts are one of the reasons I use inventory preload, I can assign a machine to a user based on the serial number and use it to set up with the appropriate building and department.

Use NoMAD to sync a local password with the user’s AD password

Fairly straightforward here, we push NoMAD, the launch daemon and a profile to configure the software. Once the user’s account is configured, if they are on campus they can log in and sync their password. If they are off campus, they can do the same once they log in via VPN.

Profile Creator has presets for NoMAD to create profiles you can upload to Jamf.

A backup plan in Self Service

A custom trigger on the DEPNotify-Starter policy allows me to set it in Self Service to kick off in case the enrollmentComplete trigger doesn’t work for some reason.

Using the jamfEvent script I detailed here.
Configured to display in Self Service

Hopefully this clears up some of the steps required to pivot to a modern deployment workflow that is compatible with zero touch.

Setting up FileVault with a Self Service button

Using some of the scripts I’ve mentioned I created a policy to enable FileVault encryption with a button in Self Service. In macOS 10.15 Catalina a new feature called the Bootstrap Token was introduced, which gives a newly created AD mobile account Secure Token access delivered from the MDM. This gives permissions to enable FileVault without a user who initially set up the computer standing over someone’s shoulder to input a password.

The policy is set up in a few parts. There is a one policy to enable encryption, a static group to which that policy is scoped, a profile to lock the FileVault pane in System Preferences, and a Self Service policy to kick it off.

The Self Service policy itself is simple. First it adds the computer to the static group, then it runs the the encryption policy by its custom trigger. The profile to lock the FileVault pane in System Preferences scoped to the static group.

This method does require a user to log out and then log back in for it to enable encryption, but with new T2 based systems the encryption is instant. Newer pre-T2 systems on SSD are pretty quick as well.

Installing with choices.xml

Some application installers have a lot of options or install additional software you may not use. You can create a choices XML file and customize the installer in many cases. Unfortunately, Jamf Pro does not natively support using a choices.XML file. There are a few ways to go about distributing software using one with Jamf Pro. You can repackage the software and run the install with a post install script assumes that you have cached the installer and a completed choices XML file to a staging location, in this case /Library/Management/ and runs the installer with the options, then deletes the cached files. The variables used are for the package name and the choices XML file name.

installer -applyChoiceChangesXML "/Library/Management/${choicesName}" -pkg "/Library/Management/${pkgName}" -target /

rm -rf "/Library/Management/${choicesName}"
rm -rf "/Library/Management/${pkgName}"

I deploy both Office and Cisco AnyConnect VPN and modify the installation as we do not utilize all the applications included. The reason this works for me is I can create a policy to cache the Office or AnyConnect installer and a separate choices XML to install only the required applications at the time. I may have a group that wants Outlook, while most installs do not, or a group requesting OneNote. Having one package for the installer for Office that is kept up to date and can be installed with the required options lets me create multiple policies that can reference a single installer that I can keep up to date without needing to update multiple policies.

Making Panopto Available in Self Service

As most of the US is now doing remote instruction to practice better social distancing, we’ve found ourselves using new tools more frequently. Panopto is a tool that is for recording classes and being able to distribute later – it lets you record from a camera and microphone and screen share, and it can be uploaded for students to reference.

We’ve been using Panopto for some time, but now we are getting requests to install in en masse. The Panopto installer does some unusual stuff that caused complications when trying to deploy with Jamf’s Self Service. First, it creates a hidden user account to manage uploads to the server. That user needs specific permissions, and in Mojave and Catalina it can cause some issues. If you are following certain security protocols you may need further exceptions for this user account for it to work. It also assumes the installer is being run by the user. We found that when Jamf installed Panopto it was either not creating the account, or it was creating it but failing to give it appropriate permissions.

We saw multiple errors, mostly an error 84 which we couldn’t find documentation for, or an error uploading. It seemed the issues with these were either that the user Panopto creates, panopto_upload, did not have permission to the folder or was not created correctly.

In order to make this work in Self Service I worked out the following steps:

  • Due to failed and incorrectly configured installs the first step is a script I wrote based on the instructions to manually uninstall Panopto. This helps as there were case where Panopto was installed and nonfunctional. The script uses the $3 variable in Jamf for Self Service, but it can be run manually and will use the logged in user if $3 is not specified.
  • Second, we install a profile to ensure the correct hostname is added in settings. Panopto’s installer is supposed to use a hostname in the installer’s filename but I’ve found that to be inconsistent when deployed with Jamf. This is a profile using the Application & Custom Settings payload in Jamf.
  • A script originally written by @macdude22 on the macadmins slack to create the Panopto user correctly before install.
  • Installing the Panopto 7.3 package as provided by Panopto’s support.
  • Running a permissions fix for the user in Self Service.

In testing with Mojave and Catalina, the Self Service installer now runs correctly for the user in Self Service. For now, this covers most of our use case. There will be an additional requirement on shared systems to ensure that the panopto_upload user has permissions for each user who logs in. Tentatively that will run using outset in a login-once script.

Migrating existing mobile AD accounts to Local accounts with NoMAD in Self Service

Moving from mostly on campus and AD bound machines with mobile accounts to working remotely for an unspecified time brings a lot of challenges. one of them is ensuring your password correctly stays in sync when changed, and ensuring your FileVault access and login keychains remain with your login password is important too. We’d had issues with those already, and were testing NoMAD already on campus as a tool to avoid this. NoMAD does not require a bind to AD, but can still sync your password with your AD account and ensure the FileVault and login keychain passwords update correctly.

As part of my test I had a Self Service policy with a script to turn a mobile account into a local account, then install NoMAD and the required profile. This was initially so we could take advantage of the bootstrap token, and use in conjunction with a Self Service policy to enable encryption.

The main part of the process is, based on Rich Trouton’s interactive script but intended for use in Self Service. It uses the #3 variable to pull the user logged in to Self Service and migrate that account if it is in fact a mobile account, and retains admin permissions as it is configured in our environment. The policy is configured to run 3 things; this script to migrate the account, install the NoMAD profile and then the NoMAD application and launchagent.

Alternately I could modify the script to run on the currently logged in account to the OS for Self Service. In our case I don’t believe this will be any more effective. It could be used as part of a policy to migrate systems to NoMAD in the background. Currently in Self Service we can scope to just the machines we are testing with so we have control over the test as we move to a wider scale.