Detecting if a script is first run

I’m looking for a way to more gracefully handle the permission dialogs in Mojave/Catalina. Given that those dialogs happen upon the first run of the script, is there a way for my script to know that it is first run?

I’m wanting to have a firstRun() subroutine to initialize a few things, specifically to have each app being called out in the larger script to have some task in the firstRun(), so that all of the permission dialogs trigger immediately, instead of scattered through various runs of the script in the future.

Is there an official way to determine if it has been run?

Unless I am missing something, this is usually done by storing a folder or file at a known (to you) location.

Then when the script is run, it checks for this folder. If it is not there (on error) then

  1. Do all the things you wanted to do in your setup routine
  2. Create and store the folder indicating first run has happened

If it IS there, just return.
Of course, this is not perfect, because the user could kill your script between setting the folder and performing the tasks. Thus ideally this whole thing should be atomic - namely either it all gets done or none of it gets done.
I am not aware of a way in pure AppleScript to do this. But I know in “real” programming there are ways to “test and set” so as to do an atomic operation.

I am a complete amateur and beginner, but one method that I’ve used (it’s not “official” in any way) is to do something like this:

set firstRun to true
do shell script "defaults read org.myorg.myapp FirstRun"
on error
set firstRun to false
end try

Then, after you’ve done the tasks you want to perform on the first run, use

do shell script "defaults write org.myorg.myapp FirstRun true"

I’m writing this from memory, without looking at my actual code, and if this doesn’t actually work you can easily work out something similar.

Again, this is pure amateurism on my part, but I wrote it because I hadn’t seen anything else.

Whatever method you choose, it might be more useful to store a version number rather than a yes/no value, so you can re-check when you update the app.

If your app isn’t code-signed and doesn’t use AppleScriptObjC, you can probably use a simple property. Otherwise my PrefsStorageLib is an option:

use script "PrefsStorageLib" version "1.0.0"
use scripting additions

prepare storage for (path to me) default values {lastVersionRun:"0"}
set lastVersionRun to value for key "lastVersionRun"
considering numeric strings
	if (value for key "lastVersionRun") as text < my version then
		--first run
		assign value my version to key "lastVersionRun"
	end if
end considering

Thanks for the replies. I’ve done something similar to these in the past - my main script has a packager script that creates a firstRun file within the script bundle when I create a final version of a build, that is deleted after the initial setup() routine that runs if that file is there when the script is run by the user. That process requires a separate script though, that I don’t have for smaller scripts.

I had wondered if there was a way to patch in to whatever OSX uses to know to check in the first place, but I should know by now that is asking for too much.

All of these suggestions are great, and broke me of the one angle I was looking at this, so I appreciate it!

Shane, I really do like the approach of using the version number, though. That allows the setup() code to run for each new version, as I do now. It would also allow the various permission triggers to fire off only on the first run of each version, if I choose not to code sign.

For that matter, is all of this even necessary? I am using the following code at the beginning of the script to trigger security dialogs all at once:

	tell application "Finder" to count windows
	tell application "System Events" to count windows
	tell application "Safari" to count windows
	-- etc

Is there any significant runtime consequence in doing that EVERY time the script is run? If not I can just forego the whole firstRun construct and count windows even when it is not necessary. Or for that matter, would counting windows be faster than looking for the defaults info? Am I gaining anything by trying to only count windows on the first run?

It’s generally not a good idea to alter the bundle of an application if you can avoid it.

There is if you have a large number of windows :grinning:. But if the scripts doing a lot of work otherwise, it’s a cheap-and-simple solution.