Hello,
We’re hoping to develop a workflow where a script could systematically poll the various computers on our network to determine their available space. Ideally this info would get passed out and into a Filemaker database that would be the clearing house for the information.
So is there some way to get the “Used Space” and “Available Space” info for Hard Drives? Would this then be expandable to ALL the various HD’s on the network?
tell application "Finder" to set theVolume to name of startup disk
tell application "Finder"
set whatsLeft to free space ¬
of disk theVolume
end tell
set Giga to {(whatsLeft) / 1024 / 1024 / 1024}
display dialog "The available space on the drive
Macintosh HD is " & Giga & " Gigabytes"
I see you have already made some progress, I am not sure how much this post really adds.
Here is something that might get you started on the data gathering part:
set reportText to ""
tell application "Finder" to ¬
set diskList to every disk whose local volume is true
repeat with diskRef in diskList
if reportText is not equal to "" then ¬
set reportText to reportText & return
tell application "Finder" to ¬
set {name:diskName, free space:freeSpace, capacity:totalSpace} to contents of diskRef
set usedSpace to totalSpace - freeSpace
set reportText to reportText & diskName & ": " & freeSpace & " / " & usedSpace
end repeat
display dialog reportText with title "Free/Used Space Report"
The core of it is getting Finder to make a list of every disk whose local volume is true. Then, in the loop, I extract various properties from each of the disks: name, free space, and capacity. Instead of making a report, it sounds like you would want to push the information into a database (I do not have Filemaker, so I will not speculate on that part). This list will include external disks, “thumb drives”, and mounted disk images (regardless of their source), so you may need to come up with a way to filter out disks in which you have no interest.
As far as gathering information from multiple machines, there is a way to run AppleScript commands on remote machines, but I only have one machine, so I have never done it. First you have to enable Remote Apple Events in the Sharing System Preference Pane. Then, you use something like tell application “Finder” of machine “Name of Other Machine” to send commands to Finder running on the other machine. See References to Remote Applications in the AppleScript Language Guide. Enabling Remote Apple Events opens a new service that may expose new security vulnerabilities.
Another way to go might be to arrange for an AppleScript program to run on each of the computers and then “report back” by writing to a file on network share, or maybe by sending the data directly to Filemaker through some sort of remote database access (I have read mentions of something like that, but I have never used Filemaker).
Model: iBook G4 933
AppleScript: 1.10.7
Browser: Safari 419.3
Operating System: Mac OS X (10.4)
Another solution might be to enable SSH tunneling on all those computers (which is relatively secure as long is no one is loose with their password and on the same LAN) and useing a short shell script to report out the disk space numbers. There is a handy little command called “df” which you can type into terminal and get out something like this:
We could THEN create a script in either shell script or applescript which can save and send that data. For example, this little script takes down that “df” data (Used space and Available space and much more included) and writes it to a file called hd_test in your Documents folder.
set theData to do shell script "df"
set dp to ((path to "docs" as text) & "hd_test.txt")
set theTarget to open for access file dp with write permission
close access theTarget
write theData to file dp
You could very easily have your own program run a remote “df” check on those machines, have it save that data as text or something like above, and email/ftp/SSH/whatever it back to your computer. It may even be possible to merely “mount” the disks remotely and run the check from your computer. If this sounds like an exceptable plan, I would be happy to walk you through creating the necassary scripts and activations for such a task.
So I’ve been working a little more on this script. What I have now will take a disk (for the attached example it’s the startup disk) and report back the Overall Capacity, the Used Space, the Available Space and finally the disk capacity as a percentage. I worked in some sub-routines to take care of rounding the numbers off some.
So the next step would be to implement this across the mounted volumes that any particular machine has. So it basically would require combining what I have so far + the script that chrys posted in his response. So that’s where I stand. I’ll keep working away on it and will post back. If anyone else wants to chime in along the way, I’m all ears. Thanks for the input so far.
I’m sure I’ll run into complications at some point when I try to consolidate what I have with chrys’s example.
Here it is:
tell application "Finder"
set theVolume to name of startup disk
set {diskSize, whatsLeft} to {capacity, free space} of disk theVolume
set usedUp to (diskSize - whatsLeft)
set ConvertedSpace to {(usedUp) / 1024 / 1024 / 1024} as string
set theSize to capacity of disk "Macintosh HD"
set ConvertedSize to {(theSize) / 1024 / 1024 / 1024} as string
set ConvertedFree to {(whatsLeft) / 1024 / 1024 / 1024} as string
set Percentage to ((diskSize - whatsLeft) / diskSize) * 100
end tell
set ConvertedSize to round_truncate(ConvertedSize, 2)
set ConvertedSpace to round_truncate(ConvertedSpace, 2)
set ConvertedFree to round_truncate(ConvertedFree, 2)
set Percentage to round_truncate(Percentage, 1)
display dialog "This Hard Drive's overall capacity is " & ConvertedSize & " GB." & return & return & "The used space is " & ConvertedSpace & " GB." & return & return & "Tha available space is " & ConvertedFree & " GB." & return & return & "This drive is " & Percentage & "% full." buttons "OK" default button "OK"
-->Subroutine #1 - Number to Text
number_to_text(ConvertedSpace)
on number_to_text(this_number)
set this_number to this_number as text
if this_number contains "E+" then
set x to the offset of "." in this_number
set y to the offset of "+" in this_number
set z to the offset of "E" in this_number
set the decimal_adjust to characters (y - (length of this_number)) thru ¬
-1 of this_number as string as number
if x is not 0 then
set the first_part to characters 1 thru (x - 1) of this_number as string
else
set the first_part to ""
end if
set the second_part to characters (x + 1) thru (z - 1) of this_number as string
set the converted_number to the first_part
repeat with i from 1 to the decimal_adjust
try
set the converted_number to ¬
the converted_number & character i of the second_part
on error
set the converted_number to the converted_number & "0"
end try
end repeat
return the converted_number
else
return this_number
end if
end number_to_text
-->Subroutine #2 - Round and Truncate
round_truncate(ConvertedSpace, 2)
on round_truncate(this_number, decimal_places)
if decimal_places is 0 then
set this_number to this_number + 0.5
return number_to_text(this_number div 1)
end if
set the rounding_value to "5"
repeat decimal_places times
set the rounding_value to "0" & the rounding_value
end repeat
set the rounding_value to ("." & the rounding_value) as number
set this_number to this_number + rounding_value
set the mod_value to "1"
repeat decimal_places - 1 times
set the mod_value to "0" & the mod_value
end repeat
set the mod_value to ("." & the mod_value) as number
set second_part to (this_number mod 1) div the mod_value
if the length of (the second_part as text) is less than the ¬
decimal_places then
repeat decimal_places - ¬
(the length of (the second_part as text)) times
set second_part to ("0" & second_part) as string
end repeat
end if
set first_part to this_number div 1
set first_part to number_to_text(first_part)
set this_number to (first_part & "." & second_part)
return this_number
end round_truncate
I know, the formatting is not perfect, but try this
property GB : 1.073741824E+9 -- is the equivalent to 1024 * 1024 * 1024
tell application "Finder" to set allDisks to name of disks whose local volume is true
set theData to "Disk" & tab & tab & "Capacity" & tab & "Used" & tab & "Free" & tab & tab & "Percentage" & return
repeat with oneDisk in allDisks
tell application "Finder" to set {diskSize, whatsLeft} to {capacity, free space} of disk oneDisk
set ConvertedSpace to round_dec(((diskSize - whatsLeft) / GB), 2)
set ConvertedSize to round_dec(diskSize / GB, 2)
set ConvertedFree to round_dec(whatsLeft / GB, 2)
set Percentage to round_dec(((diskSize - whatsLeft) / diskSize * 100), 1)
set theData to theData & oneDisk & tab & ConvertedSize & tab & ConvertedSpace & tab & ConvertedFree & tab & Percentage & return
end repeat
display dialog theData buttons {" OK "} default button 1
on round_dec(value, decplace)
return (round (value * (10 ^ decplace))) / (10 ^ decplace)
end round_dec
PS: these Apple subroutines are not needed, because the values are converted in gigabytes anyway
and the rounding can be done with an one-liner
I like this version (adapted from chrys’) which lines up a bit better:
set reportText to ""
set Gig to 1024 * 1024 * 1024
tell application "Finder" to ¬
set diskList to every disk whose local volume is true
repeat with diskRef in diskList
if reportText is not equal to "" then ¬
set reportText to reportText & return
tell application "Finder" to ¬
set {name:diskName, free space:freeSpace, capacity:totalSpace} to contents of diskRef
set usedSpace to totalSpace - freeSpace
set perc to usedSpace / totalSpace
set reportText to reportText & diskName & ": " & characters 1 thru 4 of ((freeSpace / Gig) as text) & " / " & characters 1 thru 4 of ((usedSpace / Gig) as text) & " - " & characters 1 thru 4 of ((100 * perc) as text) & "% used."
end repeat
display dialog reportText with title "Free/Used Space Report"
Did a search for “AppleScript to show free space on HD” and ended up here at MacScripter on this thread. The script by “kevincbrock” in post #5 (even though it dates back to 2007) functions perfectly on my MacBook Pro running Sonoma 14.7.3.
Looking for some help modifying this script to not just report on the startup drive, but all connected drives. Any ideas?
Edit: Actually, the script by “Adam_Bell” in post #7 gives me almost what I need (don’t know how I missed that) except, is there a way to modify the script to not show (see screenshot): Preboot, Update and VM?
This is an interesting question, and I’m not sure of the answer. Just on a proof-of-concept basis, the following script uses an exclude list.
set excludeDisks to {"VM", "Preboot", "Update", "xarts", "iSCPreboot", "Hardware", "home"} --edit as required
tell application "System Events"
set theDisks to name of every disk
set dialogText to ""
repeat with aDisk in theDisks
if aDisk is not in excludeDisks then
set dialogText to dialogText & "Disk Name: " & aDisk & linefeed
set diskSize to (capacity of disk aDisk) / 1.0E+9 div 1
set dialogText to dialogText & "Disk Size: " & diskSize & " GB" & linefeed
set freeSpace to (free space of disk aDisk) / 1.0E+9 div 1
set dialogText to dialogText & "Free Space: " & freeSpace & " GB" & linefeed
set dialogText to dialogText & linefeed
end if
end repeat
end tell
display alert "The following disks were found:" message dialogText
The other approach, of course, is to use a list of disks to include. I think I prefer the above approach.
use framework "Foundation"
use scripting additions
set theDisks to my System_Mount_Points_Names()
set dialogText to ""
repeat with aDisk in theDisks
set {diskSize, freeSpace} to my Drive_Stats(aDisk)
set dialogText to dialogText & "Disk Name: " & aDisk & linefeed
set dialogText to dialogText & "Disk Size: " & diskSize & " GB" & linefeed
set dialogText to dialogText & "Free Space: " & freeSpace & " GB" & linefeed
set dialogText to dialogText & linefeed
end repeat
display alert "The following disks were found:" message dialogText
on System_Mount_Points_Names()
try
set mountedVolumeURLs to current application's NSFileManager's defaultManager()'s mountedVolumeURLsIncludingResourceValuesForKeys:{"NSURLNameKey"} options:2
set mountedVolumeNames to current application's NSMutableArray's array()
repeat with aVolume in mountedVolumeURLs
(mountedVolumeNames's addObject:(aVolume's lastPathComponent()))
end repeat
return mountedVolumeNames as list
on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
error "<System_Mount_Points_Names>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
end try
end System_Mount_Points_Names
on Drive_Stats(aDisk)
tell application "System Events"
set diskSize to (capacity of disk aDisk) / 1.0E+9 div 1
set freeSpace to (free space of disk aDisk) / 1.0E+9 div 1
return {diskSize, freeSpace}
end tell
end Drive_Stats
You probably want to add “Recovery” to your exclude list.
I modified the script above to use true Gigabytes (i.e 1024 * 1024 * 1024)
and give results to the tenth of a GB.
set excludeDisks to {"VM", "Preboot", "Recovery", "Update", "xarts", "iSCPreboot", "Hardware", "home"} --edit as required
tell application "System Events"
set theDisks to name of every disk
set dialogText to ""
repeat with aDisk in theDisks
if aDisk is not in excludeDisks then
set dialogText to dialogText & "Disk Name: " & aDisk & linefeed
set diskSize to (capacity of disk aDisk) / 1.073741824E+8 div 1 / 10
set dialogText to dialogText & "Disk Size: " & diskSize & " GB" & linefeed
set freeSpace to (free space of disk aDisk) / 1.073741824E+8 div 1 / 10
set dialogText to dialogText & "Free Space: " & freeSpace & " GB" & linefeed
set dialogText to dialogText & linefeed
end if
end repeat
end tell
display alert "The following disks were found:" message dialogText
And, I also learned something. On my Intel 2018 Mac mini, I was able to delete from the exclude list everything but VM, Preboot, Update and Home and it worked perfectly. On my M1 2020 MacBook Pro, I had to leave the entire exclude list to come up with same “clean” result. So, apparently there are drives (so to speak) on the MacBook Pro that are not present on the Mac mini.
That’s a fair criticism. This version reports the correct name for the boot volume and it also returns valid results for small volumes rather than returning 0 for any < 1GB. Volumes capacities are returned quoted in the largest unit applicable (TB,GB,MB, or KB).
use framework "Foundation"
use scripting additions
set theDisks to my System_Mount_Points()
set dialogText to ""
repeat with aDisk in theDisks
set aDisk to contents of aDisk
set {diskName, diskSize, freeSpace} to my Drive_Stats(aDisk)
set dialogText to dialogText & "Disk Name: " & diskName & linefeed
set dialogText to dialogText & "Disk Size: " & diskSize & linefeed
set dialogText to dialogText & "Free Space: " & freeSpace & linefeed
set dialogText to dialogText & linefeed
end repeat
display alert "The following disks were found:" message dialogText
on System_Mount_Points()
try
set varOne to current application's NSFileManager's defaultManager()'s mountedVolumeURLsIncludingResourceValuesForKeys:{"NSURLNameKey"} options:2
set mountedVolumeRefs to current application's NSMutableArray's array()
repeat with aVolume in varOne
(mountedVolumeRefs's addObject:aVolume)
end repeat
return mountedVolumeRefs as list
on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
error "<System_Mount_Points>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
end try
end System_Mount_Points
on Drive_Stats(aDisk)
tell application "System Events"
set aDisk to aDisk as text
set diskSize to my BytesToCommonUnit(capacity of disk aDisk)
set freeSpace to my BytesToCommonUnit(free space of disk aDisk)
return {aDisk, diskSize, freeSpace}
end tell
end Drive_Stats
on BytesToCommonUnit(bytesCount)
set TBCount to bytesCount / 1.0E+12
if TBCount > 1 then
set bytesCount to bytesCount / 1.0E+12
set unitType to "TB"
else
set GBCount to bytesCount / 1.0E+9
if GBCount > 1 then
set bytesCount to bytesCount / 1.0E+9
set unitType to "GB"
else
set MBCount to bytesCount / 1.0E+6
if MBCount > 1 then
set bytesCount to bytesCount / 1.0E+6
set unitType to "MB"
else
set KBCount to bytesCount / 1000.0
if KBCount > 1 then
set bytesCount to bytesCount / 1000.0
set unitType to "KB"
else
end if
end if
end if
end if
set bytesCount to roundThis(bytesCount, 2)
return "" & bytesCount & " " & unitType
end BytesToCommonUnit
on roundThis(n, numDecimals)
set x to 10 ^ numDecimals
(((n * x) + 0.5) div 1) / x
end roundThis
Here, this returns…
Disk Name: Macintosh HD:
Disk Size: 499.96 GB
Free Space: 285.84 GB
Disk Name: Untitled:
Disk Size: 127.83 GB
Free Space: 127.83 GB
Disk Name: external:
Disk Size: 4.0 TB
Free Space: 2.51 TB
Disk Name: LogCollectorTool:
Disk Size: 41.28 MB
Free Space: 39.96 MB
Disk Name: SomeDiskImage:
Disk Size: 262.14 MB
Free Space: 193.74 MB
Disk Name: AFPVolume:
Disk Size: 112.0 TB
Free Space: 6.49 TB
Here is an updated version of mine that Changes the largest unit applicable…
set excludeDisks to {"VM", "Preboot", "Recovery", "Update", "xarts", "iSCPreboot", "Hardware", "home"} --edit as required
local theDisks, aDisk, dialogText, anItem, s, n, c, f, tid
tell application "System Events"
set theDisks to name of every disk
set dialogText to {}
repeat with anItem in theDisks
set anItem to contents of anItem
if anItem is not in excludeDisks then
set s to capacity of disk anItem
set f to free space of disk anItem
set n to s
set c to 0
repeat until n < 1.048576E+6
set n to n / 1024
set c to c + 1
end repeat
tell {{1.048576E+5, " MB"}, {1.073741824E+8, " GB"}, {1.099511627776E+11, " TB"}}
s / (item 1 of item c) div 1 / 10 & (item 2 of item c)
set end of dialogText to {"Disk Name: " & anItem, ¬
"Disk Size: " & (s / (item 1 of item c) div 1 / 10 & (item 2 of item c)), ¬
"Free Space: " & (f / (item 1 of item c) div 1 / 10) & (item 2 of item c)}
end tell
end if
end repeat
end tell
set tid to text item delimiters
set text item delimiters to linefeed
repeat with aDisk in dialogText
set contents of aDisk to aDisk as text
end repeat
set text item delimiters to linefeed & linefeed
set dialogText to (dialogText as text) & linefeed
set text item delimiters to tid
display alert "The following disks were found:" message dialogText --giving up after 10
Nice. I like your handling of the units better than that ugly nested IF I made! Here’s a handler for that.
on Bytes_As_Data_Storage_Units(Byte_Count, unitType)
try
if unitType is in {"KB", "MB", "GB", "TB"} then
set dataSet to {1000, {" KB", " MB", " GB", " TB"}}
else --use Kibibyte units.
set dataSet to {1024, {" KiB", " MiB", " GiB", " TiB"}}
end if
set counter to 0
repeat until Byte_Count < item 1 of dataSet
set {Byte_Count, counter} to {Byte_Count / (item 1 of dataSet), counter + 1}
end repeat
return "" & ((((Byte_Count * (10 ^ 2)) + 0.5) div 1) / (10 ^ 2)) & ((item counter of item 2 of dataSet))
on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
error "<Bytes_As_Data_Storage_Units>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
end try
end Bytes_As_Data_Storage_Units
For those of us that still qualify as the “AppleScript Unskilled”, any chance you could incorporate your new “handler” into your script. I tried replacing the entire “on BytesToCommonUnit(bytesCount)” section with no success. Ended up with errors.
Certainly. I’ve changed Bytes_As_Data_Storage_Units slightly since last posting. Now, as argument, it takes bytes and the value you want to use for your units, either 1000 or 1024. It will handle any file size from <1KB to 999 QB.
use framework "Foundation"
use scripting additions
set theDisks to my System_Mount_Points()
set dialogText to ""
repeat with thisDisk in theDisks
set thisDisk to contents of thisDisk
set {diskName, diskSize, freeSpace} to my Drive_Stats(thisDisk)
set dialogText to dialogText & "Disk Name: " & diskName & linefeed
set dialogText to dialogText & "Disk Size: " & diskSize & linefeed
set dialogText to dialogText & "Free Space: " & freeSpace & linefeed
set dialogText to dialogText & linefeed
end repeat
display alert "The following disks were found:" message dialogText
on System_Mount_Points()
try
set varOne to current application's NSFileManager's defaultManager()'s mountedVolumeURLsIncludingResourceValuesForKeys:{"NSURLNameKey"} options:2
set mountedVolumeRefs to current application's NSMutableArray's array()
repeat with aVolume in varOne
(mountedVolumeRefs's addObject:aVolume)
end repeat
return mountedVolumeRefs as list
on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
error "<System_Mount_Points>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
end try
end System_Mount_Points
on Drive_Stats(thisDisk)
tell application "System Events"
set thisDisk to thisDisk as text
set unitSize to 1000 --1000 or 1024
set diskSize to my Bytes_As_Data_Storage_Units(capacity of disk thisDisk, unitSize)
set freeSpace to my Bytes_As_Data_Storage_Units(free space of disk thisDisk, unitSize)
return {thisDisk, diskSize, freeSpace}
end tell
end Drive_Stats
on Bytes_As_Data_Storage_Units(Byte_Count, unitSize)
try
if unitSize is 1000 then
set dataSet to {" bytes", " KB", " MB", " GB", " TB", "PB", "EB", "ZB", "YB", "RB", "QB"}
else --use Kibibyte units.
set dataSet to {" bytes", " KiB", " MiB", " GiB", " TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"}
end if
set counter to 0
repeat until Byte_Count < unitSize
set {Byte_Count, counter} to {Byte_Count / unitSize, counter + 1}
end repeat
return "" & ((((Byte_Count * (10 ^ 2)) + 0.5) div 1) / (10 ^ 2)) & ((item (counter + 1) of dataSet))
on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
error "<Bytes_As_Data_Storage_Units>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
end try
end Bytes_As_Data_Storage_Units