Creating Lists of Disks

I’m trying to get a list of every disk connected to a computer, EXCLUDING the boot disk, and excluding network volumes.

I can do this:

**tell** *application* "System Events"
**set** DriveList **to** **the** name **of** **every** *disk*
**end** **tell**

But how can I determine which volumes are which KINDs of volumes.
I’m trying to dig deeper but I’m just getting further and further away from what I’m looking for.
If I do “set DriveList to the alias of every disk”, I get… what appears to be a list of paths to every item at the root level of every disk on the system.

If I can’t easily exclude network volumes, I at least have to exclude the computer’s boot disk from this list.

I was able to get a little bit closer just now by doing this:

**tell** *application* "Finder"
**set** VolumeFolder **to** *POSIX file* "/Volumes" **as** *alias*
**set** DriveList **to** name **of** **every** *item* **of** VolumeFolder **whose** kind **is** **not** "Alias"
**end** **tell**

That at least excludes the startup disk.
Is this as close as I’m going to get?
Is there a better overall approach to this?
This script is going to let the user pick a disk, and then its going to be creating files and folders, reading and writing to and from the chosen disk.

Also this forum software is terrible.

Regarding formatting… just copy your script from script editor. In the post, type three backticks alone on a line, go to the next line and paste your code, then on the next line, three more backticks. It should look something like this:

```
code
```

Regarding disks… a disk has finder properties which you can look up in the dictionary. Look them up for each type of disk that you have and see what you can use to isolate them.

tell application "Finder"
	
	set stp to startup disk
	properties of stp
	(*
	{name:"machd", index:3, displayed name:"machd", name ¬
	extension:"", extension hidden:false, container:computer ¬
	container, disk:startup disk, position:{-1, -1}, desktop ¬
	position:{1329, 63}, bounds:{-33, -33, 31, 31}, kind:"Volume", ¬
	label index:0, locked:false, description:missing value, comment:"", ¬
	size:4.8218025984E+11, physical size:4.8218025984E+11, ¬
	creation date:date "Tuesday, December 23, 2014 at 11:40 AM", ¬
	modification date:date "Friday, September 30, 2022 at 1:48 PM", ¬
	icon:missing value, URL:"file:///", owner:"system", group:"root", ¬
	owner privileges:read write, group privileges:read only, everyones ¬
	privileges:read only, container window:container window of startup ¬
	disk, id:-100, capacity:4.99055067136E+11, free space:¬
	2.1631597649E+10, ejectable:false, startup:true, format:Mac OS ¬
	Extended format, journaling enabled:true, local volume:true, ignore ¬
	privileges:false}
	*)
	
	-- Here is an example
	disks whose startup is false and local volume is true
	
end tell

Another property that you might filter on could be ejectable. I can’t test for it but probably URL as well.

Alternatively, System Events can also work with disks and it has a posix path property.

So getting properties of a disk, seems to only work in the script editor but not in an actual applescript application? What do you make of that?

Try this…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

getDrives()

on getDrives()
	local tid, disktid, USB_Drives_ext, tmp, ans, anItem, diskName, tmp
	set disktid to "/dev/disk"
	set USB_Drives_ext to {}
	set tid to text item delimiters
	set ans to do shell script "diskutil list physical"
	set text item delimiters to disktid
	set ans to text items of ans
	if (count ans) > 1 then
		set ans to rest of (text items of ans)
	else
		return {}
	end if
	repeat with anItem in ans
		set tmp to paragraphs of anItem
		repeat while (item -1 of tmp) = ""
			set tmp to items 1 thru -2 of tmp
		end repeat
		set text item delimiters to {" (external, physical):", " (internal, physical):"}
		set diskName to trimWhitespace(text 34 thru 57 of (item -1 of tmp))
		set contents of anItem to disktid & text item 1 of anItem
		set tmp to do shell script "diskutil info " & contents of anItem
		set text item delimiters to {"Device / Media Name: ", "Protocol: ", "Disk Size: "}
		set tmp to text items of tmp
		--if (word 1 of item 3 of tmp) = "USB" then
		set text item delimiters to space
		set end of USB_Drives_ext to {contents of anItem, trimWhitespace(paragraph 1 of item 2 of tmp), (words 1 thru 2 of item 4 of tmp) as text, diskName, word 1 of item 3 of tmp}
		--end if
	end repeat
	set text item delimiters to tid
	return USB_Drives_ext
end getDrives

on trimWhitespace(aString)
	local s, e, ls, ws
	set ws to "  " & tab & linefeed & return
	set ls to length of aString
	set e to ls
	set s to 1
	repeat while s ≤ ls
		if text s of aString is not in ws then exit repeat
		set s to s + 1
	end repeat
	repeat while e ≥ s
		if text e of aString is not in ws then exit repeat
		set e to e - 1
	end repeat
	if e - s < 0 then
		return ""
	else
		return text s thru e of aString
	end if
end trimWhitespace

Ok so back tracking a little bit. I tried a variation on Mockman’s suggestion and came up with this:

name of every disk where startup is false and ejectable is false and local volume is true

I like the simplicity of this, and it is showing me everything I want, EXCEPT that it shows me hidden unix subsystem volumes too. is there an easy way to exclude those? I’m not seeing a “visibility” property?

Post some examples and their properties.

I can only go by what I have on my non-networked system but consider for “home” and “net”:

  • size:0
  • physical size:0
  • creation date:date “Sunday, December 31, 2000 at 7:00 PM”
  • owner privileges:read only
  • id:-101, id:-102
  • capacity:0
  • format:unknown format

All of these properties differ from those of the startup disk.

The startup disk has an ID of -100. I’m guessing that any subsequent disks will increment by -1. If so…

disks whose id is less than -102

And if for some reason, absolutely nothing else works…

tell application "Finder"
	set ignoreList to {"home", "net"}
	disks whose name is not in ignoreList
end tell

Of course, you can add startup disk to the list, but you might get a -1700 error so maybe exclude that separately.

I was going to do an ignore list at first, but after running on differnet machines, I’m seeing different volumes on them. “home”, “net”, “vm”, “update”, “preboot”.

Here are the full properties of “vm” on one particular machine. Nothing about visibility. Also the ID filter you suggest doesn’t appear to work. The numbers seem random-ish but there doesn’t seem to be a hard logic of the numbers of invisible unix volumes vs visible user-accessible volumes.

{
	class:disk,
	name:"vm",
	index:9,
	displayed name:"VM",
	name extension:"",
	extension hidden:false,
	container:computer container of application "Finder",
	disk:disk "vm" of application "Finder",
	position:{-1, -1},
	desktop position:{-1, -1},
	bounds:{-33, -33, 31, 31},
	kind:"Volume",
	label index:0,
	locked:false,
	description:missing value,
	comment:"",
	size:8.589963264E+9,
	physical size:8.589963264E+9,
	creation date:date "Monday, January 3, 2022 at 12:54:15 PM",
	modification date:date "Wednesday, December 17, 2025 at 8:22:37 PM",
	icon:missing value,
	URL:"file:///private/var/vm/",
	owner:"system",
	group:"root",
	owner privileges:read write,
	group privileges:read only,
	everyones privileges:read only,
	container window:container window of disk "vm" of application "Finder",
	id:-103,
	capacity:1.50134214656E+11,
	free space:1.09579644928E+11,
	ejectable:false,
	startup:false,
	format:APFS format,
	journaling enabled:true,
	local volume:true,
	ignore privileges:false
}

Interesting. You obviously have a more complex environment. On my standalone mac (Sierra):

  • startup disk is -100

After that, the disks count by -1

  • home, net are -101, -102
  • -103 and -104 don’t exist
  • a dmg I opened is -105

So, I interpret that as the OS integral disks/volumes get the IDs immediately below -100 (occurring during boot) and then regular (eg network attached, other drives, usb attached, dmg) are assigned IDs as they are mounted.

However, with multiple systems, they could have different situations (eg OS version, connected devices).

What do you get when you run this:

tell application "Finder" to URL of disks
--> {"file:///", "file:///home/", "file:///net/", "file:///Volumes/Rakudo/"}

Maybe you can use some variation of url begins with "file:///Volumes/" as an isolator.

Also, it should be possible to have a superset of volumes that would be applicable to all of the computers but didn’t contain any false positives.


Update

NB I should add that if you use system events rather than finder, there is a visible property to use. The finder’s local becomes local volume under system events though.

tell application "System Events"
	-- startup of startup disk
	-- visible of startup disk
	-- local volume of startup disk
	
	name of disks whose startup is false and visible is true and local volume is true
end tell

Yes! That actually seems to work perfectly!
name of every disk where startup is false and local volume is true and URL begins with "file:///Volumes/"
That might be a winner. I’ll have to do a little more testing but it’s looking good.

You can use NSVolumeEnumerationSkipHiddenVolumes in AppleScriptObjC.
This snippet will return a sorted list of visible volume names:

use framework "Foundation"
use scripting additions

set theFileManager to current application's NSFileManager's defaultManager()
set theVolumes to theFileManager's mountedVolumeURLsIncludingResourceValuesForKeys:{} options:2 -- NSVolumeEnumerationSkipHiddenVolumes
set theVolumes to (theVolumes's valueForKey:"lastPathComponent")'s sortedArrayUsingSelector:"localizedCaseInsensitiveCompare:"
return rest of (theVolumes as list)

The same to get paths instead of names:

use framework "Foundation"
use scripting additions

set theFileManager to current application's NSFileManager's defaultManager()
set theVolumes to theFileManager's mountedVolumeURLsIncludingResourceValuesForKeys:{} options:2 -- NSVolumeEnumerationSkipHiddenVolumes
set theVolumes to (theVolumes's valueForKeyPath:"path")'s sortedArrayUsingSelector:"localizedCaseInsensitiveCompare:"
return rest of (theVolumes as list)