Hmm. I wonder if its because of the ProgramArguments array pointing to a .scpt file? In the tests I've been doing, I always pointed to a shell script. Let me try pointing to a simple .scpt file with a command similar to above and see what my results are.
@plawrence I just noticed this in your QueueDirectories path
~/Library/Containers/com.apple.Outlook
That's not the path. Its supposed to be
~/Library/Containers/com.microsoft.Outlook
Can you check to make sure you're using the right path to watch?
Mine which is also working is pointing directly to shell script not an Applescript and it has no arguments included.
I don't think it has anything to do with being pointed to a .scpt file. I changed the existing LaunchAgent I had working with a shell script to point to an Applescript file using syntax like /usr/bin/osascript /path/to/script.scpt
Loaded the LaunchAgent with no errors. Made a change to the directory in the QueueDirectories path and the Applescript ran (it just displayed a dialog on screen) But it worked, so I don't think its related to using an Applescript file.
Something else must be causing it not to work for others here.
@mm2270 Thanks for picking up on the error in my post, I've modified the QueueDirectories path to be ~/Library/Containers/com.microsoft.Outlook (and edited my previous post incase anyone copies it) but I am still having trouble getting this to work.
If I use the path of ~/Library/Containers/com.microsoft.Outlook when I go to launch the LaunchAgent the following error appears in the system log:
UserEventAgent Ignoring path: ~/Library/Containers/com.microsoft.Outlook/
If I change the QueueDirectories path without the ~ e.g. /Users/username/Library/Containers/com.microsoft.Outlook/ then the LaunchAgent appears to work correctly and it attempts to trigger the script when the folder is created, but the following errors appear in the system.log and the AppleScript never runs:
com.apple.xpc.launchd Service exited with abnormal code 1
com.apple.xpc.launchd Service only ran for 0 seconds. Pushing respawn out by 10 seconds
This got me to thinking that perhaps there is something wrong when the AppleScript runs, but I can run it fine manually. After a lot of trial and error I think I figured out what was causing the issue, in the AppleScript there is some code to read the users Active Directory information and it uses a dscl command with a $USER variable, when this script is called by the LaunchAgent it doesnt appear to process that correctly. If I hard-code a username in the dscl command, then the script runs!
For those of you that have this working, had you configured "getUserInformationFromActiveDirectory" to True in the AppleScript?
I also still need to figure out why my LaunchAgent doesnt respect the ~ character in the QueueDirectories path.
com.apple.xpc.launchd Service only ran for 0 seconds. Pushing respawn out by 10 seconds
This would seem to imply the directory is not empty and the script is running but taking less than the 10 second default minimum for an agent.
You basically have to have to start with no directory (or at least an empty one) if you want this process to work correctly and the directory existing being a condition of disabling the agent.
Queued directories are intended for mail agents etc... they are not looking for changes, they are looking for content.
Or at least that is my understanding of it...
@plawrence Sorry if this is a silly question, but the plist for the LaunchAgent is in /Library/LaunchAgents/ correct? Its not in the LaunchDaemon directory by any chance?
Also, what command are you using to load it? Are you loading it from within an app like Lingon or LaunchControl, or from Terminal? If in Terminal, can you paste the command you're using?
Finally, you may want to add the StandardErrorPath and StandardOutPath keys into the launchd file and point them to some stderr and stdout log files respectively. When you load it, and it errors, it should put something in at least one of those files that may help us figure out what's going on.
FWIW, I have set up LaunchAgents pointing to either an existing but empty directory, or a non existent directory in the QueueDirectories path, and its worked for me either way.
@mm2270 Thanks for the quick response!
Yes, I've put the plist into /Library/LaunchAgents/. To load the Agent I use the following command in Terminal 'launchctl load /Library/LaunchAgents/name.of.agent.plist'
I'll look at putting the error keys into my LaunchAgent and see what the output is.
Did you check if had you configured "getUserInformationFromActiveDirectory" to True in the AppleScript?
Are you currently using the ~ character in your LaunchAgent plist?
Hey @plawrence, so truthfully I haven't been doing testing with the actual Applescript from @talkingmoose. But I'm still not convinced it has anything to do directly with the Applescript. I've used my LaunchAgent with other Applescripts and not had an issue with loading the LaunchAgent. It should still load as long as you have things set up correctly.
As @Look mentioned above, make sure the ~/Library/Containers/com.microsoft.Outlook
folder doesn't exist on the Mac, or if its there, make sure its empty. QueueDirectories works by monitoring a directory for content. It won't run the job until some files/folders get dropped into (one of) the directories its watching.
If the com.microsoft.Outlook dir is already populated when you try loading the job, it will try running the job immediately, so make sure its empty or just not there. Outlook will take care of creating it at first or next launch.
And yes, my LaunchAgent is using the ~ character. LaunchAgents don't have a problem with that since they are always run as the logged in user.
The only thing I'm just seeing that's slightly different from what you posted above is that I included the trailing slash at the end of my path, so instead of ~/Library/Containers/com.microsoft.Outlook
, I'm using ~/Library/Containers/com.microsoft.Outlook/
I don't think this should make any difference, but try adding the trailing slash in and see if that helps.
I just wanted to post back that, once I began actually using the LaunchAgent to watch the actual folder created by Outlook on first launch, I began to see the LaunchAgent come up with errors as well. It was puzzling at first because I could point the LaunchAgent's QueueDirectories path at almost any other location and get it to load and fire a script off as soon as the dir was created and populated with some other files/folders. But when watching ~/Library/Containers/com.microsoft.Outlook/, it began generating errors. This is under Yosemite at least, since I can't install Office 2016 on anything but 10.10 and up.
I think, though not sure, that the reason is because these are sandboxed apps, and the Containers directory it creates are protected in some way, so maybe a LaunchAgent can't actually watch them with QueueDirectories? I don't know for sure since I know little about what happens behind the scenes with sandboxed apps. Maybe someone with some programming knowledge can comment to say whether or not this makes sense or not. I can't figure out why else it won't work. Any folder I make myself and have it watch, even if it doesn't exist initially, works fine. Its just with the actual ones Outlook creates that it all goes south.
If its true that its because of the sandboxing, we may have to just watch the entire ~/Library/Containers/ folder and detect if the com.microsoft.Outlook folder is being created.
OK, never mind my post above. I just had something configured incorrectly. I was trying to run a script that was calling cocoaDialog, and normally that's OK, but our default deployment of cD sets it so its so the app is not readable by most accounts. This was fixed with a simple chmod -R 755 across the app bundle, so the script run by the LaunchAgent can actually call the application. That's where the error was coming from, not from monitoring the com.microsoft.Outlook directory in the Containers folder. Once I fixed that and put the QueueDirectories path back to ~/Library/Containers/com.microsoft.Outlook/, it works fine. So it seems we can monitor for that and fire a script.
Now to get some other pieces working...
This may be a silly question- I'm just not up to snuff on my AppleScript.
I think I have the base script configured correctly, and looking at the Accounts info it seems to be.
However, when the prompt dialog box pops up to log into your Outlook account, the username is populated by the user's email address instead of their short name or username.
If you manually enter the username in place of the email address, theres no problem, but you know most users will not.
Is there a place in the script to change this behavior or is this something on my exchange server side?

Hi @AdamH - this is a known bug in Outlook 2016, as per this issue logged on GitHub: https://github.com/talkingmoose/Outlook-Exchange-Setup-5.0/issues/1
I'm seeing issues with using the LaunchAgent and using either WatchPaths or QueueDirectories. Both methods are constantly watching for modifications to either a file or whole directory, respectively. In either case this can cause an undesirable launching of one or many instances of the setup script.
In my testing with QueueDirectories watching ~/Library/Containers/com.microsoft.Outlook I was getting the script running 2x during the first launch of Outlook. And if I quit Outlook something was being modified in the watched directory making Outlook launch again and fire up the script. I was getting the same experience with WatchPaths as there isn't a file that can be reliably watched and guaranteed to never be modified again.
The ultimate problem is that 2016 has gotten rid of the Schedules option that Outlook 2011 had. Outlook 2011 was able to have a script run at launch, and as a part of the script, remove itself from the schedule so no other instances would run after it was run once. That behavior, in my opinion, should be mimicked in Outlook 2016 as well, even with the absence of the Schedules option. Leaving the LaunchAgent running as a loaded gun to fire off the setup script anytime the monitored file or path is modified could lead to mis-fires of the setup script even when the account is already setup. What happens when Outlook gets updated? There's no guarantee that a file will remain un-modified for the lifetime of the user account.
I've worked on this in a fork of @talkingmoose's script that tries to implement the change of mimicking the 2011 run-once behavior. In a nutshell, this implementation has a LaunchAgent that checks a custom plist file for a specific key in the user's space to see if the setup script has run. If so, it exits. If not it copies and loads a LaunchAgent in the user's space (~/Library/LaunchAgents) that uses WatchPaths to monitor a file that gets updated only on an Outlook launch. This allows the user to dictate when the script runs as it will only trigger when the application is launched. Once launched the setup script runs and configures the account. I've added 3 lines of code to the end of the AppleScript to write the key value to the custom plist that the main LaunchAgent is looking for on every user login to flag it as having been run, deleting the ~/Library/LaunchAgent and unloading it so it doesn't run again, even if the user quits and re-launches Outlook. This is a run-once behavior like Outlook 2011 had.
The main /Library/LaunchAgent is still loaded and runs a script on every login to check for the existence of the custom plist key. To have the setup script run again you'd just have to remove the custom plist and/or key.
My fork and writeup on this POC can be found at https://github.com/poundbangbash/Outlook-Exchange-Setup-5.0
Note my AppleScript has some custom environment changes, specifically setting the username to the UPN instead of the username. The main difference between the original script and mine are the last 3 'do shell script' lines.
-Eric
So, I did some looking and it seems its not really a bug as much as its a configuration spec.
We've been getting ready to use O365 accounts here, and in doing that have been changing the UPN in our AD template. Once that change was made to a test account, the user was able to actually log in with the email address in that field (username worked as well).
So it seems the behavior is expected, and will work if the UPN field in the AD account is set to O365 standards.
Which is cool.....I guess.....
@eholtam
I used my own setup script (with some sneaky peeks at @talkingmoose 's scripting) but got round the smoking gun as it were by doing the following.
The first thing the script does is check if there is an exchange account, if it finds one, it simply exits and unloads the launchagent. Thereby leaving it not running for the rest of the session.
The launch agent will run every login, but immediately unloads for any user that already has Outlook configured without interfering with anything however if a tech was to delete the monitored folder and exchange account the log out then it would be active again when the user next logged back in and once again reconfigure Outlook.
@Look Care to share your Exchange detecting code snippet?
When the script runs every login wouldn't it have to launch Outlook to be able to determine if an account exists or not?
@eholtam
Sure I am calling apple script from shell, so in the shell part of the script I get my user with my preferred
Current_User=$(stat -f%Su /dev/console | awk '!/root/')
which will return any none root console user.
Then I have a function.
Get_Current_State() {
if [[ "$Current_User" ]] && [[ "$(ps -cax | awk '/Microsoft Outlook/')" ]] && [[ "$(defaults read /Applications/Microsoft Outlook.app/Contents/Info.plist CFBundleShortVersionString | awk -F "." '{print $1}')" == "15" ]] && [[ -z "$(find /Users/$Current_User/Library/Group Containers/ -name *olk15MailAccount)" ]]; then
return 0
else
return 1
fi
}
Basically it checks for a user grabbed earlier, makes sure Outlook is running and that version 15 is installed (it might still fall over if 2011 was installed and open as well) then searches the profile directory to make sure there is no olk15MailAccount file.
You can then use it in the following context
if Get_Current_State; then
DO SOME STUFF ie CALL AN APPLESCRIPT
fi
UNLOAD THE AGENT
Basically the first time the Queue trigger activates it either skips everything and disables the agent or does the script then disables the agent.
It did also occur to me that you could also just have the disabling of the agent inside the agent itself as another program call, then the script just needs to check and configure or no configure as required and the agent would only ever run once per session either immediately if there were items in the directory or at the point in which the directory is populated.
Disabling the launch agent for the session is actually a brilliant idea! I like that.
Wouldn't be too difficult to detect an Exchange account without launching Outlook.
profile=$( defaults read "/Users/$USER/Library/Group Containers/UBF8T346G9.Office/OutlookProfile.plist" Default_Profile_Name )
if [ -d "/Users/$USER/Library/Group Containers/UBF8T346G9.Office/Outlook/Outlook 15 Profiles/$profile/Data/Exchange Accounts" ] ; then
echo "Exchange account present"
else
echo "Exchange account not present"
fi
This seems to work in my very limited testing.
@talkingmoose
The existence of the Exchange Accounts folder isn't enough as that folder structure remains even if all Exchange accounts are deleted from within Outlook. I used a hybrid of yours and @Look's code to come up with.
profile=$( defaults read "/Users/$USER/Library/Group Containers/UBF8T346G9.Office/OutlookProfile.plist" Default_Profile_Name )
#Check if an Exchange profile exists or not
if [ -z $(find "/Users/$USER/Library/Group Containers/UBF8T346G9.Office/Outlook/Outlook 15 Profiles/$profile/Data/" -name *olk15ExchangeAccount) ]
then
#If no LaunchAgents directory exists in the user home, create it
if [ ! -d $HOME/Library/LaunchAgents/ ]
then
mkdir -p $HOME/Library/LaunchAgents/
fi
#Copy the LaunchAgent to ~/Library/LaunchAgent and load it
cp "/Library/Management/Outlook2016Setup/LaunchAgents/net.talkingmoose.OutlookExchangeSetup5.0.plist" "$HOME/Library/LaunchAgents/net.talkingmoose.OutlookExchangeSetup5.0.plist"
launchctl load "$HOME/Library/LaunchAgents/net.talkingmoose.OutlookExchangeSetup5.0.plist"
else
exit 0
fi
That worked for all scenarios that I tested. Once the *olk15ExchangeAccount file no longer exists the setup process is made available to the user again.
The launchagent that gets loaded in the ~ space is
<?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>net.talkingmoose.OutlookExchangeSetup5.0</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/osascript</string>
<string>/Library/Management/Outlook2016Setup/Scripts/Outlook Exchange Setup 5.0.scpt</string>
</array>
<key>WatchPaths</key>
<array>
<string>~/Library/Group Containers/UBF8T346G9.Office/OutlookProfile.plist</string>
</array>
</dict>
</plist>
And the applescript has two lines at the end to remove the ~ LaunchAgent and unload it.
do shell script "rm $HOME/Library/LaunchAgents/net.talkingmoose.OutlookExchangeSetup5.0.plist"
do shell script "launchctl remove net.talkingmoose.OutlookExchangeSetup5.0"
This may be my winner winner rubber chicken dinner. Thanks for both of your insights.
I love the idea of a launch agent- its self contained and doesn't rely on anything else.
But what I'v been doing with 2011 so far and could work with 2016 as well, is add this to the beginning of the script:
tell application "System Events"
if exists (folder "~/Library/Containers/com.microsoft.Office365ServiceV2") then
error number -128
end if
end tell
... and add the script as a login script. It will run every time the computer is logged in for every user and it will just quit if an account has been created already.
I'd have a version without this in self service in case someone wants to recreate their account for some reason.
@AdamH, this is purely administrative philosophy.
My reason for having the launch agent watch for specific items is to avoid confusing the user. When he or she launches Outlook, that's when I want setup to run. The user will understand the act of launching Outlook just triggered something. If all script prompts are suppressed, the user doesn't even realize setup just ran and simply logs in to email.
Otherwise, running the script at login automatically launches Outlook, whether the user wants that or not.
Self Service would be a good additional place to add the script if the launch agent fails or we haven't built enough smarts into the script to account all the potential scenarios when it may not trigger.
I think your philosophy is sound. Personally I think it would be the optimal way to go.
But in my environment, we have a deployment team that issues all new computers. So in this scenario having Outlook automatically launch and setup the account for the user is a bonus because it ensures that Outlook is configured and working before the tech leaves.
Oh, and millions of thanks for doing the legwork in developing this script with great documentation! Its saved the scripting-impared many hours of work and related headaches!
I've appreciated all the help with the first run stuff. It's time I haven't had to devote to testing, which is why I posted everything as-is on GitHub.
Next, I'll steal ideas and give credit where due. And I'll update everything and put a bow on it. :-)