Password Expiration Warning without Active Directory

zmiller
New Contributor II

We are working with a group that can't have an Acitve Directory server, but wants passwords to expire. We were able to create a password expiration using pwpolicy, but it does not produce an expiration warning, so users end up getting locked out in screensaver, or the Local Items in Keychain for 10.9 gets messed up when the password resets (this wouldn't be solved by a warning, but it would let the users know they need to reset the password via System Preferences).

I'm looking for something that will throw out a password expiration warning, but everything I find is for Active Directory. Is there a way to create this for a single user system?

25 REPLIES 25

mm2270
Legendary Contributor III

This is possible with some advanced scripting. In this case, dscl and later defaults will be your friends.

When looking at local accounts, dscl can read back the PasswordPolicyOptions property list section from the account, including the passwordLastSetTime key-

dscl . read /Users/someuser PasswordPolicyOptions

will output a (mostly) formatted property list of the pwpolicy options set as well as some other info. You can script exporting that out to a local file that you can later read with defaults.

dscl . read /Users/someuser PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

The sed '1d' is necessary to remove the first line and make it into a valid plist that you can later read with defaults-

defaults read /tmp/pwdpolicy.plist
{
    failedLoginCount = 0;
    failedLoginTimestamp = "2001-01-01 00:00:00 +0000";
    lastLoginTimestamp = "2001-01-01 00:00:00 +0000";
    passwordLastSetTime = "2013-12-03 18:58:02 +0000";
}
defaults read /tmp/pwdpolicy.plist passwordLastSetTime
2013-12-03 18:58:02 +0000

Using that info, you can then have the script compare the time the password was last set with the current time, figure out if you're nearing the password expiration date and alert the user.
You need to first convert the above date into a unix time in seconds before you can do a proper comparison to the current time in seconds.

Assuming you have a change password policy set to say, 90 days, here's an example script:

#!/bin/bash

dscl . read /Users/someaccount PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

pwdLastSet=$( defaults read /tmp/pwdpolicy.plist passwordLastSetTime | awk '{print $1,$2}' )

pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" )
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

echo "User's password was reset $passwordResetDaysAgo days ago"

if [[ "$passwordResetDaysAgo" -gt 85 ]]; then
    do something here to alert them
else
    exit 0
fi

Hope that helps.

Edited to correct the comparison to -gt x days.

zmiller
New Contributor II

This works wonderfully!

There are a lot of computers that will need this and I found that changing

dscl . read /Users/someaccount PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

to

dscl . read $HOME PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

will check whatever user is currently logged in.

Fantastic!

mm2270
Legendary Contributor III

Good idea! I should listen to my own advice ;) I often tell folks not to hard code a path to a home directory with /Users/user, because you never know exactly where someone's home folder is located.

Glad that helped!

zmiller
New Contributor II

I had to launch the script using launchd, because that was the only way I could get it to capture the user path.

I've been playing around with the script and I've managed to include a countdown in the dialog, and change the name of the buttons, but I want the Accounts Pane of System Preferences to launch when someone clicks "Change Now," but everything I use to capture the button and then launch the application kills the script in terminal.

#!/bin/bash


dscl . read $HOME PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

pwdLastSet=$( defaults read /tmp/pwdpolicy.plist passwordLastSetTime | awk '{print $1,$2}' )

pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" )
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo )

echo "User's password was reset $passwordResetDaysAgo days ago"

echo "Password will expire in $passwordExpiresDays days."

if [[ "$passwordResetDaysAgo" -gt 52 ]]; then
osascript -e 'tell app "System Events" to display dialog "Your password will expire in '$passwordExpiresDays' days. You must change it soon to avoid becoming locked out.

You can change it in System Preferences under Users & Groups." buttons {"Remind Me Later", "Change Now"} default button 2 with title "Password Change Required" with icon caution'

else
exit 0
fi

I've been banging my head against this for far too long and my rudimentary programing skills are failing me. Is there a way to make "Change Now" launch the Accounts Pane of System Preferences in this script?

mm2270
Legendary Contributor III

@zmiller][/url- yes, it can be done but you'll either need to use AppleScript GUI scripting, which is not always the most reliable method, or you can simply have it open System Preferences > Users & Groups. If you want to "click" the change password button to leave them at the screen to change their password, then GUI scripting is the only way.

To simply open System Preferences and open Users & Groups. you can try this-

open /System/Library/PreferencePanes/Accounts.prefPane

YMMV on this when its run from a script, but that should pop open the Users & Groups PrefPane. Keep in mind the name of that Preference Pane may have changed between various versions of OS X, so if you're targeting a broad variety of OS versions, you may need to code for each type by detecting the OS version and using the appropriate command.

OTOH, if you want to open System Preferences > Users & Groups and click the Change Password button for them, then this Applescript block will typically work:

tell application "System Preferences"
    activate
    set the current pane to pane id "com.apple.preferences.users"
    reveal anchor "passwordPref" of pane id "com.apple.preferences.users"
    tell application "System Events"
        tell process "System Preferences"
            click button "Change Password…" of tab group 1 of window 1
        end tell
    end tell
end tell

Since you'd be putting that into a shell script, use the heredoc format to have the script run it as a separate block of commands, like this:

/usr/bin/osascript <<EOF
tell application "System Preferences"
    activate
    set the current pane to pane id "com.apple.preferences.users"
    reveal anchor "passwordPref" of pane id "com.apple.preferences.users"
    tell application "System Events"
        tell process "System Preferences"
            click button "Change Password…" of tab group 1 of window 1
        end tell
    end tell
end tell
EOF

Lastly, I wasn't really paying close attention to why you were using $HOME in your script but its not necessary. The dscl . read /Users/someuser part in the script is not looking at the actual user home directory path. Regardless of where any user account on the system is located, it always exists under /Users/ when talking about dscl. Even when an account home directory happens to be located in the path of /private/var/ like with some hidden accounts, or root, etc, doing dscl . read /Users/user reveals the data you're looking for in the script. As such it shouldn't be necessary to use $HOME in the script.
If you want to get the current logged in user information, just use this instead:

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

Then, in the script…

dscl . read /Users/$loggedInUser…….

Hope that helps.

Edit: Forgot to add that using the $loggedInUser with the dscl command will remove the need to run this as a launchd job. It will always look only at the user logged in, even if the script runs as root.

zmiller
New Contributor II

Thank you for the information about how to get the script to launch into "System Preferences" Acounts Pane and click the "Change Password" button.

I'm having a couple of issues.

I tried running it with the script

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

dscl . read /Users/$loggedInUser

but it wouldn't launch from Casper.

I also haven't been able to get the script to capture the click on the "Change Now." When I run the script in terminal it ends with "button returned:Change Now
logout"

I want the script to see that the "Change Now" button was clicked, and then have it launch "System Preferences."

mm2270
Legendary Contributor III

@zmiller, the "dscl . read /Users/$loggedInUser" was a reference to that line. You need the rest of the command for it to work, so:

dscl . read /Users/$loggedInUser PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

Sorry if that wasn't clear. Does the script include that full line?

zmiller
New Contributor II

Yes,

#!/bin/bash

loggedInUser=$( ls -l /dev/console | awk '{print $3}'

dscl . read /Users/$loggedInUser PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

pwdLastSet=$( defaults read /tmp/pwdpolicy.plist passwordLastSetTime | awk '{print $1,$2}' )

pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" )
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo )

echo "User's password was reset $passwordResetDaysAgo days ago"

echo "Password will expire in $passwordExpiresDays days."

if [[ "$passwordResetDaysAgo" -gt 1 ]]; then
osascript -e 'tell app "System Events" to display dialog "Your password will expire in '$passwordExpiresDays' days. You must change it soon to avoid becoming locked out.

You can change it in System Preferences under Users & Groups." buttons {"Remind Me Later", "Change Now"} default button 2 with title "Password Change Required" with icon caution'

else
exit 0
fi

mm2270
Legendary Contributor III

I see the issue. Your first line doesn't have a closing paren.
You have:

loggedInUser=$( ls -l /dev/console | awk '{print $3}'

and it needs to be:

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

I may have posted it without the closing paren. If so, sorry for the confusion. Anyway, make that change and try it again.

zmiller
New Contributor II

Ack! Sorry, I was doing a lot of undo/redo on the code and copied/pasted an older version of the code. I have the ")" in the script in Capser, but when I run it, it doesn't produce the System Event.

The log just says:

Running command #!/bin/bash loggedInUser=$( ls -l /dev/console | awk '{print $3}' ) dscl . read /Users/$loggedInUser PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist pwdLastSet=$( defaults read /tmp/pwdpolicy.plist passwordLastSetTime | awk '{print $1,$2}' ) pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" ) currentUnixTime=$( date +"%s" ) passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 ) currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 ) passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays ) passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo ) echo "User's password was reset $passwordResetDaysAgo days ago" echo "Password will expire in $passwordExpiresDays days." if [[ "$passwordResetDaysAgo" -gt 1 ]]; then osascript -e 'tell app "System Events" to display dialog "Your password will expire in '$passwordExpiresDays' days. You must change it soon to avoid becoming locked out. You can change it in System Preferences under Users & Groups." buttons {"Remind Me Later", "Change Now"} default button 2 with title "Password Change Required" with icon caution' else exit 0 fi...

Sorry for the confusion, I'm working on 50 different things here.

mm2270
Legendary Contributor III

Well that's bizarre. Not sure if that's a Casper Suite 9 thing, but I have no idea why the entire contents of the script would be output in the log. Looks to me like its not recognizing the script properly or something. The only thing showing up there should be anything sent to stdout, like echo commands, as well as the exit code, etc. All the lines in the script shouldn't be in the log as far as I know.

mm2270
Legendary Contributor III

@zmiller][/url][/url - just circling back on this. Can you double check that the script file is saved as a plain text file with a .sh extension? What application did you create the script in? If it was TextEdit, make sure the application didn't convert straight quotes into curly quotes just as one example of some things to check.

As I said, I don't think the whole script contents should be appearing in the policy log like that. I know version 9 has a quirk where script output line breaks don't get recognized, but, it seems like its just reading back the contents of the script and not actually running it to me.

Also, once we get it to work, have you considered using some other messaging tool, like jamfHelper, cocoaDialog, etc instead of Applescript for the dialog? While I'm not certain its not working because of the osascript call, I know I've run into my fair share of times when these didn't work as expected, or needed workarounds to make them actually appear. The other tools don't require any workarounds in most cases.

Edit: try this script. This may address the button opening System Preferences > Users & Groups and clicking the Change Password button. Even though you can do it with Applescript, I switched this out to using jamfHelper. The only issue I see is that the button with the labeled "Remind Me Later" gets cut off. Seems to be a limitation of jamfHelper that the button size doesn't scale accordingly.

If it still doesn't work, you may need to use some special syntax to get it to work from a script run by Casper.

#!/bin/bash

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

dscl . read /Users/$loggedInUser PasswordPolicyOptions | sed '1d' > /tmp/pwdpolicy.plist

pwdLastSet=$( defaults read /tmp/pwdpolicy.plist passwordLastSetTime | awk '{print $1,$2}' )

pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" )
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo )

echo "User's password was reset $passwordResetDaysAgo days ago"

echo "Password will expire in $passwordExpiresDays days."

if [[ "$passwordResetDaysAgo" -gt 1 ]]; then
    Msg="Your password will expire in '$passwordExpiresDays' days. You must change it soon to avoid becoming locked out.

You can change it in System Preferences under Users & Groups."

    passDialog=$( /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper 
    -windowType utility -title "Password Change Required" -description "$Msg" 
    -button1 "Remind Me Later" -button2 "Change Now" -defaultButton 2 
    -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertCautionIcon.icns" )

    if [[ "$passDialog" == "2" ]]; then
/usr/bin/osascript <<EOF
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preferences.users"
reveal anchor "passwordPref" of pane id "com.apple.preferences.users"
tell application "System Events"
tell process "System Preferences"
click button "Change Password…" of tab group 1 of window 1
end tell
end tell
end tell
EOF
    else
        exit 0
    fi
else
    exit 0
fi

zmiller
New Contributor II

My goodness! Everything works!

I was able to get the script working in Casper, and it goes through and clicks the Change Password... button (After allowing this through Accessibility in Security & Privacy in 10.9)!

Thank you so much!

rfadul
New Contributor II

@zmiller Can you provide information on how you were able to allow this through Accessibility in Security & Privacy?

tlarkin
Honored Contributor

Hi Everyone,

I helped several customers write an AD password expiry script that mimicked the functionality of ADPassMon. I think what @rfadul is getting at, is that starting in Mavericks, OS X became more sandboxed, and you needed to basically allow Terminal.app to be enabled into Security and Privacy. To accomplish this you must edit the TCC database, which I find sort of hacky so I don't really do that. Plus not to mention any Apple update could overwrite or change that SQL Lite database file.

Here is the script I came up with, borrowing code from a couple customers and adding a few tidbits here and there:

#!/bin/bash

# AD password expiry notification script
# by tlark
# no warranty given, this is only proof of concept tested on cached AD profiles on OS X 10.9.2

# this script grabs the current user by detecting who owns /dev/console

currentUser=$(ls -l /dev/console | awk '{print $3}')

# message you would like to display to the user
question='your AD password is going to expire in ${daysremaining} would you like to change it now?'


todayUnix=$(date "+%s") # today's date on OS X in epoch time

pwdExpDays='42' # default value for when you rotate passwords in AD, set this to reflect when AD is set via GPO to expire a password

# depending on your environment you may need to use /Search in your dscl query or the full AD path
# or you can point it to the local node if everything is cached
# there is also a SMBPasswordLastSet but not sure if it syncs with pwdLastSet which is the legit AD attribute

ADpasswdLastSet=$(dscl /Active Directory/AD/All Domains read /Users/${currentUser} pwdLastSet | awk '{print $2}')

lastpwdUnix=$(expr ${ADpasswdLastSet} / 10000000 - 11644473600) # math to convert LDAP time stamp to epoch

diffUnix=$(expr ${todayUnix} - ${lastpwdUnix}) # math to get the current epoch date minus the LDAP to Epoch timestamp

diffdays=$(expr ${diffUnix} / 86400) # converts seconds into days, will return 0 if not enough seconds to equal a day

daysremaining=$(expr ${pwdExpDays} - ${diffdays}) # math to get days remaining

# functions go here to be executed dependeding on user interaction

yesNo () {

    # prompt user for yes|no answers

theAnswer=$(/usr/bin/osascript <<AppleScript
tell application "Finder"
 activate
 display dialog "Hello ${currentUser}, ${question}" buttons {"No","Yes"} default button 2
  if the button returned of the result is "No" then
   set theAnswer to No
  end if
end tell
AppleScript)

/bin/echo "${theAnswer}"

if [[ ${theAnswer} == "no" ]]
    then theAnswer="no"
    else theAnswer="yes"
fi
}

changePasswd() {

osascript <<AppleScript
tell application "System Preferences"
 activate
  set the current pane to pane id "com.apple.preferences.users"
end tell
 tell application "System Events"
  tell process "System Preferences"
   click button "Change Password…" of tab group 1 of window "Users & Groups"
  end tell
 end tell
AppleScript
}


# compare days remaining to a value of 15
# if the user has more than 2 weeks to change their password this will exit

if [[ "${daysremaining}" -lt "15" ]]

    then yesNo
    else echo "password has more than two weeks"

fi

if [[ ${theAnswer} == 'yes' ]]
    then changePasswd
    else echo "User clicked no"

fi

exit 0

What I did was take out the code that actually clicked on the change password button. Because in 10.8.x and older OSes you can click on the button via Applescript with out having to add Terminal.app to the security options. Another option I explored was a case statement (you could use if/then/elif as well) that had two sets of variables, ones for OS version 10.8 and under and one for Mavericks.

Which is basically just a separate function:

changePasswdMavericks() {

 osascript <<AppleScript
tell application "System Preferences" to activate
tell application "System Preferences"
set current pane to pane id "com.apple.preferences.users"
end tell
tell application "System Preferences" to activate
AppleScript

That way you don't have to fuss with the TCC database file, and the downside is your users will have to click on the change password button. I honestly don't have a full opinion on modifying the TCC database file, but I do feel I have not tested it enough in a production environment to say it is a good idea or not.

Thanks,
Tom

bentoms
Release Candidate Programs Tester

@tlarkin, you could use my ADPassMon fork: http://macmule.com/2014/04/01/announcing-adpassmon-v2-fork/

This bypasses the need for the UI scripting.

bentoms
Release Candidate Programs Tester

Should've read the post.

Ignore me

ifbell
Contributor

Okay I have put parts of the scripts above to use and they work on my 10.9 machines, if I run the same script on 10.10.x it does not fail but no data gets created. My thoughts are that the PasswordPolicyOptions is not functioning in 10.10 or maybe it is just me.

This is the core of my password script.

#!/bin/bash

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

pwdSet=$( dscl . -read /Users/$loggedInUser PasswordPolicyOptions | sed -n '/passwordLastSetTime/{n;s@.*<date>(.*)</date>@1@p;}')

pwdLastSet=$( echo $pwdSet | sed 's/T/ /;s/Z//' )

pwdLastSetUnix=$( date -jf "%Y-%m-%d %H:%M:%S" "$pwdLastSet" +"%s" )
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo )

jamf displayMessage -message "your password is "$passwordResetDaysAgo" days old. Your password will expire in "$passwordExpiresDays" days."

zmiller
New Contributor II

Apple changed everything in 10.10. And it still doesn't work right.

takayoshi_nakao
New Contributor

Hi Ian-san,

How about this?

#!/bin/bash
loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

pwdSetEpoch=$( dscl . -read /Users/$loggedInUser accountPolicyData | sed -n '/passwordLastSetTime/{n;s@.*<real>(.*)</real>@1@p;}')

pwdLastSetUnix=$( echo $pwdSetEpoch | sed s/.[0-9,]*$//g )

currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSetUnix / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

passwordExpiresDays=$( expr 60 - $passwordResetDaysAgo )

jamf displayMessage -message "your password is "$passwordResetDaysAgo" days old. Your password will expire in "$passwordExpiresDays" days."

ifbell
Contributor

So I am revisiting this with 10.10.5 so if I run the command

_______________________________________________________
bash-3.2# dscl . -read /Users/$Username accountPolicyData dsAttrTypeNative:accountPolicyData: <?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>creationTime</key> <real>1437053022.528693</real> <key>failedLoginCount</key> <integer>39</integer> <key>failedLoginTimestamp</key> <real>1438277828.603523</real>
</dict>
</plist>
__________________________________
if I run this
__________________________________
bash-3.2# dscl . read /Users/$Username PasswordPolicyOptions
No such key: PasswordPolicyOptions
__________________________________**

if I run it as
_____________________________________
bash-3.2# dscl . -read /Users/root PasswordPolicyOptions
PasswordPolicyOptions: <?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>failedLoginCount</key> <integer>4</integer> <key>failedLoginTimestamp</key> <date>2014-12-22T21:16:57Z</date> <key>lastLoginTimestamp</key> <date>2001-01-01T00:00:00Z</date> <key>passwordLastSetTime</key> <date>2013-12-13T12:36:24Z</date>
</dict>
</plist>


So has anyone come up with an answer to this with 10.10.X ?

ehemmete
New Contributor II

Incase anyone else is working on this for 10.11(.4). Apple seems to have changed the type of data stored in the passwordLastSetTime variable again. Now it is stored in UNIX time, with a decimal. Here is what seems to be working for me:

#!/bin/sh
# Check if the users password will expire in X days

username=$( ls -l /dev/console | awk '{print $3}' )

dscl . read /Users/"$username" dsAttrTypeNative:accountPolicyData | sed '1d' > /tmp/pwdpolicy.plist

pwdLastSet=$(defaults read /tmp/pwdpolicy.plist passwordLastSetTime | cut -d"." -f 1)
currentUnixTime=$( date +"%s" )

passwordSetTimeDays=$( expr $pwdLastSet / 60 / 60 / 24 )
currentTimeDays=$( expr $currentUnixTime / 60 / 60 / 24 )

passwordResetDaysAgo=$( expr $currentTimeDays - $passwordSetTimeDays )

echo "User's password was reset $passwordResetDaysAgo days ago"

CesarT_T
New Contributor III

 

 

Pagigostra
New Contributor II

Hello Everyone,

I do not know if anyone else is running into the issue I am having. I have code like the code you are using. It will get the epoch date right and will enter the loop as needed, however if the User changes their password the system does not update the passwordLastSetTime. This is causing the code to enter the loop when it is ran again.

Any ideas on why it isn't updating right away or how to fix that time?

Thanks,

oliver
New Contributor III
New Contributor III

xpath alternative for finding the last change datetime...

#!/bin/bash
#in 10.12.5...

loggedInUser=$( ls -l /dev/console | awk '{print $3}' )
passwordDateTime=$( dscl . read /Users/$loggedInUser accountPolicyData | sed 1,2d | /usr/bin/xpath "/plist/dict/real[preceding-sibling::key='passwordLastSetTime'][1]/text()" 2> /dev/null | sed -e 's/.[0-9]*//g' )
((passwordAgeDays = ($(date +%s) - $passwordDateTime) / 86400 ))

if [[ "$passwordAgeDays" -gt 90 ]]; then
osascript -e 'tell application "System Events" to display dialog "Your password has expired. (Last set '${passwordAgeDays}' ago.)

You can change it in System Preferences under Users & Groups." buttons {"Change Now"} default button 1 with title "Password Change Required" with icon caution'
    open /System/Library/PreferencePanes/Accounts.prefPane
else
    exit 0
fi