Report Hard Drive Availabe Space ?

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?

Thanks for any input ! KB

Here’s why I’m at so far …

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:

% df
Filesystem 512-blocks Used Avail Capacity Mounted on
/dev/disk0s9 39065400 35600912 3464488 91% /
devfs 63 63 0 100% /dev
fdesc 2 2 0 100% /dev
1024 1024 0 100% /.vol
automount -fstab [243] 0 0 0 100% /Network/Servers
automount -static [243] 0 0 0 100% /automount

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.

  • dp

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

Hi,

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?

Screenshot

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.

Would not have thought to use an “exclude” list. Thank you, works perfectly!

This method only lists mount points.

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

Thanks, that seems to work equally well, with one exception, the name of the first disk, which I believe should be “Macintosh HD”.

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
1 Like

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.

1 Like

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

I like the idea of the “system mount points” as it lists the “SuperDuper! Clone” just once, rather than also listing “SuperDuper! Clone-Data”.

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.
Error
Error Lines

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