Help running login script as user

donmontalvo
Esteemed Contributor III

The attached script runs fine when manually invoked...how can I get it to run as a login script as the current user (not as root)?

#!/bin/bash

IFS=':'
for pvm_file in $( "/Users/Shared/Parallels" | grep .pvm | tr '
' ':' ); do
prlctl register "/Users/Shared/Parallels/${pvm_file}" --preserve-uuid no
done
unset IFS

I know I need to add $3 but how do I add it to this script?

TIA,
Don

--
https://donmontalvo.com
2 ACCEPTED SOLUTIONS

jarednichols
Honored Contributor

Capture the owner of /dev/console with

user=`ls -la /dev/console | cut -d " " -f 4`

and then ```
sudo -u $user <command>
```

Larkin will tell you to use awk. I'll tell you to use cut.

View solution in original post

tlarkin
Honored Contributor
Larkin will tell you to use awk. I'll tell you to use cut.

Hahaha I just caught this. I only use awk because I use it more frequently than cut. Otherwise if it gets the job done I could care less.

Cheers
-Tom

View solution in original post

29 REPLIES 29

mm2270
Legendary Contributor III

Can you explain briefly what the above script is doing? I don't use Parallels, so I'm not familiar with some of the commands in there. Is it providing a registration key for the software?

rockpapergoat
Contributor III

use a launchagent instead. do you really need to do this on every login?

jarednichols
Honored Contributor

Capture the owner of /dev/console with

user=`ls -la /dev/console | cut -d " " -f 4`

and then ```
sudo -u $user <command>
```

Larkin will tell you to use awk. I'll tell you to use cut.

rockpapergoat
Contributor III

or use a launchagent, and it will run as the user on login without having to determine who the user is.

rockpapergoat
Contributor III

to clarify, if all you need to do is run the script above on login with no changes, do something like the following:

  1. save the script to /usr/local/bin and make it executable.
  2. drop in a launchagent that calls the script under /Library/LaunchAgents with the proper permissions.

the launchd plist might look like this:

<?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>Label</key>
    <string>com.company.something</string>
    <key>LowPriorityIO</key>
    <true/>
    <key>Nice</key>
    <integer>20</integer>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/something.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

donmontalvo
Esteemed Contributor III

Sorry for the confusion, I spun off the question from the previous thread. The tool being used is prlctl which is installed by Parallels and allows manipulation of virtual machines, settings, etc.

http://kb.parallels.com/en/112013

We are using the Parallels Auto Deploy wrapper package to deploy Parallels 7 along with virtual machines (requires volume license key of course).

http://www.parallels.com/products/enterprise/desktop/

The package works fine for all existing users. It registers the deployed virtual machines, so when the user launches Parallels 7 it displays the virtual machines that we deployed, no action needed on the user's part.

However...it doesn't do anything for future users. So when a new user logs on to the Mac for the first time and launches Parallels he/she is prompted to:
1. Navigate from ~/Documents/Parallels (the consumer default) to /Users/Shared/Parallels (the enterprise default).
1. Select the virtual machine and click ADD button to register it in Parallels.

  1. User is then prompted for admin rights to register the virtual machine...(NOOOOOO!!!!!!!).

Vlad's script eliminates the need for user interaction... :):):)

What Vlad (Parallels enterprise engineer) did was provide a script that has to be run once as the user. The script inventories all virtual machines in /Users/Shared/Parallels and registers them for that user. The beauty of the script is it is non-distructive...so if a virtual machine is already registered it exits silently...and if the user registered any virtual machines that are not in the /Users/Shared/Parallels default path it won't effect those either.

Jared, thanks for the pointer...I'll test this and shout back.

PS, we plan to run this using Casper policy set to run the script Once Per User (so no need for launchd).

Don

--
https://donmontalvo.com

donmontalvo
Esteemed Contributor III

@jarednichols Just curious...isn't $3 or $userName supposed to allow us to run script as current user?

Don

--
https://donmontalvo.com

rockpapergoat
Contributor III

it's not confusing. if you use a launchagent, you won't need to know the currently logged in user's shortname or any future local or network account names, for that matter. it will fire on login, regardless. for things like this, i don't see any need to use a casper policy that mounts the casper share just to run a script. if it needs to work locally, keep it local.

i just figured i'd give you an alternative approach. "teaching to fish," etc.…

donmontalvo
Esteemed Contributor III

@rockpapergoat Thanks, the launchd suggestion looks great, but we want to try to use the existing Casper functionality first (run script Once Per User), and if the functionality isn't already there we can circle back and try the other methods like launchd. I'm going to try to add the lines recommended by Jared and will shout back with results.

--
https://donmontalvo.com

rockpapergoat
Contributor III

sort of my point: the casper approach is more work.

donmontalvo
Esteemed Contributor III

@rockpapergoat Agreed, a bit more work to set up...but in our case easier to manage (especially whn you have staff all over the world who share the same tools). ;)

--
https://donmontalvo.com

tlarkin
Honored Contributor

Hey everyone,

I think maybe a good feature request would be to run a policy as a user, then maybe the Casper Framework down the road can have launch agents run your script like Nate mentioned in this thread. I think this would be a totally awesome ability, if you all feel the same please request it.

Using the current options, if you enable login hooks in the framework you can use the $3 to option to return the current logged in user. You can also set manual parameters to the script in Casper Admin to script to run certain things or set variables.

I think launch agents are a good idea, but the one caveat is they would always run at that user's log in (or any user login depending on how you run the agent) where Casper can limit it to run once per a user and then be done.

Thanks,
Tom

donmontalvo
Esteemed Contributor III

@tlarkin Hi Tom, thanks...so back to my original question:

I know I need to add $3 but how do I add it to this script?

Based on Jared's response, I wonder if we can use this:

sudo -u $3 <command>

But how do you wrap this around the above script? Calling all script gurus.. :D

Don

--
https://donmontalvo.com

Matt
Valued Contributor

Could you maybe package the script as a postinstall script and then deploy it at login?

rockpapergoat
Contributor III

@matt, that's more complicated. i wouldn't do it that way.

@don try "sudo -u $3 prlctl…"

do you have anyone on staff who can help you write these things? it feels like posting to a community board every step of the way is pretty inefficient. or just try some stuff till it works.

donmontalvo
Esteemed Contributor III

@rockpapergoat The questions is how to use $3 on the script posted at the top of this thread. Unfortunately the below won't work since we're not running a single line command:

"sudo -u $3 prlctl…"

I'll open a ticket with JAMF, they should have the answer on how to run a shell script as a user, one time, at login. ;)

Don

--
https://donmontalvo.com

acdesigntech
Contributor II

just su $userName. Policies run as root, so you don't need a password to switch to any less privileged user.

Then just run the rest of the script. It's how I get around Integrated Colors shtty sht sht sht ColorEyes installer

acdesigntech
Contributor II

or you can use applescripts do shell script commands and port your script to applescript, and have a bash wrapper that calls osascript using the HEREDOC method. It's what I use to unlock a users desktop automatically... Ex below:

osascript<<ENDDetectUnlock
set unlockAfter to 1202 -- The desktop is set to lock after 20 minutes of inactivity, however if the mouse is moved or keyboard pressed immediately after the screen saver starts, the Mac will NOT prompt for a password, so set the locked desktop check to 20 minutes and 2 seconds (1202 seconds)

tell application "System Events" to set screenSaverActive to (exists process "ScreenSaverEngine") -- the user may have their screen saver start before the system is idle for 20 minutes which will also lock the computer, so we need to check for this as well, since the system may not be idle for ~20.033 minutes yet

set idleTime to do shell script "echo $((`ioreg -c IOHIDSystem | sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))" -- get the system idle time in seconds
if ((idleTime as integer) ? unlockAfter) or screenSaverActive then
    tell application "System Events" -- if the system is idle for ~20.033 minutes or more OR the screen saver is active, unlock the screen by simulating the user pressing the space bar and unlocking the screen with their password (except we do it as the admin)
        keystroke space
        delay 1
        keystroke tab
        delay 1
        keystroke "admin"
        delay 1
        keystroke tab
        delay 1
        keystroke "password"
        delay 1
        keystroke return
    end tell
else
    do shell script "echo System did not need unlocking."
end if
ENDDetectUnlock
fi

The <<EndDetectUnlock tells Bash to run every command until the next occurrence of ENDDetectUnlock using applescript

frozenarse
Contributor II

I think you would need to add the "sudo -u $3" part in front of each line of your original script that you wish to run as the logged in user. You only will be using that script in your Casper policy instead of using a script to call your original.

rockpapergoat
Contributor III

this bikeshed is huge, man.

you only need to run one line of that script as another user, so try my suggestion and see if it gets you there.

you don't need to be another user to iterate through the files or set IFS, just to run prlctl. you don't need to su to the user or use applescript here, either.

i'm tapped out on this one. as digital underground says, "do what cha like."

bentoms
Release Candidate Programs Tester

Sounds like a vote up for the below FR: Allow policies to be run once per user per computer.

https://jamfnation.jamfsoftware.com/featureRequest.html?id=45

talkingmoose
Moderator
Moderator

Sorry for jumping into the middle of the conversation.

I have to agree with Nate. This is a job for a launch agent. The purpose of a launch agent is to do or run something at login as the current user. It was designed to address the problem at hand.

Sometimes Casper just doesn't need to be part of the solution.

donmontalvo
Esteemed Contributor III

@jarednichols Dude, I owe you big time...works like a charm:

#!/bin/sh

user=`ls -la /dev/console | cut -d " " -f 4`

IFS=":"
for pvm_file in $( ls "/Users/Shared/Parallels" | grep .pvm | tr 'n' ':' ); do
sudo -u $user prlctl register "/Users/Shared/Parallels/${pvm_file}" --preserve-uuid no
done
unset IFS
exit 0

Guys, thanks for all the ideas and suggestions.

Don

--
https://donmontalvo.com

tlarkin
Honored Contributor
Larkin will tell you to use awk. I'll tell you to use cut.

Hahaha I just caught this. I only use awk because I use it more frequently than cut. Otherwise if it gets the job done I could care less.

Cheers
-Tom

donmontalvo
Esteemed Contributor III

Thomas, for what it's worth, I just tested your method and it works too. Is it possible for you and Jared to share an ether beer? :)

I passed the completed script to Vlad at Parallels so they can share it along with the Parallels Auto Deploy wrapper package (new one will be released soon that fixes the reported issues).

Don

--
https://donmontalvo.com

bentoms
Release Candidate Programs Tester

Hi All,

I've also needed this, but for me i had to amend the script.. we have 2 VM's called: Template 10.7.3 040512 & Template Win7 32BIT 040512

Amended script below:

user=`ls -la /dev/console | cut -d " " -f 4`

IFS=$'
'

for pvm_file in $( ls "/Users/Shared/Parallels" | grep .pvm ); 
    do
        sudo -u $user prlctl register "/Users/Shared/Parallels/${pvm_file}" --preserve-uuid no
        echo "Registered ${pvm_file}..."
    done

unset IFS

exit 0

oh & ty for this!

rmanly
Contributor III

don't parse ls
http://mywiki.wooledge.org/ParsingLs

#!/bin/bash

user=$(stat -f %Su /dev/console)

while read -r -d $'�' pvm_file; do
    su "${user}" -c prlctl register "${pvm_file}" --preserve-uuid no
    echo "Registered ${pvm_file}..."
done< <(mdfind -onlyin /Users/Shared kMDItemContentType = "com.parallels.vm.vmpackage" -0)

# or done< <(find /Users/Shared -name "*.pvm" -print0)

kboissonneault
New Contributor

Hi, I'm trying to set up a new lab iMac image whereby our students can log in with their AD accounts and get my custom log in user template. But for some reason I can't get these suggestions to work properly.

Specifically, I'm trying to use a LaunchAgent to run a script that uses DockUtil to add a Downloads folder to the custom dock, but it keeps failing, seemingly on the sudo command given here.

This is the LaunchAgent .plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>Label</key>
   <string>com.user.loginscript</string>
   <key>Program</key>
   <string>/usr/local/bin/UNE_Add_Dock_Icons.sh</string>
   <key>RunAtLoad</key>
   <true/>
</dict>
</plist>

This is the script:

#!/bin/bash

user=`ls -la /dev/console | cut -d " " -f 4`

sudo -u $user /usr/local/bin/dockutil --add /Users/$user/Downloads --no-restart

killall cfprefsd

killall Dock

exit 0

I know I could just use a similar approach to add all my custom apps to the dock, but the script would still need to work!

Here I am running the code manually in terminal as root

sh-3.2# user=`ls -la /dev/console | cut -d " " -f 4`
sh-3.2# echo $user
jtremblay3
sh-3.2# sudo -u $user /usr/local/bin/dockutil --add /Users/$user/Downloads --no-restart
/var/root/Library/Preferences/com.apple.dock.plist does not seem to be a home directory or a dock plist

So it seems the user= code does return the console user, but for some reason sudo -u $user still runs as root. I'm at a loss there.

UPDATE: OK, I don't know why this works, but instead of putting the .plist in /Library/LaunchAgents, I put it in the User Template/Library/LaunchAgents so all new users will get it in their home folder, and I added a sleep 5 command right after the dock util.

bentoms
Release Candidate Programs Tester

@kboissonneault LaunchAgents run as the user, so no need to do the sudo -u or try & find the username.

IIRC, newer builds of dockutil are cfprefsd aware, so no need to kill it, maybe just kill the dock or leave the restart in.

Also, I'd remove the exit 0 as that will show the script as successful even when not.

So something like.

#!/bin/bash

/usr/local/bin/dockutil --add ~/Downloads