Running application on user login just once

danshaw
Contributor II

Hey everyone - First time poster here! I have an application that I need to run after it installs. After scouring the forums for how to get this done, it looks like the best way is to have it run on login using a LaunchAgent. I've set that up with a plist and its runs fine, but now I have the issue where I only want it to run once.

Does anyone have some creative ideas on how this can be done? I can create a policy to have it removed, but I only want it removed once I know it has run.

15 REPLIES 15

ljungholms
New Contributor

Couldn't you just set the policy to once per computer or am I missing something?

tknighton
New Contributor II

yeah, you're really failing to utilize the the features of Casper here.

You can create a policy that includes a script to run the application on user login. Then you set that script to just run once per computer. done.

geoffreykobrien
Contributor

fa1c30eb0c7d443d86ac7593f59e4601

You can also do, Once Per User Per Computer.

thoule
Valued Contributor II

If you want it run as the user session, then yes, you need to run it via LaunchAgent and it sounds like you've already figured that out.

What I would do in your situation is to have the launch agent execute a script that opens the program you want, and then deletes the launchAgent and the script and whatever else needs to go.

danshaw
Contributor II

Thanks for the responses guys. @tknighton & @geoffreykobrien I should have given you a bit more information. I've tried what you mentioned, but without getting into too much detail, I am not able to open an application as root. It has to be opened from the user. I was not able to create a script that finds the current logged in user and then runs the open command. I kept getting errors as these scripts were on JAMFNATION from 2012. So my next bet was to use a launch agent.

@thoule - I think your option is the best. To have a launch agent open a script and then delete itself. If anyone comes across some example code on how that would be done that would be great. I am still learning scripting and could use a hand.

geoffreykobrien
Contributor
#!/bin/bash userName="$(stat -f%Su /dev/console)" sudo -u $userName -H open "/Applications/Application.app"

ljungholms
New Contributor

To open an application using a script is easy enough.
Something like this.

tell application "Safari" activate
end tell

thoule
Valued Contributor II

This is an example script that you need to call with your LaunchAgent

#!/bin/sh

open /Path/To/Application.app
launchctl unload -w /Library/LaunchAgents/org.danshaw.appopener.plist
rm  /Library/LaunchAgents/org.danshaw.appopener.plist
rm  /Path/To/thisscript.sh

The open command basically issues a 'double-click' to the item. Launchctl line unloads the LaunchAgent item from 'memory'. And the rm lines remove the items referenced.

Before you package and deploy it, the script needs to be executable (chmod +x /Path/To/thisscript.sh).

Good luck! -t-

danshaw
Contributor II

Thanks @thoule that will get me started. May I ask, if the script you have there opens the application, what should the plist do then?

mm2270
Legendary Contributor III

I may be wrong, but I don't think the rm on the LaunchAgent plist will work since /Library/LaunchAgents/ is a protected directory. You can do launchctl load and unload as the user (no root or sudo) on a plist in /Library/LaunchAgents/, but can't remove it from that folder without root.
The -w flag should keep the job disabled though as that stores the state in the overrides file for launchd jobs. Meaning, it should not run again, even after a full reboot.

mm2270
Legendary Contributor III

@danshaw The script he posted would be run by the LaunchAgent itself, meaning the plist will have a reference to that script (in whatever location you deploy it to) in the Program line.

Example:

<?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>org.company.runmeonce</string>
    <key>Program</key>
    <string>/Library/Scripts/runmeonce.sh</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Whereas the "runmeonce.sh" script is what you see a few posts above, so, it launches the application, then disables the job.

danshaw
Contributor II

Getting closer! Thanks @mm2270 for that snippet. So my plist is referencing my script and its opening the application on user login, but the "rm" is not removing the plist or the sh script. Any ideas? Is that a permissions issue like you had said earlier?

And it looks like the -w flag is not preventing it from running again on each login.

ljungholms
New Contributor

Are you running the script directly on the machine or using JAMF? The script should run with full permissions when using the JSS.

mm2270
Legendary Contributor III

@danshaw yes, as I mentioned, you can unload and load a LaunchAgent without using sudo, but you can't remove the plist without sudo since anything inside /Library/LauncAgents/ isn't globally writable to all accounts.

It's odd that it's not staying disabled after reboots or logouts but that may also be a permissions issue. Maybe to add a job to the overrides plist and specify it being disabled requires admin privileges. Not certain, but that might be why. If that isn't working, I would recommend having your script check for a user level local file that would indicate it already launched the application. So make it first check for the existence of the file. If it's not there, go ahead with launching the app and THEN write the file into the users directory. If the file is present, just exit without doing anything. That way it should only launch the app once. It's a bit of a hack since it means the job will remain active and launch at each login, but shouldn't fire the application again for that particular user on the system.

Another probably better way to make sure it doesn't run again is to make sure the script it references gets deleted after its first run. No script means no application launching.

danshaw
Contributor II

Thanks everyone for your help. I was able to get it all working after lots of trial and error. In case someone stumbled on this post here is how I got it to work.

  1. Created a LaunchAgent plist and placed it in the /Library/LaunchAgents folder
<?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.application.startup</string>
    <key>Program</key>
    <string>/private/var/scripts/application_startup.sh</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

2. Created the script that it references and placed it in /Private/Var/Scripts folder that I created. I couldn't get it to remove the files because of permission issues, so I created an IF/THEN statement. Later I can go in and clean up the files if I need to. This script creates an invisible file in their documents folder that I then look for.

if [ -f ~/Documents/.application_ran ];
then
else
    open /Applications/YourAppYourFile.app
    touch ~/Documents/.application_ran
fi

I tested this on 10.10 and 10.11.