Hiding default user folders using a launch agent

New Contributor II

Hi all,

Bit of an odd one. Our organisation needs to allow some aspect of local storage access to accommodate work on large files without constantly writing to network drives. They work on these files and then copy them to mounted AD drives.
I want to restrict the local files that can be written to. My solution has been to create a launchagent that hides all default folders using chflags hidden and schg on the first login of a user. I have used a launchagent because of the impending threat of login hooks being removed.
The issue is that Documents and Downloads never have the flag applied and I have no idea why. It applies to every other folder. I have added a delay before the script is run, added the script to the sudoers file so it can be run as root, changed the code, killed finder and kept it killed for the script duration, and even made the script just try to hide documents and nothing works.
Any suggestions would be appreciated.

FYI I have tried:
find ~ -maxdepth 1 -mindepth 1 -type d -not -name '.' -not -path "/Library" -not -path "*/Desktop" -exec sudo chflags schg {} ; -exec sudo chflags hidden {} ;

sudo chflags hidden $HOME/Documents

sudo chflags hidden ~/Documents


Esteemed Contributor II

@Autton Ever heard the old joke where the patient says to the doctor "It hurts when I do..." and the doctor replies "Then don't do..."? That pretty much sums up trying to make modifications to the Documents folder as of Big Sur. Enabling iCloud Drive on older versions of macOS, especially if the user enabled the Desktop & Documents option, would also blow away any changes every time a Mac restarted. I hadn't seen that behavior with the Downloads folder, but I got tired of fighting the OS before I tried mucking with it.

Valued Contributor

I used to "re-adjust" the Home folders, but gave up banging my head against that one.
If you really have to do it, Please note, I have not tried this since Mavericks. The method I used was to have the Launch agent script, pass the Username to a Launch Daemon script, and have the Daemon script do the heavy lifting. LaunchDaemons run as root. I did it with watch files. Launch Agent runs a touch /path/to/watchfile and the LaunchDaemon is set to activate on the watchfile being looked at. Set the Agent to save the username to a temp file, and pull that into the Daemon script. Just put your watchfile somewhere safe, but where the User permissions allow the logging in user to access it to touch it.

Examples of the plists etc are in my reply here

But I have not tried to adjust the Home folders since Mavericks, and therefore suggest you do loads of testing, if you are going to go down this route. The basic concept of getting a LaunchAgent to run a LaunchDaemon still works, its the Home Folder side I can't say will work.

If Apple is willing to protect Chess with SIP, then I guess they will protect a whole bunch of more important things.

New Contributor II

@sdagley It is unfortunately beginning to look that way. It applies to every folder aside from Documents and Downloads. I do wonder if it is because of iCloud drive, even if it is not on. I think the last thing that I will do is look for a way to stop any iCloud drive daemons or plists from launching on boot before I give up. I have kept a log of my tried methods and descent into madness here: https://apple.stackexchange.com/questions/423046/hiding-default-folders-via-launchagent-not-applying-to-documents
Is there anything on the Jamf Pro side of things that may allow me to achieve what I want?


New Contributor II

Ok, I have solved this and I will explain the answer fully if anyone has a similar issue.

There are certain times when you will need to run a start script/event as sudo. You can do this using LaunchDaemons which are run as sudo at system boots and are run outside of a specific user session. However, there are times where you may want to run something as sudo in user context.
To resolve this, I initially had a plist that called an executable script with sudo as an argument, ie sudo path/to/script/script.sh

The script was added to visudo during the postinstall of the agent, and looked like %everyone ALL = (ALL) NOPASSWD: /Library/Scripts/script.sh. Do not do this. I only go into such detail because to me it seems like the most logical way to go about it. Plists act oddly when parsing the sudo parameter.

Instead, don't bother making the script executable with chmod +x and leave its permissions 700 if it is sensitive. Add a visudo command with the bash/sh parameter like %everyone ALL = (ALL) NOPASSWD: /bin/sh /Library/Scripts/script.sh.

Next, and most importantly create a secondary initialiser script that will call the main script. Call the main script with sudo. This script will need at least 755 permissions. In the Plist, call the initialiser script using no parameters other than bash/sh.

Overall, the process should be:


echo '%everyone ALL = (ALL) NOPASSWD: /bin/sh /Library/Scripts/script.sh' | sudo EDITOR='tee -a' visudo


<?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">

Initialiser script:

sudo sh /Library/Scripts/script.sh

Main script:

Whatever you want