Add app to login items for different user?

Hi,

I’m looking for a way to add an application to the login items of a different user. Upon search I found the following script (original post) which seems to do the trick but I am unable to understand all of it, and don’t see how to adapt it to my situation. Especially the last four lines are a mystery to me.

do shell script "sudo defaults write /Path/to/user/Library/Preferences/loginwindow '{
    AutoLaunchedApplicationDictionary = (
        {
            Hide = 0;
            Path = \"/Path/to/loginitem.app\";
        }
    );
    BuildVersionStampAsNumber = 17371360;
    BuildVersionStampAsString = 8J135;
    SystemVersionStampAsNumber = 168036096;
    SystemVersionStampAsString = \"10.4.7\";
}'"

The original poster also comments to do the following after this script:
“Also, you’ll need to do a: chown user:group /Path/to/user/Library/Preferences/loginwindow.plist”.

Is this equal to this?

do shell script "chown user:group /Path/to/user/Library/Preferences/loginwindow.plist"

Or is there an altogether different way of doing this?

Hi Stadsman,

a different way is to use Remote Apple Events, which must be enabled in the Sharing PrefPane.
An other condition is, that the remote user must be logged in.

property user_name : ""
property pass_word : ""
property TheID : "502" -- the UID of the remote user
property theApp : "Mail.app"

tell (system info) to set HostName to host name
set pathApp to POSIX path of (path to application theApp)
set theUser to word 1 of (do shell script "/usr/bin/nireport / /users name uid | grep " & TheID)

if pass_word is "" then
	set eppc to "eppc://" & HostName & "/?uid="
else
	set eppc to "eppc://" & user_name & ":" & pass_word & "@" & HostName & "/?uid="
end if

try
	using terms from application "Finder"
		tell application "Finder" of machine (eppc & TheID)
			get processes -- a trick to launch System Events on the remote user
		end tell
	end using terms from
	
	using terms from application "System Events"
		tell application "System Events" of machine (eppc & TheID)
			make new login item at end of login items with properties {path:pathApp, hidden:false}
		end tell
	end using terms from
on error
	display dialog "User \"" & theUser & "\" with ID " & TheID & " is not logged in"
end try

Thanks Stefan!

I actually also created a different approach which allows setting login items for all user (and can be easily adapted to one specific user). In this case none of the users has to be logged in (other than the administrator)

set prefPath to path to preferences
set thePlist to (prefPath & "loginwindow.plist") as text
set backupPlist to (prefPath & "loginwindow_old.plist") as text

tell application "Finder"
	set theP to POSIX path of thePlist
	set backupP to POSIX path of backupPlist
end tell

--backup login item list
do shell script "cp " & theP & space & backupP

--create new login item list
tell application "System Events"
	set t to login items
	repeat with i from 1 to (length of t)
		delete (first login item)
	end repeat
end tell

tell application "System Events"
	make new login item with properties {path:"/Applications/Safari.app", hidden:false} at end
end tell

--backup old login prefs for all users
try
	do shell script "sudo mv /Library/Preferences/loginwindow.plist /Library/Preferences/loginwindow_old.plist" with administrator privileges
end try

--move the new login item list to all users
try
	do shell script "sudo mv " & theP & " /Library/Preferences/loginwindow.plist" with administrator privileges
	do shell script "sudo chmod 777 /Library/Preferences/loginwindow.plist" with administrator privileges
end try

--restore this user's login item list
try
	do shell script "mv " & backupP & space & theP
end try

Hi Stadsman,

You don’t need to keep writing to the /Library/Preferences/loginwindow.plist. Just create one script application that runs for all users. The script application looks in some folder for all apps, folders, files, etc. that needs to be opened and opens them. So, all you need to do is add alias files to these items to the predesignated folder (old login items method). Another way might be to store a list of items and the script app just opens these items.

gl,

Hi guys. One or two further suggestions, if I may…

If you’re using the path to command, and then concatenating text to complete the path, there are a couple of points to bear in mind.

Lets break down this form of construct:

set prefPath to path to preferences
set thePlist to (prefPath & "loginwindow.plist") as text

The actual stages involved might be itemised as:

set prefPath to path to preferences

-- result is an alias:
--> alias "startup disk:Users:username:Library:Preferences:"

set thePlist to (prefPath & "loginwindow.plist") as text

-- items in parentheses are evaluated first:
--> prefPath & "loginwindow.plist"

-- result of concatenation is a list:
--> {alias "startup disk:Users:username:Library:Preferences:", "loginwindow.plist"}

-- the next operation is a coercion:
--> {alias "startup disk:Users:username:Library:Preferences:", "loginwindow.plist"} as text

-- result of coercion to text is dependent on the value of AppleScript's text item delimiters:
--> "startup disk:Users:username:Library:Preferences:loginwindow.plist"
(* if text item delimiters are set to anything other than "" or {""}, the result will differ *)

-- the final operation assigns the result to the variable 'thePlist'

Now let’s compare that with another approach:

set prefPath to path to preferences as Unicode text
set thePlist to prefPath & "loginwindow.plist"

While this may look very similar, here’s what it does:

set prefPath to path to preferences as Unicode text

-- result is text (this is no coercion; the 'as type' parameter specifies the type of result returned by 'path to'):
--> "startup disk:Users:username:Library:Preferences:"

set thePlist to prefPath & "loginwindow.plist"

-- result of concatenation is text:
--> "startup disk:Users:username:Library:Preferences:loginwindow.plist"

-- the final operation assigns the result to the variable 'thePlist'

So the latter approach is less complex, involves fewer operations, executes faster “ and is less likely to return unexpected results. In addition, Unicode text paths are generally preferable to strings since, on some machines, file paths may include Unicode-only characters (which could cause the script to fail).

That said, we should be able to skip a few steps here anyway. Instead of this (for which, incidentally, the Finder tell statement isn’t needed)…

set prefPath to path to preferences
set thePlist to (prefPath & "loginwindow.plist") as text
set backupPlist to (prefPath & "loginwindow_old.plist") as text

tell application "Finder"
   set theP to POSIX path of thePlist
   set backupP to POSIX path of backupPlist
end tell

… we could jump straight to the POSIX paths:

set prefPath to POSIX path of (path to preferences)
set theP to prefPath & "loginwindow.plist"
set backupP to prefPath & "loginwindow_old.plist"

Another little refinement might be to replace this repeat loop…

tell application "System Events"
	set t to login items
	repeat with i from 1 to (length of t)
		delete (first login item)
	end repeat
end tell

… with a single command:

tell application "System Events" to delete login items

One final observation is probably worth mentioning. Apple advises that using sudo(8) and with administrator privileges is generally unnecessary, and creates security holes. Their recommendation is to remove the sudo altogether.

I hope none of this comes across as in any way critical; most of the points are fairly minor, and the examples highlighted are generally typical. Just thought I’d butt in with a few suggested tweaks, FWIW…
:slight_smile:

BTW, since I’m currently on a slightly older version of Tiger, perhaps I can double-check this with you guys. The hidden property of login items is broken here. Specifying {hidden:false} doesn’t reveal a problem, since that’s the default “ but {hidden:true} doesn’t work, and the value of the property is always returned as missing value. (I have to use a workaround.) Since you’re specifying the property, can I assume that the bug is now fixed?

First off, Kai and Kel, thanks so much for the helpful comments!!!

And yes, the hidden property works fine in 10.4.9. At least here it does.

Kel, I will try your approach as well. I’m not sure yet how you would accomplish this but I guess I have to use the LoginHook.

Hi Stadsman,

It’s really easy. All you need to do is do what you posted for making a global login item for all users. That global login would be a script application. Once you have this login items for all users on every computer, you just need to change the script app.

Suppose you wanted to open a set of apps. I placed a folder on the desktop with alias files to some apps.


property the_url : "http://macscripter.net/"
--
tell application "Finder"
	open every item of folder "LoginItems" of desktop
	set Safari_running to exists process "Safari"
end tell
if Safari_running then
	tell application "Safari" to set URL of front document to the_url
end if

I couldn’t think of a good example, but what this does is look if Safari has an alias file in my LoginItems folder on the desktop. If so, it opens the url. Ultimately, you could make this script app background only, so it doesn’t bounce in the dock at login.

Edited: I just thought of something. You wouldn’t use the desktop. You would have to place your alias files somewhere accessible to all users. This is just for example.

gl,

With all your help I got a lot further, thanks!

However an annoying problem has been bugging me for hours now and Google couldn’t help me :frowning:

I decided to take use the LoginHook to set startupitems with a shell script whoch works great when the script is made upfront and set to be executable (chmod +x):

set scriptF to /path/to/script/script.sh

do shell script "sudo defaults write com.apple.loginwindow LoginHook " & scriptF with administrator privileges

The shell script is very easy:

#!/bin/sh

open /Applications/Path/To/the_app.app

The problem is that I need some more flexibility than a predefined script offers. So I figured I can create the script in my AS app:

do shell script "echo '#!/bin/sh'" & return & return & "open /Applications/To/the_app.app > " & scriptF
do shell script "sudo defaults write com.apple.loginwindow LoginHook " & scriptF with administrator privileges
do shell script "sudo chmod +x " & scriptF with administrator privileges

This creates exactly the same file as when done outside the script, with the same premissions. However, it won’t execute. I also tried to get the thus created script executed in the Terminal but the Terminal says it can’t find the file or folder, even though it shows up in with ‘ls -l’. The other file, created outside of my AS app, will run fine in Terminal…

So I have two seemingly identical files, same content, same owner, same permissions, but one the one created in AppleScript will not execute whereas the other one will…

As I was typing this I had the idea that the cause might be the carriage return. If I copy and paste the complete text from the working script into the non-working, the non-working is working correctly. So I tried using linefeed (ASCII character 10) instead but still no luck. Trying other delimiters like tab and semicolon also was fruitless.

Anyway, I’m lost on this one. Anyone have any idea?

Found the solution:

The ‘returns’ have to be given as Unicode text:

do shell script "echo '#!/bin/sh'" & return & return as Unicode text & "open /Applications/Path/To/the_app.app > " & scriptF