#!/usr/bin/python2.7 import datetime import plistlib import subprocess # Obtain username from last logged in user user = plistlib.readPlistFromString(subprocess.check_output(['/usr/bin/syslog', '-F', 'xml', '-k', 'Facility', 'com.apple.system.lastlog', '-k', 'Sender', 'loginwindow']))[-1]['ut_user'] # Get UID of user uid_returned = subprocess.check_output(['/usr/bin/dscl', '.', '-read', '/Users/' + user, 'uid']) uid = int(uid_returned.split()[1:][0]) # UIDS < 1000 are local users; UIDs > 1000 are network accounts if uid < 1000: # Use 'dcsl' to read 'PasswordPolicyOptions' data # This first method works on 10.9 or earlier clients, or 10.10 clients that migrated from earlier versions output = subprocess.check_output(['/usr/bin/dscl', '.', '-read', '/Users/' + user, 'PasswordPolicyOptions']) try: plist = plistlib.readPlistFromString('\n'.join(output.split()[1:])) # When read from 'PasswordPolicyOptions' the date is a 'datetime' object lastSetDate = plist['passwordLastSetTime'].date() except Exception: # If 'passwordLastSetTime' does not exist the data will be found in 'accountPolicyData' # This is expected on 10.10 or newer clients that were not migrated output = subprocess.check_output(['/usr/bin/dscl', '.', '-read', '/Users/' + user, 'accountPolicyData']) try: # The syntax below strips the first line from 'output' which is not valid XML plist = plistlib.readPlistFromString('\n'.join(output.split()[1:])) # When read from 'accountPolicyData' the date is in a floating point/real number timestamp format lastSetDate = datetime.datetime.utcfromtimestamp(plist['passwordLastSetTime']).date() except Exception: try: # If 'passwordLastSetTime' does not exist fall back to the account creation timestamp lastSetDate = datetime.datetime.utcfromtimestamp(plist['creationTime']).date() except Exception: # If unable to determine any usable timestamp from the above, exit with a 'No Value' result print("No Value") raise SystemExit else: try: # Active Directory accounts use the SMBPasswordLastSet attribute output = subprocess.check_output(['/usr/bin/dscl', '.', '-read', '/Users/' + user, 'SMBPasswordLastSet']) epoch_last_set_time = int(output.split()[1:][0]) / 10000000 - 11644473600 lastSetDate = datetime.datetime.utcfromtimestamp(epoch_last_set_time).date() except Exception: try: # If 'passwordLastSetTime' does not exist fall back to the account creation timestamp lastSetDate = datetime.datetime.utcfromtimestamp(plist['creationTime']).date() except Exception: # If unable to determine any usable timestamp from the above, exit with a 'No Value' result print("No Value") raise SystemExit # 'datetime' supports addition and subtraction between 'datetime.date' objects # We use this here to obtain the number of days from today and the 'lastSetDate' today = datetime.datetime.utcnow().date() passwordAge = (today - lastSetDate).days # Output the result for the extension attribute print("{0}".format(passwordAge))