Need help forcing script to run commands under current logged on user

matthsco
New Contributor II

Hi there,

Trying to write a script that does the following

  • Runs under the current logged on user
  • Removes their FavoriteServers.sfl file (or even the whole parent directory)
  • killall cfprefsd
  • killall sharedfilelistd
  • killall Finder
  • Uses the SFLTOOL to add a new entry to the (now empty) FavoriteServers.sfl file

If I make the below code unix executable and run from the users desktop, it works a treat.

#!/bin/bash
rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
killall cfprefsd
killall sharedfilelistd
killall Finder
rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
sfltool add-item -n "OSAKA" com.apple.LSSharedFileList.FavoriteServers "cifs://OSAKA/"
killall Terminal

I think I will need something that actively targets the logged in user. I'm guessing as Casper is currently set to SSH as "HSCO.ADMIN" (local admin account) it will attempt to run all the commands targeting the hsco.admin user profile, instead of the user currently logged on. I tried something like the below. I think it's working to some extent as it kills / refreshes the Finder, but doesn't add anything to the FavoriteServers.sfl file.

#!/bin/bash
currentuser=$(/bin/ls -la /dev/console | /usr/bin/cut -d ' ' -f 4)
su -l $currentuser -c "rm -rf ~/Library/Application Support/com.apple.sharedfilelist/"
killall cfprefsd
killall sharedfilelistd
killall Finder
sfltool add-item -n "OSAKA" com.apple.LSSharedFileList.FavoriteServers "cifs://OSAKA/“

Any help would be much appreciated! :)

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

@matthsco Here's an example of how you could deploy the script into a discrete file and run it as the user all in one script, so no need to package it up and deploy it for example. My recommendation on this comes because as I mentioned, you have multiple commands all needing to run as the logged in user, not just one or two. My personal opinion is that when you start going to 3 or more consecutive commands that have to run as something other than the account running the script it's best to have them all in one script and run the whole script as the user.

#!/bin/bash

loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

if [[ "$loggedInUser" != "root" ]] || [[ "$loggedInUID" -ne 0 ]]; then

cat << EOF > /private/tmp/script.sh
#!/bin/bash
/bin/rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
/usr/bin/killall cfprefsd
/usr/bin/killall sharedfilelistd
/usr/bin/killall Finder
/bin/rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
/usr/bin/sfltool add-item -n "OSAKA" com.apple.LSSharedFileList.FavoriteServers "cifs://OSAKA/"

exit 0
EOF

else
    echo "No user logged in. Can't run as user, so exiting"
    exit 0
fi

if [ -e /private/tmp/script.sh ]; then
    /bin/chmod +x /private/tmp/script.sh
    /bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/private/tmp/script.sh"
    sleep 2
    echo "Cleaning up..."
    /bin/rm -f "/private/tmp/script.sh"
else
    echo "Oops! Couldn't find the script to run. Something went wrong!"
    exit 1
fi

So let me explain what's going on in the above so it's clear.

First, it's getting the logged in user and the logged in user's UID.

Next, it checks to see if either the logged in username is "root" or the UID is "0" either of which would indicate that no-one is logged in. If no-one is logged in the script needs to exit since the point is to run a script as an actual logged in user.

If both those checks turn out to be negative (someone is logged in), it continues by creating a local script in /private/tmp/ using a process that takes input and pipes it to local file.

It then checks to make sure the script is actually there and if so, sets it to be executable.

Finally, it uses a launchctl asuser process to run the entire local script as the logged in user.

It then cleans up the script and exits.

I ran a quick test with the above script (different server address) on a test Mac from a Jamf Pro policy and it worked. It successfully added in my custom server address to the Connect to Server window. I did get an error about the FavoriteServers.sfl file not being found, but this Mac was recently re-imaged and likely didn't have such files. I guess the script could be changed to check for their existence first before trying to rm them, or just pipe errors to /dev/null/ so it doesn't complain. I also noted that your script seems to be trying to delete the com.apple.LSSharedFileList.FavoriteServers.sfl file twice at different times, but I'm not sure why. Maybe it only needs to happen once.

Anyway, give the above a try and see if it works for you.

View solution in original post

25 REPLIES 25

hkabik
Valued Contributor

Scripts are run as root. Does this work?

#!/bin/bash
currentuser=`stat -f "%Su" /dev/console`
sudo -u $currentuser rm -rf ~/Library/Application Support/com.apple.sharedfilelist/
killall cfprefsd
killall sharedfilelistd
killall Finder
sudo -u $currentuser sfltool add-item -n "OSAKA" com.apple.LSSharedFileList.FavoriteServers "cifs://OSAKA/"

Works for me.

matthsco
New Contributor II

@hkabik thx for the response! -

When I open terminal in the current session/user and run the script you provided, it works.

When I deploy this script through CasperRemote, it seems to go through a few steps (Finder closed & re-opened) but didn't add a new entry to the Connect To Servers window. (unfortunately I need to look at a separate issue why my logging isn't working takes me to a broken page)

Any other suggestions what I might be doing wrong here? I believe CasperRemote uses our local admin account ("hsco.admin") to authenticate to the local computer, but based on the script it shouldn't really matter from what I understand.

Would love to hear if you had any other suggestions what I might be doing wrong here...

matthsco
New Contributor II

Ok managed to get the logs working, was a bit confused by this bit:

Script result: rm: /Users/hsco.admin/Library/Application Support/com.apple.sharedfilelist/: Permission denied
Created item with URL: cifs://OSAKA/ in list:

From what I understand the first few lines of script tell it not to run as root but to switch to the active / current session and perform the commands within there - so in this case I would expect it to be pointing to /Users/matt/etc....

I'll check in a moment but I can only assume the "created item with URL in list:" meant that it created this under the admin profile, not my current user ("matt")

hkabik
Valued Contributor

sudo -u $currentuser tells it to run the command as the current console owner, so whoever is logged in. Or should...

Throw an echo $currentuser in to verify that variable.

matthsco
New Contributor II

Yeah echo $currentuser returns "matt" as expected... that's why I'm confused that the logs show /Users/hsco.admin

hkabik
Valued Contributor

Try /Users/$currentuser/ rather than ~/

matthsco
New Contributor II

Yeah no luck on that either unfortunately

mm2270
Legendary Contributor III

Hi @matthsco I believe I was helping you on this script on this other thread. Did the syntax I provided there work by chance?

If not, I have a few other suggestions you can try. Since you have several commands you're needing to run as the user, a few other options you can look at are:

  • Craft and deploy a LaunchAgent and the script that can run the script as the user, which is more or less guaranteed to work
  • Send just the script itself down to the Mac in a specific location and then call the script as the user (rather than running commands in the script as the user)
  • There is an additional "run as user" syntax you can use, which is more reliable, but also harder to work with and understand initially

If you need more info on any of the options above, post back and I can provide more details on how you would do any of these

matthsco
New Contributor II

@mm2270 yes you were assisting me on the other thread! thanks again, it's much appreciated.

So basically I took a slightly different approach from the original thread, I ended up telling it to delete the local file, stop/kill a few services and then use sfltool to add the server to the connect-to-servers window.

The script works well when running as the local user, but seems to fail when deploying the script through Casper (even with the additional code telling it to perform the commands as the local user) At the moment Casper logs are showing command executing successfully but it's not actually removing the FavoriteServers.sfl or adding the new server entry.

What exact steps would you suggest in Casper for sending the script to the local computer, then having the script run as the logged in user to perform the commands?

mm2270
Legendary Contributor III

@matthsco Here's an example of how you could deploy the script into a discrete file and run it as the user all in one script, so no need to package it up and deploy it for example. My recommendation on this comes because as I mentioned, you have multiple commands all needing to run as the logged in user, not just one or two. My personal opinion is that when you start going to 3 or more consecutive commands that have to run as something other than the account running the script it's best to have them all in one script and run the whole script as the user.

#!/bin/bash

loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

if [[ "$loggedInUser" != "root" ]] || [[ "$loggedInUID" -ne 0 ]]; then

cat << EOF > /private/tmp/script.sh
#!/bin/bash
/bin/rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
/usr/bin/killall cfprefsd
/usr/bin/killall sharedfilelistd
/usr/bin/killall Finder
/bin/rm ~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl
/usr/bin/sfltool add-item -n "OSAKA" com.apple.LSSharedFileList.FavoriteServers "cifs://OSAKA/"

exit 0
EOF

else
    echo "No user logged in. Can't run as user, so exiting"
    exit 0
fi

if [ -e /private/tmp/script.sh ]; then
    /bin/chmod +x /private/tmp/script.sh
    /bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/private/tmp/script.sh"
    sleep 2
    echo "Cleaning up..."
    /bin/rm -f "/private/tmp/script.sh"
else
    echo "Oops! Couldn't find the script to run. Something went wrong!"
    exit 1
fi

So let me explain what's going on in the above so it's clear.

First, it's getting the logged in user and the logged in user's UID.

Next, it checks to see if either the logged in username is "root" or the UID is "0" either of which would indicate that no-one is logged in. If no-one is logged in the script needs to exit since the point is to run a script as an actual logged in user.

If both those checks turn out to be negative (someone is logged in), it continues by creating a local script in /private/tmp/ using a process that takes input and pipes it to local file.

It then checks to make sure the script is actually there and if so, sets it to be executable.

Finally, it uses a launchctl asuser process to run the entire local script as the logged in user.

It then cleans up the script and exits.

I ran a quick test with the above script (different server address) on a test Mac from a Jamf Pro policy and it worked. It successfully added in my custom server address to the Connect to Server window. I did get an error about the FavoriteServers.sfl file not being found, but this Mac was recently re-imaged and likely didn't have such files. I guess the script could be changed to check for their existence first before trying to rm them, or just pipe errors to /dev/null/ so it doesn't complain. I also noted that your script seems to be trying to delete the com.apple.LSSharedFileList.FavoriteServers.sfl file twice at different times, but I'm not sure why. Maybe it only needs to happen once.

Anyway, give the above a try and see if it works for you.

matthsco
New Contributor II

Thanks @mm2270 that's great, I'll give this a go now and let you know how it goes!

Re: duplicate line to delete the FavoriteServers file, that was more of a precaution. I wanted to make 110% sure it was clearing the file before adding 1 line for the new server

matthsco
New Contributor II

Thanks @mm2270 that's great, I'll give this a go now and let you know how it goes!

Re: duplicate line to delete the FavoriteServers file, that was more of a precaution. I wanted to make 110% sure it was clearing the file before adding 1 line for the new server

matthsco
New Contributor II

@mm2270 tested and works!

Thank you so much for your assistance here, and to all those that helped across the various threads : )

Wakko
Contributor II

@mm2270 Thanks, this is exactly what I was looking for. Worked like a charm sir, much obliged sir.

hpavlic_
New Contributor III

@mm2270

Quick question, can you also install configuration profiles with that commant

/bin/launchctl asuser

Because i want to run configuration profile which needs to be run in user context but every command i try it ends up with configuration manager tool asking user to enter their password.

Can that be avoided with a command like that, or is there another way?

mm2270
Legendary Contributor III

@hpavlic. Yes, it can be used for that actually. In fact, you can take a look at an API based script I made for downloading and installing Configuration Profiles that were created and stored in your JSS. The script will pull the Config Profile down and determine if it was set to Computer Level or User Level and install it in the appropriate space.

That being said, it wasn't clear if you intended to install this profile from a Casper/Jamf Pro policy or if it needed to be installed outside of the product. But the launchctl asuser syntax is what I use in the script to install "user" profiles as the logged in user.

Anyway, the script is located here

hpavlic_
New Contributor III

@mm2270

Thanks for the response.
Yes, I am trying to install profile through Casper/Jamf Pro policy, for testing purposes I downloaded the profile from Casper and put it manually on a Mac I run tests on.
Then I ran the following policy with the script:

#!/bin/bash

loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

/bin/launchctl asuser "$loggedInUID" sudo su - "$loggedInUser" -c "profiles -I -F /private/tmp/signed.mobileconfig"

And when the policy runs Configuration Manager Tool will ask the user to enter their password.

mm2270
Legendary Contributor III

You have part of the command wrong. It's not sudo su - "$loggedInUser", it's sudo -iu "$loggedInUser" That may account for why you're seeing the prompt to enter a password. Try that and post back if you're still seeing a prompt.

hpavlic_
New Contributor III

@mm2270

I have tried the following based on your suggestion:

/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" profiles -I -F "/private/tmp/signed.mobileconfig"

And still asking for password when ran :(

mm2270
Legendary Contributor III

@hpavlic. Ok, I think I now see the problem.

Change that line to look like this please

/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/usr/bin/profiles -I -F "/private/tmp/signed.mobileconfig""

I don't know for sure if this would be the reason for the prompt, but when using that launchctl asuser synatx, the actual command to be run as the logged in user must be surrounded in double quotes. Any actual double quotes within the command need to be escaped with a backslash. Some other characters need to be escaped as well depending on what you're running.

The way you had it, I think what was happening is it was trying to run "/private/tmp/signed.mobileconfig" only as the user, which may be why they were being prompted for a password. This is kind of the equivalent of opening the .mobileconfig profile in the Finder.
Anyway, try that and see if it works.

hpavlic_
New Contributor III

@mm2270

Now there is following error:

Script exit code: 127
Script result: -bash: /usr/bin/profiles -I -F "/private/tmp/signed.mobileconfig": No such file or directory
Error running script: return code was 127.

mm2270
Legendary Contributor III

@hpavlic. Well that's an odd error, since 127 would mean it can't find the profiles command. At least that's what it looks like. That doesn't make sense to me since profiles has been a part of the OS for years now. Can you confirm that the profiles binary is on the Mac? If you do which profiles in Terminal on it, it should show the path to it. If it errors, then it's not able to find it. Could be a PATH environment issue that needs to be addressed.

Other than that, have you double checked to make sure the actual mobileconfig file is in /private/tmp/ and is named "signed.mobileconfig"?

hpavlic_
New Contributor III

@mm2270

When running which profiles in terminal i get:

/usr/bin/profiles

And yes there is .mobileconfig file in the right location and named correctly. Last commands we tried all ran that config file so location is correct.
The issue is maybe that the profile is grabbing certificate from PKI server and prompt for password is for trying to install the certificate into the keychain? Didn't have any experiences in this area before so I could be saying something wrong.

mm2270
Legendary Contributor III

Well, I was going to ask what the profile actually does. It's certainly possible that the prompt is coming from needing to do something in the user space after the profile gets installed. But, if you just manually install the profile under the current account in Terminal, do you also get a password prompt? If so, then I'd guess that's what's going on. If not, then I'm not 100% sure. I don't have any profiles that have a PKI payload in them to test with, so I'm not sure. Could have something to do with it though.

If you deploy the profile from the JSS over APNs, assuming you can do that, does it work? Is the profile set up in the JSS to be a "User level" profile?

hpavlic_
New Contributor III

@mm2270

Tried with API script an this was the result:

Script result: Single ID was passed. Running in single mode
Obtaining Configuration Profile as xml…
Reformatting html entities in the xml to proper tags…
Obtaining the old ID string from the xml…
renameFlag was set to: false…
Creating final .mobileconfig file…
Profile has a User Level scope
Installing Configuration Profile as current user…
-bash: /usr/bin/profiles -I -F "/tmp/3.mobileconfig": No such file or directory
Installation result: Failed