Hello, I’m looking to modify an existing script I have found online, source. The purpose of this script is to remove the “X-SHARED-PHOTO-DISPLAY-PREF:ALWAYS_ASK” text that was added on to hundreds of contacts after importing them from iPhone contacts to iCloud contacts.
The existing script targets the native contact list on the Mac, which works fine, but when trying to get it to target the iCloud contact list, it errors out. Can anyone please help modify the existing script?
-- Define the search string
set search_string to "X-SHARED-PHOTO-DISPLAY-PREF:ALWAYS_ASK"
-- Get the list of contacts from the Contacts app
tell application "Contacts"
set contact_list to people
end tell
-- Iterate through each contact
repeat with contact in contact_list
set match_found to false
tell application "Contacts"
-- Iterate through each phone number of the contact
repeat with phone_number in phones of contact
set phone_value to value of phone_number
-- Check if the phone number contains the search string
if phone_value contains search_string then
-- Remove the search string from the phone number
set correct_phone_value to text 1 thru ((offset of search_string in phone_value) - 1) of phone_value
set value of phone_number to correct_phone_value
set match_found to true
end if
end repeat
-- Save the contact if a match was found
if match_found then save contact
end tell
end repeat
I tried modifying the “set contact_list to people” to the following below but none have worked so far.
“All iCloud”, All iCloud, “iCloud”, iCloud, “General”, General
Below is are images of the error I receive when I run the script.
Contacts.app’s scripting dictionary doesn’t offer a way to target particular accounts and I’m not sure what different accounts are included when it returns people.
I’ve put together a version of the script which targets the Contacts framework directly instead of using the Contacts application. I don’t know if it’ll be any more successful for your purposes, but it’s worth a try. It doesn’t work when run in Script Debugger, possibly because of the thread on which SD runs scripts. But it does work in Script Editor on my system and may do so in the script menu or as an application in its own right.
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
set contactStore to |⌘|'s class "CNContactStore"'s new()
-- Fetch all the contacts in the user's database (regardless of account?)
-- We're only interested in their phone numbers.
set contactArray to contactStore's unifiedContactsMatchingPredicate:(missing value) ¬
keysToFetch:({|⌘|'s CNContactPhoneNumbersKey}) |error|:(missing value)
repeat with thisContact in contactArray
set match_found to false
set phones to thisContact's phoneNumbers()'s mutableCopy() -- Editable array of labeled values.
repeat with labeledValue in phones
set numberString to labeledValue's value()'s stringValue()
-- Does the search string occur in the phone number string?
set bogeyRange to (numberString's rangeOfString:(search_string))
-- If so, replace the labeled value in the phones list with an edited version.
if (bogeyRange's |length|() > 0) then
set match_found to true
set correctedString to (numberString's substringWithRange:({0, bogeyRange's location()}))
set newPhoneValue to (|⌘|'s class "CNPhoneNumber"'s phoneNumberWithStringValue:(correctedString))
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(newPhoneValue))
end if
end repeat
-- If any of the labeled values were changed, save an edited copy of the contact.
if (match_found) then
set mutableContact to thisContact's mutableCopy()
(mutableContact's setPhoneNumbers:(phones))
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
Here you go. E-mail addresses, like phone numbers, are labeled values, but their values are the strings themselves instead of structures containing the strings.
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
set contactStore to |⌘|'s class "CNContactStore"'s new()
-- Fetch all the contacts in the user's database (regardless of account?)
-- In this script, we're only interested in their e-mail addresses.
set contactArray to contactStore's unifiedContactsMatchingPredicate:(missing value) ¬
keysToFetch:({|⌘|'s CNContactEmailAddressesKey}) |error|:(missing value)
repeat with thisContact in contactArray
set match_found to false
set emailAddresses to thisContact's emailAddresses()'s mutableCopy() -- Editable array of labeled values.
repeat with labeledValue in emailAddresses
set addressString to labeledValue's value()
-- Does the search string occur in the e-mail address string?
set bogeyRange to (addressString's rangeOfString:(search_string))
-- If so, replace the labeled value in the emailAddresses list with an edited version.
if (bogeyRange's |length|() > 0) then
set match_found to true
set correctedString to (addressString's substringWithRange:({0, bogeyRange's location()}))
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(correctedString))
end if
end repeat
-- If any of the labeled values were changed, save an edited copy of the contact.
if (match_found) then
set mutableContact to thisContact's mutableCopy()
(mutableContact's setEmailAddresses:(emailAddresses))
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
Here for completeness is a combination of the above two scripts which checks the phone numbers and e-mail addresses in the same run:
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 and e-mail addresses.
set contactStore to |⌘|'s class "CNContactStore"'s new()
set contactArray to contactStore's unifiedContactsMatchingPredicate:(missing value) ¬
keysToFetch:({|⌘|'s CNContactPhoneNumbersKey, |⌘|'s CNContactEmailAddressesKey}) |error|:(missing value)
-- Work through each in turn.
repeat with thisContact in contactArray
set {phonesCorrected, phoneNumbers} to checkPhoneNumbers(thisContact, search_string)
set {emailsCorrected, emailAddresses} to checkEmailAddresses(thisContact, search_string)
if ((phonesCorrected) or (emailsCorrected)) then
set mutableContact to thisContact's mutableCopy()
if (phonesCorrected) then (mutableContact's setPhoneNumbers:(phoneNumbers))
if (emailsCorrected) then (mutableContact's setEmailAddresses:(emailAddresses))
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 match_found to false
set phoneNumbers to thisContact's phoneNumbers()'s mutableCopy()
repeat with labeledValue in phoneNumbers
set numberString to labeledValue's value()'s stringValue()
set bogeyRange to (numberString's rangeOfString:(search_string))
if (bogeyRange's |length|() > 0) then
set match_found to true
set correctedString to (numberString's substringWithRange:({0, bogeyRange's location()}))
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 {match_found, phoneNumbers}
end checkPhoneNumbers
on checkEmailAddresses(thisContact, search_string)
set match_found to false
set emailAddresses to thisContact's emailAddresses()'s mutableCopy()
repeat with labeledValue in emailAddresses
set addressString to labeledValue's value()
set bogeyRange to (addressString's rangeOfString:(search_string))
if (bogeyRange's |length|() > 0) then
set match_found to true
set correctedString to (addressString's substringWithRange:({0, bogeyRange's location()}))
set labeledValue's contents to (labeledValue's labeledValueBySettingValue:(correctedString))
end if
end repeat
return {match_found, emailAddresses}
end checkEmailAddresses