Hi @Wade_Wolf. Welcome to MacScripter.
Sorry for the slow reply. The script in post 12 above already handles the “Country or Region” field in Contacts on my machine. Did you mean something different? The new version below also includes Department and Instant Message addresses. Do let me know if there are any problems.
use AppleScript version "2.5" -- OS X 10.11 (El Capitan) or later
use framework "Foundation"
use framework "Contacts"
main()
on main()
set search_string to "X-SHARED-PHOTO-DISPLAY-PREF:ALWAYS_ASK"
tell application "Contacts" to if (running) then quit
set |⌘| to current application
-- Fetch all the contacts from the user's Contacts database, including their phone numbers, e-mail addresses, URL addresses, postal addresses, and notes.
set contactStore to |⌘|'s class "CNContactStore"'s new()
set contactArray to contactStore's unifiedContactsMatchingPredicate:(missing value) ¬
keysToFetch:({|⌘|'s CNContactPhoneNumbersKey, |⌘|'s CNContactEmailAddressesKey, |⌘|'s CNContactUrlAddressesKey, |⌘|'s CNContactInstantMessageAddressesKey, |⌘|'s CNContactPostalAddressesKey, |⌘|'s CNContactDepartmentNameKey, |⌘|'s CNContactNoteKey}) |error|:(missing value)
set postalAddressFormatter to |⌘|'s class "CNPostalAddressFormatter"'s new()
set postalAddressKeys to {|⌘|'s CNPostalAddressCountryKey, |⌘|'s CNPostalAddressISOCountryCodeKey, |⌘|'s CNPostalAddressPostalCodeKey, |⌘|'s CNPostalAddressStateKey, |⌘|'s CNPostalAddressCityKey, |⌘|'s CNPostalAddressStreetKey}
-- Work through each contact in turn.
repeat with thisContact in contactArray
set {phonesCorrected, phoneNumbers} to checkPhoneNumbers(thisContact, search_string)
set {emailsCorrected, emailAddresses} to checkURLs(thisContact, |⌘|'s CNContactEmailAddressesKey, search_string)
set {urlsCorrected, urlAddresses} to checkURLs(thisContact, |⌘|'s CNContactUrlAddressesKey, search_string)
set {IMAddressesCorrected, IMAddresses} to checkIMAddresses(thisContact, search_string)
set {postalAddressesCorrected, postalAddresses} to checkPostalAddresses(thisContact, postalAddressFormatter, postalAddressKeys, search_string)
set {departmentCorrected, department} to checkString(thisContact's departmentName(), search_string)
set {noteCorrected, note} to checkString(thisContact's note(), search_string) -- Only works in Script Editor.
if ((phonesCorrected) or (emailsCorrected) or (urlsCorrected) or (IMAddressesCorrected) or (postalAddressesCorrected) or (departmentCorrected) or (noteCorrected)) then
set mutableContact to thisContact's mutableCopy()
if (phonesCorrected) then (mutableContact's setPhoneNumbers:(phoneNumbers))
if (emailsCorrected) then (mutableContact's setEmailAddresses:(emailAddresses))
if (urlsCorrected) then (mutableContact's setUrlAddresses:(emailAddresses))
if (IMAddressesCorrected) then (mutableContact's setInstantMessageAddresses:(IMAddresses))
if (postalAddressesCorrected) then (mutableContact's setPostalAddresses:(postalAddresses))
if (departmentCorrected) then (mutableContact's setDepartmentName:(department))
if (noteCorrected) then (mutableContact's setNote:(note)) -- Only works in Script Editor.
set saveRequest to |⌘|'s class "CNSaveRequest"'s new()
(saveRequest's updateContact:(mutableContact))
(contactStore's executeSaveRequest:(saveRequest) |error|:(missing value))
end if
end repeat
end main
on checkPhoneNumbers(thisContact, search_string)
set bogey_found to false
set phoneNumbers to thisContact's phoneNumbers()'s mutableCopy()
repeat with labeledValue in phoneNumbers
set {corrected, correctedString} to checkString(labeledValue's value()'s stringValue(), search_string)
if (corrected) then
set bogey_found to true
set newPhoneNumber to (current application's class "CNPhoneNumber"'s phoneNumberWithStringValue:(correctedString))
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(newPhoneNumber))
end if
end repeat
return {bogey_found, phoneNumbers}
end checkPhoneNumbers
on checkURLs(thisContact, theKey, search_string)
set bogey_found to false
set URLs to (thisContact's valueForKey:(theKey))'s mutableCopy() -- E-mail or URL addresses.
repeat with labeledValue in URLs
set {corrected, correctedString} to checkString(labeledValue's value(), search_string)
if (corrected) then
set bogey_found to true
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(correctedString))
end if
end repeat
return {bogey_found, URLs}
end checkURLs
on checkIMAddresses(thisContact, search_string)
set bogey_found to false
set instantMessageAddresses to thisContact's instantMessageAddresses()'s mutableCopy()
repeat with labeledValue in instantMessageAddresses
set imaddress to labeledValue's value()
set {corrected, correctedString} to checkString(imaddress's username(), search_string)
if (corrected) then
set bogey_found to true
set newIMAddress to (current application's class "CNInstantMessageAddress"'s alloc()'s initWithUsername:(correctedString) service:(imaddress's service()))
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(newIMAddress))
end if
end repeat
return {bogey_found, instantMessageAddresses}
end checkIMAddresses
on checkPostalAddresses(thisContact, formatter, postalAddressKeys, search_string)
set |⌘| to current application
set bogey_found to false
set postalAddresses to thisContact's postalAddresses()'s mutableCopy()
repeat with labeledValue in postalAddresses
set postalAddress to labeledValue's value()
if ((formatter's stringFromPostalAddress:(postalAddress))'s containsString:(search_string)) then
set bogey_found to true
set postalAddress to postalAddress's mutableCopy()
repeat with thisKey in postalAddressKeys
set {corrected, correctedString} to checkString(postalAddress's valueForKey:(thisKey), search_string)
if (corrected) then
if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressCountryKey)) then
(postalAddress's setCountry:(correctedString))
else if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressISOCountryCodeKey)) then
(postalAddress's setISOCountryCode:(correctedString))
else if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressPostalCodeKey)) then
(postalAddress's setPostalCode:(correctedString))
else if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressStateKey)) then
(postalAddress's setState:(correctedString))
else if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressCityKey)) then
(postalAddress's setCity:(correctedString))
else if (thisKey's isEqualToString:(|⌘|'s CNPostalAddressStreetKey)) then
(postalAddress's setStreet:(correctedString))
end if
end if
end repeat
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(postalAddress))
end if
end repeat
return {bogey_found, postalAddresses}
end checkPostalAddresses
on checkString(theString, search_string)
set bogeyRange to theString's rangeOfString:(search_string)
set bogey_found to (bogeyRange's |length|() > 0)
if (bogey_found) then set theString to theString's substringWithRange:({0, bogeyRange's location()})
return {bogey_found, theString}
end checkString