Wait for a Volume to Mount or Unmount/Eject in AppleScript

In working with Alfred, I've created a workflow that loads files from a Volume (DMG) file. In order for this to work correctly, I need the script to wait until the volume is actually loaded and visible in Finder before continuing.

This can be done a few different ways, but here is the AppleScript code I'm using which works with Alfred or Keyboard Maestro. It's based on several examples I found.

The first script gets the name of the mounted volumes and keeps looping until the expected volume shows up in the list.

The second script is the opposite. It keeps looping and trying to eject the disk until the name isn't in the list of mounted volumes.

Wait for Volume to be Mounted

set mountedDisk1 to list disks
set thevolume1 to "Insert Volume Name Here"
set wasmounted to false
set counter to 0
set max_number_of_iteration to 30

--use activate to bring dialog to front
if mountedDisk1 contains thevolume1 then
    set wasmounted to true
end if

if wasmounted is false then
    delay 1
    tell application "Finder"
        if (not (exists (disk thevolume1))) then
            repeat until (mountedDisk1 contains thevolume1 or counter is greater than max_number_of_iteration)
            set mountedDisk1 to list disks
            if mountedDisk1 contains thevolume1 then
            end if
            delay 1
            set counter to counter + 1
            end repeat
        end if
    end tell
end if

Wait for Volume to be Unmounted/Ejected

set mountedDisk1 to list disks
set thevolume1 to "Insert Volume Name Here"
set wasmounted to false
set counter to 0
set max_number_of_iteration to 30

--use activate to bring dialog to front
if mountedDisk1 contains thevolume1 then
    set wasmounted to true
end if

if wasmounted is true then
    delay 1
    tell application "Finder"
    eject disk thevolume1
        if ((exists (disk thevolume1))) then
            repeat until (mountedDisk1 does not contain thevolume1 or counter is greater than max_number_of_iteration)
            set mountedDisk1 to list disks
            if mountedDisk1 contains thevolume1 then
                eject disk thevolume1
            end if
            delay 1
            set counter to counter + 1
            end repeat
        end if
    end tell
end if

Adapted from:

Other articles of interest:

It’s all about templates, macros and workflows in 2020

Over this holiday break I have been excitedly playing with Alfred and Keyboard Maestro to the point where I might be wasting time trying to find ways to save time.

In reality, I've created multiple workflows in each application to accomplish some trivial, but still useful tasks.

While looking up some examples for Keyboard Maestro, I followed the demo and set my machine to empty the system trash every Friday night at 10pm. Yes, the system does it, but this is more efficient.

I took that idea and set Keyboard Maestro to empty the trash in DevonThink Office at the same time. Keyboard Maestro can enter keystrokes and press dialog buttons. That's nice!

It even adds the extra option to make sure the system was idle in case I was doing something.

Because I've done it more than once manually, I built a Keyboard Maestro workflow to copy files out of my Dropbox folder to my local system so they could be used by DevonThink.

Again, these are rather trivial tasks, but they are solid learning blocks and they perform useful work. Work that I don't have to worry about.

I took that same idea and applied it to Alfred. I've created several keywords to make consistent work environments. One Alfred workflow for automation starts Katalon, CodeRunner, SnippetsLab, Github Desktop and opens the project in Finder.

It's hardly a chore to start some apps, but it means I don't have to go looking for an app. It's already running. When I need it, it's there, and my flow isn't disrupted.

The same is true for my writing apps. I type a keyword and Scrivener, WordWeb, WordPress, TextSoap and MWeb are all launched. My writing project is loaded and is ready to go. I could even add options to close apps like Messages, Slack and email so my focus doesn't wander.

Again, not difficult, but consistent. And a consistent environment means I can get more done with less distraction.

Another workflow that came up was specifically because I was at home.

While working from home over the holiday break, I needed to share my screen a few times. It's no problem to do so, however, I wanted to shut down multiple apps so notification messages wouldn't pop up. This meant closing Messages, Mail, monitoring tools, Affinity Dashboard, and others.

No one needs to know that a pair of shoes I'm interested in has gone on sale. Nor do they need to see some scammer trying to tell me my iTunes account has been suspended and I need to log in to confirm ownership.

That is a horrible business presentation.

Now, I can use Alfred to close these apps without my need to remember the name of each one. When I'm finished, I restart them all, and restore the state of my machine.

I'm even working on creating shell scripts and triggers that emulate some of the functionality of Hazel. I can move and copy files based on their name or extension. I can have the action triggered by keyword or run on a schedule.

Using these two tools, I'm very quickly creating a set it and forget it mentality.

Just think of what will happen when I actually know what I'm doing!

Other articles of interest:

Improve your writing with TextSoap

While getting ready for 2020, it occurred to me I can use TextSoap’s regex engine to improve my writing by finding and highlighting common and overused words. There are 3 steps to the process:

  • Use the “If Text Matches” action with a list of words I want to highlight
  • Format the foreground and background colors of the text
  • Set problem words to capitals so they stand out

After checking a couple of websites, I created this short list of words to focus on.

\b(and|or|for example|but|just|other|more|new|good|best|many|first|able|basically|interesting|honestly|literally|very|really|quite|seems|had|even|that|seriously|to be honest|ridiculous|know)\b

From there I used the Set Text Color, Set Background Color filters, followed by the Convert to Uppercase action.

When finished, the “cleaner” can run inside Scrivener itself, so I don’t have to leave my main app to get feedback.

It’s a simple formatter, but I think this will have a powerful impact.


Other articles of interest:

Keyboard Maestro makes a last minute appearance on the Party Barge

While researching Alfred, CopyLess and PopClip, I saw many references to Keyboard Maestro, but never quite understood what the app was for. It came across as a text expander, or a clipboard editor, or a keyboard mapper.

So, taking a moment out to pause and reflect, it finally became clear to me. All those functions are a part of Keyboard Maestro. How is that possible?

It makes a little more sense when Keyboard Maestro is presented as an extension or the next version of Automator. It uses a similar style of building blocks to chain actions together to accomplish tasks. At one end you can tie an action to a hotkey, and at the other, actions can be triggered by system events such as switching networks, or a USB drive being inserted.

After downloading a copy, trying it out, watching some videos and assembling some blocks of my own, Keyboard Maestro jumps aboard the Party Barge just as we cast off for 2020.

In reality there is some overlap between Alfred and Keyboard Maestro. They are both development environments for creating shortcuts for repetitive tasks. And in many ways they go about it the same way. However, they both offer distinct tools and functionality.

To give a simple example, in Alfred you can create a workflow to stop and start multiple applications using AppleScript.

In Keyboard Maestro, the same job can be set up as a macro using a series of the “Application Control” actions that list the applications to stop and start. It can also be done using the Execute AppleScript module.

In Alfred:

    tell application "Firefox" to activate
    tell application "Mail" to activate
    tell application "Messages" to activate

In Keyboard Maestro:


Same end results, slightly different way of getting there.

But where Keyboard Maestro comes into it’s own is with system events. You can create actions for when a file is added to a folder, when you login, when the system goes idle, when the system wakes, when an application starts or stops, when text is copied to the clipboard, etc. There are dozens of events you can monitor and take action on.

Additionally, you can build loops, use IF statements, employ variables, set up decision making, and even prompt for input before continuing.

Or if you prefer, you can skip the module building part and use straight scripting in AppleScript, a shell script, Swift, or JavaScript.

I even watched a couple of videos where Keyboard Maestro was used to fill in forms on a Google page.

Once I took a serious look, I saw just how powerful Keyboard Maestro can be. I’ve already built a few simple macros with many more coming. There is a fair bit to learn, but like Alfred, there is a very active community of users and plenty of examples to study.

With their combined powers, very few computer tasks will escape me.

Keyboard Maestro

Other articles of interest:

Big F(U) for BestBuy and their ability to deliver appliances

So, to take a slight detour from my normal writings, I wanted to relate a story about BestBuy and another less than stellar experience I had with them. I don't simply want to shame BestBuy for the catastrophically bad job they did, but to highlight several lessons that can and should have been learned.

The story starts with an appliance delivery. BestBuy had a good deal on a washer and dryer set, so I bought them for Black Friday. As I'm sure many people did.

The problem comes right as they deliver the units. Or rather, when they should have delivered the units because they were a couple of hours late and didn't feel it necessary to inform anyone of that situation. How can you be so poor at time and task management when you only have the one job to do?

Next, we have two misguided fools who I shall call MF1 and MF2. They were given full instructions on where the old washer and dryer were, that they were taking those away for recycling and would be putting the new units in the same place. It was explained that the washer needed to be lifted up and out of the washer pan as it would need to be used again since BestBuy didn't sell those.

Since these two spend their day installing and removing appliances, this should be an easy undertaking, right?

Not so.

MF1 immediately drags the washer out of position. Notice he didn't employ the help of MF2, who was standing around, nor did he lift the washer. This resulted in the pan getting crushed and cracked to the point it can't be used. The drip pan needs to catch water and when you smash off the sides and put holes in it, that's no longer possible.

Mistakes get made all the time, and while this was completely avoidable, it's not the end of the world. But MF1 wasn't in the mood to try and fix the problem he just created, he was more interested in shifting blame. And he shifted blame like a pro.

It wasn't his fault the drip pan was there. It wasn't his fault the washer was still hooked up. It wasn't his fault he didn't have a replacement.

I don't believe the washer being hooked up had anything to do with him pulling the washer rather than lifting it. Additionally, he is the expert, shouldn't he have made sure it wasn't connected before taking action?

Despite MF1 throwing out blame, the fact remained the pan was broken and it would be idiotic to install a washing machine on the second floor without a drip pan. Since Lowe's is right down the road, why not just run down there and get one? Or to Home Depot which is a couple miles in the opposite direction?

MF1 saw no merit in this proposal and stated this job had already made him late and he had no time or authority to get a drip pan. I would need to take care of that and put it under the washer at a later time. He needed to hook up the washer and get on with his day.

Now, there is no point hooking up the washer when it needs to be unhooked in order to put a drip pan underneath it. MF1 replied that wasn't his problem, he didn't have the pan, wasn't in a position to buy one, and I could ask BestBuy for reimbursement.

That's not the way this works, Jackass.

MF1 was told that since he smashed the original drip pan, it was his responsibility to replace it before the washer was put in place. Either he needed to go and get one, call and have someone else bring it over, or this job was going no further.

He supposedly called his supervisor and returned with "there's nothing we can do."

Oh yes there is.

He was then told to take the appliances back, put them on the truck, put the original appliances back where the found them and cancel the entire order. Plus, I would be calling BestBuy to pay for the damages he caused.

"You don't want the appliances?" was his stunned reply.

"Oh no. I absolutely want the appliances. But they need to be installed correctly, which means a drip pan. So without one, they aren't getting installed. If they aren't getting installed today, cancel the order and I will get the appliances from someone else."

This led to MF1 to pull out the paperwork, incorrectly log what had taken place, that the appliances were being refused for an entirely different reason, basically that I had changed my mind, and that the order was to be cancelled.

I added several hand written changes, as well as a couple of vulgarities, and MF1 and 2 were tossed out of the house, taking the appliances with them and costing BestBuy well over $1500 in purchases, time and labor.

What can we learn from this situation?

First and foremost, failure IS an option and in this case, MF1 made the choice to fail. Instead of thinking twice and acting one, he acts like a buffoon and breaks one of the most important pieces to the operation.

Second, instead of owning up to the error, he throws blame around like it's candy. Everyone else caused him to make this mistake. It wasn't his fault, he's the victim.

Third, instead of fixing the problem, it becomes someone else's problem. He's too busy, too far behind schedule, and not in a position to fix what he has broken. He needs to finish what he's doing here and move on, even though he is doing the job incorrectly.

Finally, a small mistake can cost thousands of dollars. This small error resulted in the entire order being cancelled, and my less than complimentary phone call to BestBuy later that night to confirm it was indeed cancelled, refute the lies included in the explanation MF1 provided, and get a reimbursement for damaged goods.

When you start a call with, "I don't want to ruin your night, so please get your supervisor for me and tell them I'm going to start yelling," it takes on a certain tone.

To be blunt, none of this should have happened. Had MF1 thought about what he was doing and considered his actions, the pan never would have been broken, the appliances would have been installed and everyone would have been happy.

There were multiple points along the way where failure could have been avoided. Many red flags were thrown. But MF1 forged ahead, using the same methods of thinking and the same actions that caused the situation in the first place.

When you find yourself in a hole, stop digging.

Other articles of interest:

Recent Comments

  • Working with Dates and Date Formatting in Katalon Studio (15)
    • Sangeethaa: How to get previous day’s date(Yesterday’s date)? Actually I was using today.previous() before,it was working fine till today morning.Now its not retrieving right date. Can anyone please guide me on this.
    • Don Pedro: That could be a little tricky. First, is the text/format always going to be the same? You will need to do some parsing. Separate the first but of text at 2019. After that, split the text again to get rid of Central Standard...
    • Don Pedro: It should be of the same Date type as today. You could then do some calendar trickery with Calendar /*Calendar c = Calendar.getInstance(); //c.set(Calendar.MONTH, 1) //Set the month, 0=January, 11=December println...
    • josh: I’m testing a page with a string like “Updated November 21, 2019 16:25:32 PM Central Standard Time.” How might I capture the date and time and compare it to current time to verify that the update time was within...
    • zakir hussain: today = new Date() lastWeek = (today – 1.week) can u please help me in understanding what is the return type of lastweek? and I wanted to set nextyear date how can i do it
    • ALLAN FORD: Useful !
    • Don Pedro: Not sure I understand what you are trying to do.
  • Output status messages and test information by writing to the Log File Viewer in Katalon Studio (6)
    • Saranya: Good One. Could you plz share link to access all your katalon related blogs. ThankQ
    • Rodrigo Calabretta: I’m using the KeywordUtil.markFailed or KeywordUtil.markError and my test stops is being shown as Error and If I use in the @afterTestCase the testCaseContext.getTestCaseSta tus() to show the status test case...
  • Setting up Environment Profiles in Katalon Studio (2)
    • Don Pedro: Not quite sure I understand. The term “Execution Profile” is normally used now, but they are still GlobalVariables and are created in the same way for version 7 as previous. You make a new execution profile, then...
    • Aparna: Hello, Your documentation is excellent and has helped me understand many things. But this article above seems outdated and I need help in creating my own Global variables and all the documentation out there seems to be point to...
  • Here is my drive cluster (2)
    • Don Pedro: While I still have those drives, the drive cluster looks nothing like that now. Almost all of my external drives have had the cases removed and they have been installed into a series of MediaSonic 8 Bay Drive Enclosures. I...
    • Marin Boucher: Hi! Verry funny blog with “go to the point” on many post! I spent good time reading some of your post. Regarding this one about NAS, “many NAS” in fact, I would be curious to see a screenshot of...
  • How To Disable the Quicken Registration Prompt (27)
    • debra: didn’t work for me… my 2007 – which I am keeping on my older mac.
  • Adding entries to an open Excel spreadsheet during runtime (1)
    • IanG: Hi: Seems like nobody else has described (in detail) how Katalon can be configured to test an API by reading the first entry from a multi-row multi column XLSX spreadsheet, executing a test, writing the result to another column (or...