Password Change Script Won't Repeat

So I’m trying to create an Applescript to batch change all the stored keychain passwords for printers, since we’re required to change passwords every ninety days. I found the following script from here which I based my version on:

tell application "Keychain Scripting"
	tell keychain "holbrook"
		set matches to keys whose name is "Safari Forms AutoFill"
		repeat with match in matches
			tell me to display dialog (get account of match)
		end repeat
	end tell
end tell

That script works as advertised and and displays the dialog of each form. I tried to modify it for my needs to look for certain accounts and change the password of each entry. I came up with this:

tell application "Keychain Scripting"
	tell current keychain
		set matches to keys whose account is "DOMAIN\\username"
		repeat with match in matches
			set password of match to "abc123"
		end repeat
	end tell
end tell

The script works, but it doesn’t repeat. It’ll change the password for one key, but not for all of them. If I run the script again, oddly enough, it changes the password for the next one. If anybody could let me know if I’m doing something wrong, I’d appreciate it.

Hi, Thunderforge, and welcome to these forums.

I haven’t tried changing all my passwords to test this, but it sounds as if you may have run into a ‘reference’ problem. Keychain Scripting returns the keys as a list of index references to the various generic and Internet keys. I suspect it might reorder the keys internally after changing a password, making the references you’ve got in ‘matches’ out of date. You could try using name references instead:

tell application "Keychain Scripting"
	tell current keychain
		-- Get the names of the keys instead of index references.
		set matches to name of keys whose account is "DOMAIN\\username"
		repeat with match in matches
			-- Name reference: key match of current keychain.
			set password of key match to "abc123"
		end repeat
	end tell
end tell

I don’t know if keys have to have unique names or not. If not, the above will need further adjustment.

Keys have unique names:

tell application "Keychain Scripting"
	launch
	set KeyNames to name of every Internet key of current keychain
end tell

Then you’d change any of them (I didn’t actually try this):

tell application "Keychain Scripting"
	launch
	tell current keychain
		tell (some Internet key whose name is "blah") to set password to "FooBar"
	end tell
end tell

The first script by Nigel Garvey unfortunately didn’t work. I got the error Keychain Scripting got an error: Can’t set password of key (item 1 of {“Myers 107”, “asdfas”}) of current keychain to “abc123”. (Myers 107 and asdfas were two keys I was trying to get changed). I presume it didn’t work because they didn’t have unique names, as was suggested.

I’m a bit confused about Adam Bell’s scripts. The first script seems to set it up so that every internet password is changed. Unfortunately, it’s not that simple for me since the keys are network keys and there are only certain ones I need to change (the ones that have the DOMAIN\username sort of thing). At one point, I’d actually tried creating a script similar to Adam Bell’s second script, but tried to batch change the password by changing “some” to “every”. Unfortunately, I got the error "Keychain Scripting got an error: Can’t set password of every Internet key of current keychain whose account = “DOMAIN\username” to “FooBar” which was why I tried to find a way to repeat the script instead.

My first script was merely to illustrate that Internet keys do have names and that you could get them all in a list. Presuming that you know the names of those for which you want to change the password (perhaps in another list), it’s straight-forward to iterate through the key name list and change them as required.

“some Internet key whose name is “blah” will return a list – you need to iterate within it (or if only one there, get first item of…”

Like Nigel, I’m not willing to run such a script because I don’t want to change my own keychain, so you’ll have to do the testing. Easiest from here on if you post your own script for us.

My goal with this Applescript is to create a script that could help others in the same situation as I am. Because of the way things set up, the name of the key is the name of the printer, but we’ve got tons of printers, so it’s not really useful to search by name (not to mention that new ones are added every now and then). However, they all require the same account name, which is the domain and the username (which I’m representing as DOMAIN\username). That’s why I keep trying to make a list to define things by account rather than name, but I’m having trouble with that.

Then is my problem that this sort of thing doesn’t work if I’m using account rather than name? Also, I can’t define how many iterations there are because users could be connected to any number of printers.

I just made a few dummy keys that are the only ones that meet the criteria of my Applescript, that way I don’t have to worry about changing all my real keys.

Perhaps the problem is that I’m trying to make the criteria for “account” and the key name lists only work for “name”? Or is there something else that isn’t going right?

You might try the description property. On my machine several types show up and in your case, printer might be one of them. Then you could search on Internet keys with that description. Another that might work is “server”.

Why don’t you find one of your keys in an AppleScript and then look at its properties?

I had a look at the printer keys and it turns out that they are using a special description called “Network Password”. I’m a bit wary about using “description” for that because I imagine “Network Password” might be used by other things that I wouldn’t want to change. Still, I gave it a try by making my dummy keys “Network Password” and using the “description” criteria in my original script. I came across the same problem: it works, but only changes the password for one key, then stops. If I run it again, it changes the password for the next key.

What really confuses me is why my script switches which key it changes each time I run it. If it was a problem of only being able to access one key, then wouldn’t it always pick the same key each time (i.e. the first one it can find)?

I didn’t have any luck trying it with the other scripts suggested either. Using “description” had the same results as using “account”.

EDIT: Interestingly, I found a way to change two keys at once. It’s not pretty, but it works:

tell application "Keychain Scripting"
tell current keychain
tell (some key whose account is "DOMAIN\\username")
set password to "abc123"
end tell
tell (some key whose account is "DOMAIN\\username")
set password to "abc123"
end tell
end tell
end tell

This changes them both. I’m glad to see there isn’t some sort of limitation to Keychain Access that prevents multiple passwords from being changed. I’d appreciate if anyone knows a more elegant way to do this, as I’m having trouble getting repeat stuff to work.

You’ll have to iterate through them – you can’t collectively change them. Lets get down to basics here. If you were doing this by hand, how would you know which key in a keychain belonged to a printer? How do you know what to change? Is “Domain\Username” always the same?

Yes, DOMAIN\Username is always the same for the printers. That’s why I was trying to batch change based on “account” since it’s always going to be DOMAIN\Username. Sorry that I hadn’t made that clear in the first place.

As you can see from the code example, all I did was tell “some key” with the account criteria to change it’s password. I told it to do this twice and, for some reason, it chose the first key the first time I told it to look for “some key” and the second time it chose the second key for “some key”.

I suppose one way I could solve the problem is to just have it tell “some key” to change the password twenty times or so, but again, I’d really like to have a better way to do it. I tried some things with getting repeats to work, but I had the same trouble I described earlier. When I try to repeat the “tell” instruction for a certain number of times, it either only does it once or gives me an error. I’m starting to wonder if there’s some sort of safeguard in Keychain Access that prevents a single instruction from changing the password for multiple keys. For example:


tell application "Keychain Scripting"
tell current keychain
tell (every key whose account is "DOMAIN\\username")
return password
end tell
end tell
end tell

This works. It returns the password for every key (Keychain Access asks for permission for the script to get them first).


tell application "Keychain Scripting"
tell current keychain
tell (every key whose account is "DOMAIN\\username")
set password to "abc123"
end tell
end tell
end tell

The only difference is that I told it to set the password for every key to abc123. This doesn’t work and I get the error "Keychain Scripting got an error: Can’t set password of every Internet key of current keychain whose account = “DOMAIN\username” to “abc123”. Since it works for return but not for set, maybe there is some sort of safeguard?

Gotcha – I thought you were just hiding what they were. How about this:


tell application "Keychain Scripting"
	tell current keychain
		set everyKey to (every key whose account is "DOMAIN\\username")
		repeat with oneKey in everyKey
			tell oneKey to set password to "abc123"
		end repeat
	end tell
end tell

Actually, the user would have something besides DOMAIN\username (specifically, the real domain and their real username) but for privacy and simplicity, I just substituted that in for this. For testing, I’m just using that.

Well, unfortunately, the script you wrote in the last post did the same thing that my scripts did. They changed the password for only one key and, if run again, it would only change it for the other key. For some reason, I hadn’t thought to look at the Event Log until now. Here’s what the event log said for your script:

The kicker is that the event log says it’s working right and that it’s changing both keys. However, when I check the keys in Keychain Access, only one of the keys is actually changed.

After experimenting with a few dummy keys of my own, it appears that my surmise was correct: changing a property of a key does change its index in the keychain (but not, of couse, in the AppleScript list through which the script is iterating). It’s moved to the end of the keys of its particular class (eg. to the end of the generic keys or to the end of the Internet keys) and the other keys of that class are renumbered accordingly. One way to cope with this situation is to iterate through the list backwards:

tell application "Keychain Scripting"
	launch
	tell current keychain
		set matches to keys whose account is "DOMAIN\\username"
		repeat with i from (count matches) to 1 by -1
			set password of item i of matches to "abc123"
		end repeat
	end tell
end tell

Clever, Nigel – I didn’t actually run tests as I said earlier and they were clearly needed!

Nigel’s script works like a charm! Thank you both very much for helping me to figure out how to get a script to do this.