I’m just running this in OS X Yosemite, but it skips the serial number.
How can I get this working please?
Thanks
Matt
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:
Parsing the System Profiler text isn’t currently as simple as it appears to have been back in 2009.
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 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?
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
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