Getting names and serial numbers from USB devices

I’m just running this in OS X Yosemite, but it skips the serial number.
How can I get this working please?

Thanks

Matt

Hi,

I am running this in macOS Sierra.

Getting Error: “The variable serial_num is not defined.”
Same as post above (I think), has this ever been resolved?

Someone, anyone please help.
Cheers

The script appears to have four main problems:

  1. It only pretends to get the serial numbers and mount points of attached USB drives, whereas the OP asked for the serial numbers and names of devices.
  2. It assumes there’s only one volume/mount point per drive.
  3. The cue used to start parsing the text lines for the drives currently comes after the serial numbers (where they exist), so the handler never finds those lines.
  4. It looks as if the scripter thinks that changing the value of i in the run handler repeat has some influence on the repeat index.

Parsing the System Profiler text isn’t currently as simple as it appears to have been back in 2009. :confused:

Nigel, I have worked on something similar…
Check it out at: http://macscripter.net/viewtopic.php?id=45403 and see if you could help me out.
Thanks in advance

Try :

set USB_Drives to {}
set USB to paragraphs of (do shell script "system_profiler SPUSBDataType -detailLevel basic")
set i to 0
set iMax to count USB
repeat
	set i to i + 1
	if i > iMax then exit repeat
	--if item i of USB contains "Removable Media: Yes" then
	if item i of USB contains "Product ID:" then
		set {maybe, i} to process_usb_device(i, USB)
		if class of maybe is list then set end of USB_Drives to maybe
	end if
end repeat
USB_Drives
on process_usb_device(i, USB)
	set current_item to item i of USB
	set serial_num to "?" # default value
	set mount_point to "?" # default value
	set isRemovable to false
	repeat --until current_item = ""
		set i to i + 1
		if i > (count USB) then exit repeat
		set current_item to item i of USB
		log current_item
		if current_item contains "Serial Number:" then
			set serial_num to text ((offset of ": " in current_item) + 2) through -1 of current_item
		else if current_item contains "Removable Media: Yes" then
			set isRemovable to true
		else if current_item contains "Mount Point:" then
			set mount_point to text ((offset of ": " in current_item) + 2) through -1 of current_item
			exit repeat
		end if
	end repeat
	if isRemovable then
		return {{serial_num, mount_point}, i}
	else
		return {false, i}
	end if
end process_usb_device

One of the problems was that as designed, the original code failed to define the variables serial_num or mount_point.
In my case,it’s serial_num which wasn’t defined.

Here is a part of the contents of the variable USB:
[format]
Patriot Memory:

          Product ID: 0x3100
          Vendor ID: 0x13fe  (Phison Electronics Corp.)
          Version: 1.10
          Serial Number: 07981808B2F1361F
          Speed: Up to 480 Mb/sec
          Manufacturer:         
          Location ID: 0xfa130000 / 5
          Current Available (mA): 500
          Current Required (mA): 300
          Extra Operating Current (mA): 0
          Media:
            Patriot Memory:
              Capacity: 8,01 GB (8 011 120 640 bytes)
              Removable Media: Yes
              BSD Name: disk2
              Logical Unit: 0
              Partition Map Type: GPT (GUID Partition Table)
              USB Interface: 0
              Volumes:
                EFI:
                  Capacity: 209,7 MB (209 715 200 bytes)
                  BSD Name: disk2s1
                  Content: EFI
                  Volume UUID: 0E239BC6-F960-3107-89CF-1C97F78BB46B
                Yosemite Install Disk - 10.10.4:
                  Capacity: 7,67 GB (7 667 146 752 bytes)
                  Available: 582,6 MB (582 569 984 bytes)
                  Writable: Yes
                  File System: HFS+
                  BSD Name: disk2s2
                  Mount Point: /Volumes/Yosemite Install Disk - 10.10.4
                  Content: Apple_HFS
                  Volume UUID: 72B11AB5-2D53-3564-A5CF-683019424F49

[/format]
As you may see, the first occurrence of the string “Removable Media: Yes” is 11 lines after the one containing the device’s Serial Number so the handler was unable to see it.

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) dimanche 18 décembre 2016 13:29:24

That’s a bit of an understatement :slight_smile: Even parsing it as a property list is laborious. But this works here, at least:

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

set USB to do shell script "system_profiler -xml SPUSBDataType"
set aString to current application's NSString's stringWithString:USB
set theData to aString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
set {theThing, theError} to current application's NSPropertyListSerialization's propertyListWithData:theData options:0 |format|:(missing value) |error|:(reference)
set theItems to (theThing's firstObject()'s valueForKeyPath:"_items")'s firstObject()'s valueForKeyPath:"_items._items"
set theInfo to {}
repeat with anItem in theItems
	if (anItem's isKindOfClass:(current application's NSArray)) then
		repeat with subItem in anItem
			set sn to (subItem's valueForKey:"serial_num")
			if (sn is not missing value) then
				set theMedia to (subItem's valueForKey:"Media")
				if (theMedia is not missing value) then
					repeat with aMedium in theMedia
						if aMedium is not missing value and (aMedium's valueForKey:"removable_media") as text = "yes" then
							set theVolumes to (aMedium's valueForKey:"volumes")
							repeat with aVolume in theVolumes
								set end of theInfo to {mountPoint:((aVolume's valueForKey:"mount_point") as text), serialNo:(sn as text)}
							end repeat
						end if
						
					end repeat
				end if
			end if
		end repeat
	end if
end repeat
return theInfo

I’m puzzled by your code Shane.

With a single USB device connected, it returns a list of two lists :
[format]{{mountPoint:“missing value”, serialNo:“07981808B2F1361F”}, {mountPoint:“/Volumes/Yosemite Install Disk - 10.10.4”, serialNo:“07981808B2F1361F”}}[/format]

As you may see,the same device is returned twice:
1 - with no mountPoint
2 - with its true mountPoint

My understanding is that a complementary test upon mountPoint is required.

repeat with aMedium in theMedia
	if aMedium is not missing value and (aMedium's valueForKey:"removable_media") as text = "yes" then
		set theVolumes to (aMedium's valueForKey:"volumes")
		repeat with aVolume in theVolumes
			set maybe to (aVolume's valueForKey:"mount_point")
			if maybe is not missing value then
				set end of theInfo to {mountPoint:maybe as text, serialNo:(sn as text)}
			end if
		end repeat
	end if
end repeat

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) dimanche 18 décembre 2016 14:50:25

In a nod to the original question in this thread, this returns (on my mid-2009 MBP running El Capitan) a list of records containing the name, serial number (where available) and mount points (where appropriate) of connected USB devices. To keep the result simple, the structure doesn’t include the buses, but it could if desired:

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

set USB to (do shell script "system_profiler -xml SPUSBDataType" without altering line endings)
-- set USB to (read (choose file) as «class utf8») -- For testing with Yvan's XML results.

set aString to current application's class "NSString"'s stringWithString:(USB)
set theData to aString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
set {theThing, theError} to current application's class "NSPropertyListSerialization"'s propertyListWithData:(theData) options:(0) |format|:(missing value) |error|:(reference)
set deviceDetails to current application's class "NSMutableArray"'s new()
parseRecursively(theThing's firstObject(), deviceDetails)
return deviceDetails as list

on parseRecursively(thisThing, deviceDetails)
	set subthings to thisThing's valueForKey:("_items")
	repeat with thisSubthing in subthings
		if (thisSubthing's allKeys()'s containsObject:("_items")) then
			parseRecursively(thisSubthing, deviceDetails)
		else
			-- In El Capitan, 'volumes', if it exists, is a direct property of a device. In Sierra, it's apparently a property of individual 'media' which a device may have.
			if (thisSubthing's allKeys()'s containsObject:("Media")) then -- Sierra.
				set theMedia to (thisSubthing's valueForKey:("Media"))
				set mediaDetails to current application's class "NSMutableArray"'s new()
				repeat with thisMedium in theMedia
					set theseDetails to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisMedium's valueForKey:("_name"), thisMedium's valueForKeyPath:("volumes.mount_point")}) forKeys:({"name", "mount points"}))
					tell mediaDetails to addObject:(theseDetails)
				end repeat
				set thisEntry to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisSubthing's valueForKey:("_name"), thisSubthing's valueForKey:("serial_num"), mediaDetails}) forKeys:({"name", "serial number", "media"}))
			else -- El Capitan.
				set mountPoints to (thisSubthing's valueForKeyPath:("volumes.mount_point")) -- List of mount points.
				set thisEntry to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisSubthing's valueForKey:("_name"), thisSubthing's valueForKey:("serial_num"), mountPoints}) forKeys:({"name", "serial number", "mount points"}))
			end if
			tell deviceDetails to addObject:(thisEntry)
		end if
	end repeat
end parseRecursively

Edits:
1. Script replaced with a recursive version which burrows down through the “_items” of any objects which have them. This should remove the previous assumption about the hierarchy depth.
2. Another revision based on a couple of XML inputs which Yvan helpfully sent me. In his El Capitan XML, the ‘volumes’ are direct properties of the devices. In Sierra, they’re properties of individual ‘Media’ possessed by the devices.

Hello Nigel

It seems that something is wrong in your code.

Here it return:

{{|name|:"FaceTime HD Camera (Built-in)", |serial number|:"CC2B26051GDGGDFP", |mount points|:missing value}, {|name|:"hub_device", |serial number|:missing value, |mount points|:missing value}, {|name|:"hub_device", |serial number|:missing value, |mount points|:missing value}}

The original Shane’s script return :

{{mountPoint:"missing value", serialNo:"07981808B2F1361F"}, {mountPoint:"/Volumes/Yosemite Install Disk - 10.10.4", serialNo:"07981808B2F1361F"}}

The edited one return :

{{mountPoint:"/Volumes/Yosemite Install Disk - 10.10.4", serialNo:"07981808B2F1361F"}}

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) dimanche 18 décembre 2016 19:34:23

Hi Yvan.

No. The code works perfectly on my machine, whereas Shane’s ” even with your modification ” only returns an empty list. It’s more likely to be a change in system_profiler’s report structure between between El Capitan and Sierra. Or perhaps there’s something in the architecture of the machines which causes the structures to be different.

I suspect it relates to how the device is formatted.

I wouldn’t be surprised if the structure were highly version-dependent.

The connected key are journalized HFS : they were prepared to install OS X
The system used to run the script is Sierra 10.12.2

Nigel’s script :

{{|name|:"FaceTime HD Camera (Built-in)", |serial number|:"CC2B26051GDGGDFP", |mount points|:missing value}, {|name|:"hub_device", |serial number|:missing value, |mount points|:missing value}, {|name|:"hub_device", |serial number|:missing value, |mount points|:missing value}}

Original Shane’s one:

{{mountPoint:"missing value", serialNo:"07981808B2F1361F"}, {mountPoint:"/Volumes/Yosemite Install Disk - 10.10.4", serialNo:"07981808B2F1361F"}}

Modified Shane’s one:

{{ {mountPoint:"/Volumes/Yosemite Install Disk - 10.10.4", serialNo:"07981808B2F1361F"}}

script from message # 21

{{"07981808B2F1361F", "/Volumes/Yosemite Install Disk - 10.10.4"}, {"442A60CDF2EE", "/Volumes/Transcend"}}

Here is the flow of data returned from System Profiler so you may compare with what you get.

    USB 2.0 Bus:

      Host Controller Driver: AppleUSBEHCIPCI
      PCI Device ID: 0x1c2d 
      PCI Revision ID: 0x0005 
      PCI Vendor ID: 0x8086 

        FaceTime HD Camera (Built-in):

          Product ID: 0x850b
          Vendor ID: 0x05ac  (Apple Inc.)
          Version: 7.55
          Serial Number: CC2B26051GDGGDFP
          Speed: Up to 480 Mb/sec
          Manufacturer: Apple Inc.
          Location ID: 0xfa200000 / 2
          Current Available (mA): 500
          Current Required (mA): 500
          Extra Operating Current (mA): 0
          Built-In: Yes

        Hub:

          Product ID: 0x2514
          Vendor ID: 0x0424  (SMSC)
          Version: 0.03
          Speed: Up to 480 Mb/sec
          Location ID: 0xfa100000 / 1
          Current Available (mA): 500
          Current Required (mA): 2
          Extra Operating Current (mA): 0
          Built-In: Yes

            Patriot Memory:

              Product ID: 0x3100
              Vendor ID: 0x13fe  (Phison Electronics Corp.)
              Version: 1.10
              Serial Number: 07981808B2F1361F
              Speed: Up to 480 Mb/sec
              Manufacturer:         
              Location ID: 0xfa130000 / 5
              Current Available (mA): 500
              Current Required (mA): 300
              Extra Operating Current (mA): 0
              Media:
                Patriot Memory:
                  Capacity: 8,01 GB (8 011 120 640 bytes)
                  Removable Media: Yes
                  BSD Name: disk2
                  Logical Unit: 0
                  Partition Map Type: GPT (GUID Partition Table)
                  USB Interface: 0
                  Volumes:
                    EFI:
                      Capacity: 209,7 MB (209 715 200 bytes)
                      BSD Name: disk2s1
                      Content: EFI
                      Volume UUID: 0E239BC6-F960-3107-89CF-1C97F78BB46B
                    Yosemite Install Disk - 10.10.4:
                      Capacity: 7,67 GB (7 667 146 752 bytes)
                      Available: 582,5 MB (582 541 312 bytes)
                      Writable: Yes
                      File System: HFS+
                      BSD Name: disk2s2
                      Mount Point: /Volumes/Yosemite Install Disk - 10.10.4
                      Content: Apple_HFS
                      Volume UUID: 72B11AB5-2D53-3564-A5CF-683019424F49

            Keyboard Hub:

              Product ID: 0x1006
              Vendor ID: 0x05ac  (Apple Inc.)
              Version: 96.15
              Serial Number: 000000000000
              Speed: Up to 480 Mb/sec
              Manufacturer: Apple, Inc.
              Location ID: 0xfa120000 / 4
              Current Available (mA): 500
              Current Required (mA): 300
              Extra Operating Current (mA): 0

                Apple Keyboard:

                  Product ID: 0x0221
                  Vendor ID: 0x05ac  (Apple Inc.)
                  Version: 0.69
                  Speed: Up to 1.5 Mb/sec
                  Manufacturer: Apple, Inc
                  Location ID: 0xfa122000 / 9
                  Current Available (mA): 500
                  Current Required (mA): 20
                  Extra Operating Current (mA): 0

            BRCM2046 Hub:

              Product ID: 0x4500
              Vendor ID: 0x0a5c  (Broadcom Corp.)
              Version: 1.00
              Speed: Up to 12 Mb/sec
              Manufacturer: Apple Inc.
              Location ID: 0xfa110000 / 3
              Current Available (mA): 500
              Current Required (mA): 0
              Extra Operating Current (mA): 0
              Built-In: Yes

                Bluetooth USB Host Controller:

                  Product ID: 0x8215
                  Vendor ID: 0x05ac  (Apple Inc.)
                  Version: 2.08
                  Serial Number: 442A60CDF2EE
                  Speed: Up to 12 Mb/sec
                  Manufacturer: Apple Inc.
                  Location ID: 0xfa111000 / 6
                  Current Available (mA): 500
                  Current Required (mA): 0
                  Extra Operating Current (mA): 0
                  Built-In: Yes

    USB 2.0 Bus:

      Host Controller Driver: AppleUSBEHCIPCI
      PCI Device ID: 0x1c26 
      PCI Revision ID: 0x0005 
      PCI Vendor ID: 0x8086 

        Hub:

          Product ID: 0x2514
          Vendor ID: 0x0424  (SMSC)
          Version: 0.03
          Speed: Up to 480 Mb/sec
          Location ID: 0xfd100000 / 1
          Current Available (mA): 500
          Current Required (mA): 2
          Extra Operating Current (mA): 0
          Built-In: Yes

            Mass Storage Device:

              Product ID: 0x9380
              Vendor ID: 0x058f  (Alcor Micro, Corp.)
              Version: 0.01
              Speed: Up to 480 Mb/sec
              Manufacturer: Alcor Micro
              Location ID: 0xfd140000 / 4
              Current Available (mA): 500
              Current Required (mA): 100
              Extra Operating Current (mA): 0
              Media:
                USB Flash Disk:
                  Capacity: 513,8 MB (513 802 240 bytes)
                  Removable Media: Yes
                  BSD Name: disk3
                  Logical Unit: 0
                  Partition Map Type: GPT (GUID Partition Table)
                  USB Interface: 0
                  Volumes:
                    Transcend:
                      Capacity: 513,8 MB (513 761 280 bytes)
                      Available: 477,4 MB (477 360 128 bytes)
                      Writable: Yes
                      File System: Journaled HFS+
                      BSD Name: disk3s1
                      Mount Point: /Volumes/Transcend
                      Content: Apple_HFS
                      Volume UUID: A3BF7C69-65E7-3910-B569-4334704B34CF

            IR Receiver:

              Product ID: 0x8242
              Vendor ID: 0x05ac  (Apple Inc.)
              Version: 0.16
              Speed: Up to 1.5 Mb/sec
              Manufacturer: Apple Computer, Inc.
              Location ID: 0xfd120000 / 2
              Current Available (mA): 500
              Current Required (mA): 100
              Extra Operating Current (mA): 0
              Built-In: Yes

            Card Reader:

              Product ID: 0x8403
              Vendor ID: 0x05ac  (Apple Inc.)
              Version: 98.33
              Serial Number: 000000009833
              Speed: Up to 480 Mb/sec
              Manufacturer: Apple
              Location ID: 0xfd110000 / 3
              Current Available (mA): 500
              Current Required (mA): 500
              Extra Operating Current (mA): 0
              Built-In: Yes

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) lundi 19 décembre 2016 09:29:16

I’ve just replaced my script in post #24 with a recursive version which goes as deep as necessary instead of assuming a certain hierarchy depth. Is it any more successful in Sierra?

Take a look at my solution in the other thread, too.

Hi Nigel, StefanK (and everyone who’s commenting here),

Thank you for the adjustment in post #24
Check out post number (#3) is this thread http://macscripter.net/viewtopic.php?pid=188321#p188321 - similar post perhaps you could help me out. Read over post #3 and let me know if you have any ideas.

One thing I forgot to mention in that thread was that I am using it as part of an authentication process, the script will always be run off an external USB Stick and I want sell “per-usb” licences (example scenario - not actually making money with this script), so I’m thinking hard coding the serial number of the drive into the script and using a bit of simple AppleScript to grab the mount path of the volume on which the script is located. Then, pass this mount point into some sort of function that will return the serial number of the drive that has this mount point.
Lastly, if that serial number and the serial number which is hard coded match, I can conclude that the USB drive has a legitimate copy of my script running.

I am absolutely lost as to how to pass the mount point into some function that returns the serial number of the drive with that hosts that mount point.

Cheers

@Programmer

Under 10.12.2 the script continue to fail to report some devices. Here it returned :

{{|name|:"FaceTime HD Camera (Built-in)", |serial number|:"CC2B26051GDGGDFP", |mount points|:missing value}, {|name|:"Patriot Memory", |serial number|:"07981808B2F1361F", |mount points|:missing value}, {|name|:"Apple Keyboard", |serial number|:missing value, |mount points|:missing value}, {|name|:"Bluetooth USB Host Controller", |serial number|:"442A60CDF2EE", |mount points|:missing value}, {|name|:"Mass Storage Device", |serial number|:missing value, |mount points|:missing value}, {|name|:"IR Receiver", |serial number|:missing value, |mount points|:missing value}, {|name|:"Card Reader", |serial number|:"000000009833", |mount points|:missing value}}

It missed the Transcend USB Flash Disk formatted as Journaled HFS+

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) lundi 19 décembre 2016 12:18:40

I’ve just revised my effort in post #24 in the light of a couple of Yvan’s XML results which he e-mailed to me. Thanks, Yvan.

Bingo

THanks Nigel

This time every items appear :

{{|name|:"FaceTime HD Camera (Built-in)", |serial number|:"CC2B26051GDGGDFP", |mount points|:missing value}, {|name|:"Patriot Memory", |serial number|:"07981808B2F1361F", media:{{|name|:"Patriot Memory", |mount points|:{missing value, "/Volumes/Yosemite Install Disk - 10.10.4"}}}}, {|name|:"Apple Keyboard", |serial number|:missing value, |mount points|:missing value}, {|name|:"Bluetooth USB Host Controller", |serial number|:"442A60CDF2EE", |mount points|:missing value}, {|name|:"Mass Storage Device", |serial number|:missing value, media:{{|name|:"USB Flash Disk", |mount points|:{"/Volumes/Transcend"}}}}, {|name|:"IR Receiver", |serial number|:missing value, |mount points|:missing value}, {|name|:"Card Reader", |serial number|:"000000009833", |mount points|:missing value}}

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) lundi 19 décembre 2016 16:36:59

Hi ProGrammer.

My script in post #24 returns a list of records, each record containing (where available) a serial number and a list of mount points. It should be just a matter of checking each record’s |mount points| to see if it contains the one for your script’s home volume and, if it does, checking the record’s |serial number| to see if it matches the one you require it to be. But things have just got more complicated in my attempt to make the script compatible with Sierra’s system_profiler, which returns a more complex structure. In this case, instead of a |mount points| list, each record has a media list, each of which has a list of |mount points|.

-- A record returned by the script in El Capitan:
{|name|:"Patriot Memory", |serial number|:"07981808B2F1361F", |mount points|:{missing value, "/Volumes/Yosemite Install Disk - 10.10.4"}}

-- The record for the same device in Sierra:
{|name|:"Patriot Memory", |serial number|:"07981808B2F1361F", media:{{|name|:"Patriot Memory", |mount points|:{missing value, "/Volumes/Yosemite Install Disk - 10.10.4"}}}}

If the script’s confirmed to work properly in Sierra, you can scan its result as below, replacing the set scriptDiskMountPoint . and set requiredSerialNumber . lines with your own code for finding the mount point and specifying a serial number. It’s more complicated than simply parsing text, but there’s less likelihood of a mismatch between mount point and serial number.

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

set scriptDiskMountPoint to "/Volumes/My USB Disk" -- Set to your script's home disk mount point.
set requiredSerialNumber to "12345" -- Set to the serial number of the device it has to match.

set USB to (do shell script "system_profiler -xml SPUSBDataType" without altering line endings)

set aString to current application's class "NSString"'s stringWithString:(USB)
set theData to aString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
set {theThing, theError} to current application's class "NSPropertyListSerialization"'s propertyListWithData:(theData) options:(0) |format|:(missing value) |error|:(reference)
set deviceDetails to current application's class "NSMutableArray"'s new()
parseRecursively(theThing's firstObject(), deviceDetails)
set deviceDetails to deviceDetails as list

set serialNumberMatched to false
repeat with deviceRecord in deviceDetails
	set {|mount points|:mountPoints, media:media} to deviceRecord & {|mount points|:missing value, media:missing value}
	if (media's class is list) then
		repeat with thisMedium in media
			set mountPointFound to (thisMedium's |mount points| contains scriptDiskMountPoint)
			if (mountPointFound) then exit repeat
		end repeat
	else
		set mountPointFound to ((mountPoints's class is list) and (mountPoints contains scriptDiskMountPoint))
	end if
	if (mountPointFound) then
		set serialNumberMatched to (deviceRecord's |serial number| is requiredSerialNumber)
		exit repeat
	end if
end repeat
return serialNumberMatched

on parseRecursively(thisThing, deviceDetails)
	set subthings to thisThing's valueForKey:("_items")
	repeat with thisSubthing in subthings
		if (thisSubthing's allKeys()'s containsObject:("_items")) then
			parseRecursively(thisSubthing, deviceDetails)
		else
			-- In El Capitan, 'volumes', if it exists, is a direct property of a device. In Sierra, it's apparently a property of individual 'media' which a device may have.
			if (thisSubthing's allKeys()'s containsObject:("Media")) then -- Sierra.
				set theMedia to (thisSubthing's valueForKey:("Media"))
				set mediaDetails to current application's class "NSMutableArray"'s new()
				repeat with thisMedium in theMedia
					set theseDetails to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisMedium's valueForKey:("_name"), thisMedium's valueForKeyPath:("volumes.mount_point")}) forKeys:({"name", "mount points"}))
					tell mediaDetails to addObject:(theseDetails)
				end repeat
				set thisEntry to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisSubthing's valueForKey:("_name"), thisSubthing's valueForKey:("serial_num"), mediaDetails}) forKeys:({"name", "serial number", "media"}))
			else -- El Capitan.
				set mountPoints to (thisSubthing's valueForKeyPath:("volumes.mount_point")) -- List of mount points.
				set thisEntry to (current application's class "NSDictionary"'s dictionaryWithObjects:({thisSubthing's valueForKey:("_name"), thisSubthing's valueForKey:("serial_num"), mountPoints}) forKeys:({"name", "serial number", "mount points"}))
			end if
			tell deviceDetails to addObject:(thisEntry)
		end if
	end repeat
end parseRecursively