Enterprise Connect Login Item

Treger
Contributor

Hi Guys,

Has anyone found a way to add EC into the user Login Items? I have managed to get these to work locally on my machine to add EC to the login items but as soon as I run it through ARD to a remote machine (figured if I cannot get it to work with ARD it won't work with Casper) it just constantly fails, I have tried quite a few different options on the App name too just incase it wasn't pulling the correct name remotely.

defaults write /Library/Preferences/loginwindow AutoLaunchedApplicationDictionary -array-add '{Path="/Applications/Enterprise Connect.app";}'

/usr/bin/osascript -e 'tell application "System Events" to make new login item with properties { path: "/Applications/Enterprise Connect.app", hidden:false } at end'

I also tried to do it as a LaunchAgent as specified here: https://macmule.com/2011/09/08/how-to-map-drives-printers-based-on-ad-group-membership-on-osx/ as suggested by @bentoms but I could not get this to work for me either. I got this for the the jamf original discussion here: https://jamfnation.jamfsoftware.com/discussion.html?id=10969

Anyone had any success with this or can anyone see what I am doing wrong?

35 REPLIES 35

Treger
Contributor

Here is what I tried with the plist and the LaunchAgent...

<?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>Enterprise Connect</string> <key>Program</key> <string>/Applications/Enterprise Connect.app</string> <key>RunAtLoad</key> <true/> </dict> </plist>

dan-snelson
Valued Contributor II

@Treger Here's what we're using, courtesy of @rjlemmon:

Since Enterprise Connect will create its own login item for each user account, you need only get it to launch once for each user.

LaunchAgent

(i.e., /Users/localadmin/Library/LaunchAgents/com.company.launchECFirstTime.plist)

<?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.launchECFirstTime</string>
    <key>ProgramArguments</key>
    <array>
        <string>/local/path/to/scripts/launchECFirstTime.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Client-side Script

(i.e.,/local/path/to/scripts/launchECFirstTime.sh)

#!/bin/sh

sleep 5

loggedinuser=`who|grep console |awk {'print $1'}`
echo "Logged in user is ${loggedinuser}"
open /Applications/Enterprise Connect.app
rm /Users/${loggedinuser}/Library/LaunchAgents/com.company.launchECFirstTime.plist

These files are captured with Composer and then a DMG was built, which when deployed, Filled User Template and Existing Users.

Treger
Contributor

Worked it out, please ignore this. Cant delete it...

Treger
Contributor

Thanks @dan.snelson, I will actually give that a shot instead of the way I am doing it, I would prefer to use a LaunchAgent

iJake
Valued Contributor

We use a LaunchAgent that runs a script that ensures it is always running so definitely go with that.

Treger
Contributor

I can get it to run as Admin and not as the user with the Launch Agent, what perms did you guys use so that the user gets this as well?

iJake
Valued Contributor
-rw-r--r--   1 root  wheel   451 Jun  9 19:00 com.cisco.enterpriseconnectlauncher.plist

Treger
Contributor

Thanks,

Ok I put the plist in /Library/LaunchAgents and the script in /Library/Scripts, made sure the perms on the plist were correct and I still can't get it to run as the user. I had them previously in localadmin/Library/LaunchAgents and Scripts respectively and the same thing do I need to change the perms on the script to like a 755?

iJake
Valued Contributor

No. The permissions should match what I showed you which would

sudo chmod 644 PATH/TO/FILE

I would add some logging to your agent to see if maybe it is trying to run but can't. Add this to your LaunchAgent plist

<key>StandardOutPath</key>
<string>/Library/Logs/FILENAME.log</string>
<key>StandardErrorPath</key>
<string>/Library/Logs/FILENAME_Err.log</string>

Also, remember that LaunchAgents run AS the user so the user needs to have read and execute permission on the script your LaunchAgent is meant to run.

Treger
Contributor

Thanks @iJake I will give that a go!

Treger
Contributor

Ok, I have found part of the problem, its my .plist, it doesn't seem to be loading. I have run the script from the terminal as the user and it works, but it would also appear that the dmg that I am creating does not seem to be FEU and FUT, I moved the files back into the local admin and re-created the DMG and this still is not populating the user library. I am assuming the script could actually stay where it is as it can run, its just a case of trying to get the plist into he user LaunchAgent folder so that it can call it.

Am I missing something here, I thought the FUT and FEU would complete as requested if you built the DMG with say the local admin account and fill the user locations as per the DMG..?

dan-snelson
Valued Contributor II

@Treger Please confirm the DMG and the policy have FUT and FEU enabled:
3710cacdeb084eabb6f5624e533d89ee
45cdc9f2872c4faca9fd7951c99289a1

I don't know that it matters, but my Composer VM has a different local admin than our production machines (i.e., ladmin vs. localadmin).

After your policy installs the DMG, can you observe your .plist in?

/System/Library/User Template/English.lproj/Library/LaunchAgents

Treger
Contributor

Hi @dan.snelson

See attached they are definitely ticked, I might try move the plist to the /System/Library/User Template/English.lproj/Library/LaunchAgents and see if that makes a difference97348ba92a8e46268660b82626f35be9

Treger
Contributor

@dan.snelson yes the plist is actually in /System/Library/User Template/English.lproj/Library/LaunchAgents already...

iJake
Valued Contributor

Why are you messing with FUT and FEU? Any LaunchAgent in /Library/LaunchAgents/ will be run by and user that logs in.

Treger
Contributor

I tried that and it only seems to run as the local admin, so I thought I had to get it into the user LaunchAgents folder. I have just wiped the machine I was testing on for a clean slate, let me try put it into that folder again and see if I can get it to work like that...

Treger
Contributor

I don't know if this affects anything but I have noticed that my plist is saving with some extended attributes, and is a com.apple.TextEncoding 15 when I check. Will this maybe be whats stopping things from running?

iJake
Valued Contributor

What are you editing the file with?

Treger
Contributor

I initially used TextEdit which after some reading I have now realised was a bad move... I tried to open it with TextWrangler and Sublime Text after wards to re-save it and it didn't work, eventually I got rid of the attribute with the xattr command but it still doesn't work. I think I need to go back to the drawing board with it and use Textwrangler which I believe allows the plist to be edited without damaging the properties? If not can you let me know a good one to use..?

Sorry guys I am still a noob with plist files and this LaunchAgent thing...

I even copied a plist out of the LaunchAgent folder to the desktop this last time to make sure the file was in the correct format to start with but obviously when I saved it in TextEdit it destroyed it again...

iJake
Valued Contributor

Yeah, stick with TextWrangle, Sublime or any other actual code editor. It keeps the hidden characters out that will break things. If you need help recreating it post what you have but otherwise i would start from scratch/or duplicate then modify an existing plist in one of those code editors

johnklimeck
Contributor II

@iJake,

What's up, thanks for your posts here.

Would you mind pinging me, or posting here the script you mention.

I am having similar issues with getting Ent Connect to launch after install via the JSS policy (Launch Agent plist with script). Via executing the script manually in terminal, EC will launch. I have checked everything permissions (600), driving me crazy.

John K
john.klimeck at fox dot com

dgreening
Valued Contributor II

Here is what I have for a script to open up EC for the logged in user upon install. Just make sure that when you push out an update to EC that you don't tack the script on to the update policy.

#!/bin/bash
# Script to check the local user and open Apple Enterprise Connect for the first time
# This script will only launch Enterprise Connect if the logged in user is not root or any user with admin in the name.
# 10/28/2015 Daniel J Greening

thisUser=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`

if [ $thisUser == "root" ]; then
    echo "User is root, bailing."
    exit
elif [[ $thisUser == *admin* ]]; then
    echo "User is the local admin, bailing."
    exit
else
    echo "User is not root or the local admin, opening Enterprise Connect."
    su $thisUser -c 'open /Applications/Enterprise Connect.app/Contents/MacOS/Enterprise Connect'
fi

exit 0

Additionally, here is the script for an "Enterprise Connect Status" Extension Attribute which I use to determine if the user has signed in. As we deployed EC to some of our local support people before I had the launcher in the policy, I scope the launcher script to those machines via the Ext Attr / Smart Group.

#!/bin/bash

user=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`
plist="/Users/$user/Library/Preferences/com.apple.Enterprise-Connect.plist"
ec="/Applications/Enterprise Connect.app"

if [ -d "$ec" ]; then
echo "Enterprise Connect is installed"
    if [ -e "$plist" ]; then
    plistkey=`defaults read /Users/$user/Library/Preferences/com.apple.Enterprise-Connect datePasswordExpires`
    echo "$user Enterprise Connect plist exists"
        if [[ ! "$plistkey" ]]; then
        echo "<result>$user is not configured</result>"
        else
        echo "<result>$user is configured</result>"
        fi
    else
    echo "$user EC plist does not exist"
    fi
else 
echo "<result>Not Installed</result>"
fi

iJake
Valued Contributor

I can't yet post our scripts directly but I've reached out to @johnklimeck to assist and would be happy to with anyone else. I hope to soon show how we are using Enterprise Connect and all the supporting scripts we've built around it.

tanderson
Contributor

We had EC set up to use a Launch Agent and saw times where it would actually open and be running dual instances. It wouldn't happen every time or for every user but it did for some. Reached out to support and were told not to use the LA and roll with the Login Item. YMMV, just adding to the discussion.

iJake
Valued Contributor

The script our LA calls checks to see if it running and then launches it if all other criteria is met. I suspect the double launch will happen if there is nothing checking to see if it's already running.

johnklimeck
Contributor II

iJake / tanderson,

Thx again, just can not get LaunchAgents to work for whatever reason. I see Login Items mentioned above, and tried that. Using osascript to enter a Login Item for EC and then a simple open Enterprise Connect script, working great.

thx,

John

rickwhois
Contributor

@iJake Hey Jake, would you mind sharing your scripts with me regarding the LA?

I've followed along with whats recommended here and it's working for the most part. Except if a user doesn't enter credentials upon first launch then it wont get added to the users startup items. I think ideally it would be best to have the LA check for process and run if it isn't running rather than add a startup item that the user can easily remove.

iJake
Valued Contributor

@rickwhois Sorry for the delay, I was traveling. Below is the script our LaunchAgent calls. There is a lot in this that ties to a daemon we also use because we have wrapped EC in a whole password policy management solution we wrote but not the part that makes sure EC is running. That code is fairly simple and near the bottom of this script. As you can see we do a few checks to make sure EC is configured properly before we worry about making sure it is running. We do not rely on the Startup Item at all and only this LaunchAgent. The LaunchAgent running is enforced by checks from the Casper side to be sure its always loaded. Let me know if you have any questions.

#!/bin/bash

## HEADER
# Script Title: Enterprise Connect Launcher
# Author: Jacob Davidson <jadavids@cisco.com>


## Definitions
softwareTitle="enterpriseConnectLauncher"
logFolder="/PATH/TO/LOGS"
timeStamp=`date "+%Y %b %d %T"`
consoleUser=$(stat -f %Su "/dev/console")
logSize=$(stat -f%z $LogFile)
maxSize=1000000
compliancePlist="REDACTED"
enterpriseConnectApp="/Applications/Enterprise Connect.app"
enterpriseConnectPrefs="/Library/Preferences/com.apple.Enterprise-Connect.plist"
enterpriseConnectMainUser=$(defaults read "$compliancePlist" mainUser)
timeStamp14dBack=$(date -v-14d -u +"%s")
fiveDays=432000
twoDays=172800
ecKeychainUser=$(/usr/bin/security find-generic-password -l "Enterprise Connect" | grep "acct" | awk -F "=" '{print $2}' | tr -d """)
NCutil="/PATH/TO/NCutil.py"
yo="/PATH/TO/yo.app/Contents/MacOS/yo"
title="Enterprise Connect Alert"
icon="/Applications/Enterprise Connect.app/Contents/Resources/AppIcon.icns"
ecKiller="/PATH/TO/enterpriseConnectKiller.sh"

## Functions

grabConsoleUserAndHome()
{
currentUser=$(stat -f %Su "/dev/console")
homeFolder=$(dscl . read "/Users/$currentUser" NFSHomeDirectory | cut -d: -f 2 | sed 's/^ *//'| tr -d '
')
  case "$homeFolder" in  
     * * )
           homeFolder=$(printf %q "$homeFolder")
          ;;
       *)
           ;;
esac
}

grabConsoleUserAndHome

logFile="$homeFolder$logFolder"/"$softwareTitle.log"

writeLog(){ echo "[$(date "+%Y-%m-%d %H:%M:%S")] [$consoleUser] [$softwareTitle] $1" >> "$logFile"; }
[[ -e "$(dirname "$logFile")" ]] || mkdir -p -m 775 "$(dirname "$logFile")"
[[ "$(stat -f%z "$logFile")" -ge 1000000 ]] && rm -rf "$logFile"

killEnterpriseConnect()
{
killall "Enterprise Connect"
}

launchEnterpriseConnect()
{
if [[ $(curl -sL -w "%{http_code}" "INTERNAL URL" -o /dev/null) -eq 200 ]]
    then
        writeLog "CAPnet detected. Launching..."
        osascript <<EOF
set theDirectory to "$enterpriseConnectApp"
set macPath to POSIX file theDirectory as Unicode text
tell application "Finder" to open file macPath
EOF
    else
        writeLog "CAPnet NOT detected. NOT launching..."
fi
}

yoNotifSettings()
{
$NCutil -i com.github.sheagcraig.yo
$NCutil -a alerts com.github.sheagcraig.yo
$NCutil --show-on-lock-screen true com.github.sheagcraig.yo
sleep 2
}

yoFix() 
{
if [[ $(curl -sL -w "%{http_code}" "INTERNAL URL" -o /dev/null) -eq 200 ]]
    then
        writeLog "CAPnet detected. Prompting..."
        if [[ -e $yo ]]
            then
                yoNotifSettings
                $yo -d -t "$title" -b "Fix" -B "bash "$ecKiller"" -s "$1" -n "$2" -p -i "$icon"

            else
                $3
        fi
    else
        writeLog "CAPnet NOT detected. NOT prompting..."
fi
}

newInstallPrompt()
{
msg="Enterprise Connect has just been installed!

Enterprise Connect is the new Password Policy
enforcement tool for Macs at Cisco.

To learn more go to:
INFO URL

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
defaults write "$userCompliancePlist" newInstallAlertSeen -bool TRUE
exit
}


keychainMissingPrompt()
{
msg="Enterprise Connect has not been configured.

This is required per Cisco policy.

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

oldADSyncPrompt()
{
msg="Enterprise Connect has not connected in two weeks. This is required per Cisco policy. Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

prefsMissingPrompt()
{
msg="Enterprise Connect has not been configured.

This is required per Cisco policy.

Enterprise Connect will prompt you to log in after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

adNotSyncedPrompt()
{
msg="Your local password is not synced with your CEC password.

This is required per Cisco policy.

Enterprise Connect will prompt you to sync them after you close this dialog."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
killEnterpriseConnect
sleep 2
launchEnterpriseConnect
}

expirationAlertPrompt()
{
msg="Your CEC password is expiring in less than two days!

Please change your password with Enterprise Connect from the Menubar."
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "$title" -description "$msg" -icon "$icon" -button1 "Continue" -defaultButton 1 -lockHUD -startlaunchd -windowPosition ur
launchEnterpriseConnect
}


userCompliancePlist="REDACTED"

if [[ "$currentUser" == "root" ]]
    then
        exit
fi

if [[ "$enterpriseConnectMainUser" != "$currentUser" ]]
    then
        writeLog "$currentUser is not the determined Main User. Exiting..."
        exit
    else
        writeLog "$currentUser IS determined Main User. Checking Enterprise Connect configuration..."
fi

#We can't be sure logged in user account matches AD username so this section has been removed
# if [[ "$ecKeychainUser" = "$enterpriseConnectMainUser" ]]
#   then
#       writeLog "Enterprise Connect keychain configured for correct user..."
#   elif [[ "$ecKeychainUser" = "security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain." ]]
#       then
#           # writeLog "Enterprise Connect keychain item is missing. Prompting and relaunchig app to fix..."
#           writeLog "Enterprise Connect keychain item is missing."
#           # yoFix "Enterprise Connect not configured" "Click the fix button to configure" "keychainMissingPrompt"
#           exit
#   else
#           # writeLog "Enterprise Connect keychain not configured for current user. Prompting and relaunchig app to fix..."
#           writeLog "Enterprise Connect keychain not configured for current user."
#           # yoFix "Enterprise Connect not configured" "Click the fix button to configure" "keychainMissingPrompt"
#           exit    
# fi

enterpriseConnectPrefsCreateDate=$(date -j -f "%Y-%m-%d%T" "$(mdls -n kMDItemFSCreationDate "$homeFolder""$enterpriseConnectPrefs"  | awk '{print $3 $4}')" "+%s")
# dateExpirationChecked=$(defaults read "$homeFolder""$enterpriseConnectPrefs" dateExpirationChecked | awk '!($3="")' | sed 's/ *$//')
# dateExpirationCheckedEpoch=$(date -j -f "%Y-%m-%d %T" "$dateExpirationChecked" +%s)
mainUserLastConnectEpoch=$(defaults read "$userCompliancePlist" mainUserLastConnect)
newInstallAlertSeen=$(defaults read "$userCompliancePlist" newInstallAlertSeen)

if [[ $mainUserLastConnectEpoch =~ ^-?[0-9]+$ ]]
    then
        writeLog "Enterprise Connect HAS connected at least once. Continuning..."
    else
        if [[ $newInstallAlertSeen -eq 1 ]]
            then
                writeLog "New install prompt HAS been seen. Alerting to configure..."
                yoFix "Enterprise Connect not configured" "Click the fix button to configure" "prefsMissingPrompt"
                exit
            else
                writeLog "Enterprise Connect HAS NOT connected at least once. Prompting..."
            newInstallPrompt
        fi
fi

if [[ -e "$homeFolder""$enterpriseConnectPrefs" ]]
    then
        writeLog "Enterprise Connect prefs exist..."
        if [[ $mainUserLastConnectEpoch -lt $timeStamp14dBack ]]
            then
                writeLog "Enterprise Connect hasn't checked AD in 14 days. Prompting and relaunching app to fix..."
                yoFix "EC hasn't connected in 2 weeks" "Click the fix button to login" "oldADSyncPrompt"
                exit
            else
                writeLog "Enterprise Connect checked AD $(date -j -f "%s" "$mainUserLastConnectEpoch" "+%Y-%m-%d %T"). Continuing..."
                defaults read "$homeFolder""$enterpriseConnectPrefs" datePasswordExpires
                if [[ $? -eq 0 ]]
                    then
                        adExpirationDateEpoch=$(date -j -f "%Y-%m-%d %T" "$(defaults read "$homeFolder""$enterpriseConnectPrefs" datePasswordExpires | awk '{print $1,$2}')" "+%s")
                        twoDaysCheck=$[$adExpirationDateEpoch - $(date "+%s")]
                        if [[ $twoDaysCheck -lt $twoDays ]]
                            then
                                writeLog "AD password expires in less than two days. Prompting..."
                                expirationAlertPrompt
                        fi
                        adExpirationDatePlusFiveEpoch=$[$adExpirationDateEpoch + $fiveDays]
                        adExpirationDatePlusFive=$(date -j -f "%s" "$adExpirationDatePlusFiveEpoch" "+%m/%d/%Y")
                        writeLog "Updating $currentUser password expiration date key to AD+5, $adExpirationDatePlusFive"
                        defaults write "$userCompliancePlist" mainUserExpirEpoch "$adExpirationDatePlusFiveEpoch"
                        defaults write "$userCompliancePlist" mainUserExpir "$adExpirationDatePlusFive"
                        chmod 664 "$userCompliancePlist"
                    else
                        writeLog "adExpirationDate is missing. Not setting expiration date or alerting..."
                fi
        fi
        writeLog "Verifying password is synced with AD..."
        localADPasswordsInSync=$(defaults read "$homeFolder""$enterpriseConnectPrefs" localADPasswordsInSync)
        if [[ $localADPasswordsInSync -eq 0 ]]
            then
                writeLog "${currentUser}'s password is not synced with AD. Prompting and relaunchig app to fix..."
                defaults write "$userCompliancePlist" localADPasswordsInSync -bool FALSE
                chmod 664 "$userCompliancePlist"
                yoFix "Local password doesn't match CEC" "Click the fix button to sync" "adNotSyncedPrompt"
                exit    
            elif [[ $localADPasswordsInSynced -eq 1 ]]
                then
                    writeLog "${currentUser}'s password is synced with AD..."
                    defaults write "$userCompliancePlist" localADPasswordsInSync -bool TRUE
                    chmod 664 "$userCompliancePlist"
        fi
    else
        writeLog "Enterprise Connect prefs don't exist. Prompting and launching app to fix..."
        yoFix "Enterprise Connect not configured" "Click the fix button to configure" "prefsMissingPrompt"
        exit
fi


if [[ -e "$enterpriseConnectApp" ]]
    then
        counter=1
        while [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
        do
            if [ $counter -gt 9 ]
                then
                    if [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
                        then
                            writeLog "Error"
                            writeLog "Unable to get Enterprise Connect running. Exiting..."
                            exit 1
                        else
                            writeLog "Enterprise Connect launched on attempt $counter"
                            break
                    fi
                else
                    if [[ $(ps aucxwwm | grep -v  grep | grep -Ec '(^|s)Enterprise Connect($|s)') -lt 1 ]]
                        then
                            writeLog "Enterprise Connect not running. Launching..."
                            launchEnterpriseConnect
                        else
                            writeLog "Enterprise Connect launched on attempt $counter"
                            break
                        fi
            fi
            counter=$[$counter+1]
            sleep 10
        done
    else
        writeLog "Enterprise Connect missing. Exiting..."
fi

writeLog "Enterprise Connect running..."

exit

rickwhois
Contributor

@iJake this is quite magical! It has got my gears turning for sure. Thanks very much for sharing this.

iJake
Valued Contributor

@rickwhois Glad to help! If you or anyone has the same or similar case where you need to manage the password policy for non-bound accounts using pwpolicy I'd be more than happy to make a write up on our whole implementation we wrote around Enterprise Connect.

lashomb
Contributor II

@iJake I'd love to see your implementation! Few months later, but I think more than a few people are getting away from bound devices.

iJake
Valued Contributor

Below is an overview of the moving parts of Cisco's implementation including where they are located, what they do, and what invokes them. If you would like details on any individual part I can provide that.

Our implementation of Enterprise Connect at Cisco has a heavily customized workflow with daemon, agents, and both Casper-side and local scripts to leverage Enterprise Connect as the basis for our password policy and local account enforcement. As part of this, the daemon will attempt to determine the main user of the machine when there are multiple accounts in order to only present the alerts and Enterprise Connect GUI to one user.

For local accounts determined not to be the main user, password policy enforcement will work by comparing the date the password of the account was last set to the date the latest password policy was installed. If the password was set earlier than the policy install date then the account will have it’s password expired so that it can be updated to ensure it meets policy. Passwords for these secondary accounts are expired after 180 days of their last change should they reach that age.

Casper Side
1. Enforces (if user logged in) a. pwpolicy up to date (via hashing to ensure tamper-resistant) b. LaunchDaemon installed and running c. LaunchAgent installed and running d. MDM Configuration Profile installed e. Enterprise Connect installed, up to date, and running f. Yo.app installed g. Removes legacy ChangePW install

  1. Scripts a. enterpriseConnectEnforce_MONTH-DAY-YEAR.sh i. Casper-side enforcement script ii. Date is pwpolicy xml date b. enterpriseConnectPayload.sh i. Casper-side installation script called by enforce script ii. Installs Enterprise Connect.app, LaunchDaemon, LaunchAgent, and associated scripts c. enterpriseConnectPWpolicyInstaller.sh i. Clears current local and installs latest pwpolicy via XML embedded in script ii. Calculates hash of pwpolicy output after installing and stores it in plist for verification by local daemon
  2. Packages a. CiscoYo.pkg i. Installs Cisco-branded Yo.app ii. Used to alert users

Client Side
1. LaunchDaemon (Runs as root) a. Determines main user of machine (if multiple found) i. Removes password hint ii. Sets expiration of main user to AD +5 Days determined by LaunchAgent b. Enforces pwpolicy up to date (via hashing to ensure tamper-resistant) c. Manages password expiration of secondary accounts i. If password is older than pwpolicy install time password is expired ii. Unless password is already expired

  1. LaunchAgent (runs as user) a. Reads in main user which determines if EC needs to be running i. Ensures is running if main user logged in b. Ensures EC is configured for main user i. Alerts via Yo.app or jamfhelper if not c. Ensures EC has check AD in at least 14 days i. Alerts via Yo.app or jamfhelper if not d. Reads AD password expiration date. Calculates AD +5 days for LaunchDaemon e. If AD password expires in less than 2 days presents additional alerting i. Alerts via Yo.app or jamfhelper if not f. Ensures local password is synced with AD password i. Alerts via Yo.app or jamfhelper if not

  2. Enterprise Connect.app a. Preferences managed via MDM profile from Casper b. Asks for and stores, in Keychain, users CEC credentials c. Checks credentials and reads AD expiration date from AD on network state change d. Acquires Kerberos TGT e. Notifies user of impending AD account expiration f. Allows user to see AD account expiration in menu bar g. Allows user to set network shares to automatically mount on connection h. Asks user to sync local password with AD

  3. Scripts a. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectDaemon.sh i. Called by LaunchDaemon b. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectLauncher.sh i. Called by LaunchAgent c. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectSuccessConnect.sh i. Called by Enterprise Connect.app on successful auth to AD ii. Records timestamp of last time AD expiration was checked iii. Set by MDM Profile d. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectPassSync.sh i. Called by enterpriseConnectPassSyncLauncher.sh ii. Attempts to sync AD password at pwreset.cisco.com iii. Users can choose to manually sync instead iv. Updates blizzard and Outlook keychain entries with new password e. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectPassSyncLauncher.sh i. Called by Enterprise Connect.app on successful AD password change ii. Runs enterpriseConnectPassSync.sh in background iii. EC GUI would appear frozen if sync not tasked out f. /Library/CiscoIT/Scripts/EnterpriseConnect/enterpriseConnectKiller.sh i. Quits and reopens Enterprise Connect.app process for Launcher

swolosin
New Contributor III

I've given up on EC's ability to auto launch and wrote a launchD for it.

<?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>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Applications/Wireshark.app/Contents/MacOS:/usr/local/sbin</string>
    </dict>
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <true/>
    </dict>
    <key>Label</key>
    <string>LnchEC</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/Enterprise Connect.app/Contents/MacOS/Enterprise Connect</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Minute</key>
            <integer>60</integer>
        </dict>
    </array>
</dict>
</plist>

mottertektura
Contributor

Here's what I cooked up. It ain't pretty, but it works.

#!/bin/bash

#app="${4}"
app="Enterprise Connect"
#appPath="${5}"
appPath="/Applications/Enterprise Connect.app"

IFS=","

# Identify the username of the logged-in user
currentUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`

if [[ $? != 0 ]]; then
    currentUser=$( /usr/bin/stat -f%Su /dev/console )
    /bin/echo "Python user check failed. Checking console."
    /bin/echo "Logged in username is $currentUser"
else
    /bin/echo "Python user check successful."
    /bin/echo "Logged in username is $currentUser"
fi

# Identify the UID of the logged-in user
currentUserUID=`id -u "$currentUser"`

listLoginItems=$(/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to get the name of every login item')

/bin/echo "Login Items: $listLoginItems"

for v in $listLoginItems; do
    noSpace="$(echo -e "${v}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    if [[ "$noSpace" == "$app" ]]; then
        /bin/echo "$noSpace found in Login Items. Exiting..."
        exit 0
    fi
done

/bin/echo "$app was not found in Login Items. Adding login item $app..."
/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to make login item at end with properties {name: "'$app'",path:"'$appPath'", hidden:false}'

listLoginItems=$(/bin/launchctl asuser "$currentUserUID" /usr/bin/osascript -e 'tell application "System Events" to get the name of every login item')
for v in $listLoginItems; do
    noSpace="$(echo -e "${v}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    if [[ "$noSpace" == "$app" ]]; then
        /bin/echo "$app found in Login Items. Exiting..."
        exit 0
    fi
done

/bin/echo "Something went wrong. $app was not found in Login Items. Exiting..."
/bin/echo "Login Items: $listLoginItems"
exit 1

mauroghiglia
New Contributor

Hello,
I hope this is the right discussion for this. If not, please help me finding an answer to my problem.
My organization uses Enterprise Connect. Problems come when a user is not connected to our domain network and his/her password has expired.
We've found a workaround for this but only works if the user is still able to login into his/her Mac but, many times, users are locked out from their Mac systems and the old password doesn't work (since it has expired) and a new temporary one is not accepted (it seems that Enterprise Connect is unable to work with AD temporary passwords).
Do you think that a new password set with an external tool could work?

Thanks for your time, guys.