Page 1 of 2
How to get available hard drive space [SOLVED]
Posted: 28 Apr 2014 07:05
by Dos_Probie
The below code will give me my CORRECT Local Drive Free space (as show in My Computer) when increasing 1024 to 1036. Is this just a issue with batch files doing the math or what?
Code: Select all
@echo off
for /f "skip=1 usebackq delims==" %%i in (`wmic logicaldisk where "mediatype='12'" get caption`) do (
call :doit %%i )
:doit
set driveletter=%1
if {%driveletter%}=={} goto :EOF
for /f "usebackq delims== tokens=2" %%x in (`wmic logicaldisk where "DeviceID='%driveletter%'" get FreeSpace /format:value`) do set FreeSpace=%%x
for /f "usebackq delims== tokens=2" %%x in (`wmic logicaldisk where "DeviceID='%driveletter%'" get Size /format:value`) do set Size=%%x
set LocalDrv=%cd:~0,2%
set FreeMB=%FreeSpace:~0,-10%
set SizeMB=%Size:~0,-10%
set /a HDPercent=100 * FreeMB / SizeMB
set /a KB=%FreeSpace:~0,-4%
set /a MB = KB/1036
set /a GB = MB/1036
Echo %LocalDrv% Drive: %GB% GB Of Free Space = %HDPercent%%% Available..
Pause>nul
Re: Question on Avialable hard drive output from batch?
Posted: 28 Apr 2014 10:16
by penpen
It is because you use "set /A KB=%FreeSpace:~0,-4%".
So KB doesn't store the real amount of free disk space in KB: only FreeSpace/1000 (/ == div == integer division without rest).
The correct value should be: FreeSpace/1024 (default math division).
When you are seeing it from the MB size, the correct value were (default math division; the "a^b" should denote "a to the power of b"):
FreeSpace/(1024^3) == FreeSpace/(1024*1024^2)
== FreeSpace/(1000 * 1.024 *1048576)
== FreeSpace/(1000 * 1073741,824)
== FreeSpace/(1000 * 1036,2151436839745395093974366397^2)
== (FreeSpace/1000) / (1036,2151436839745395093974366397^2)
penpen
Edit: Corrected 2 flaws.
Re: Question on Avialable hard drive output from batch?
Posted: 28 Apr 2014 10:19
by Compo
Why not use one of the fancy hybrid methods!
Code: Select all
<!-- : Begin batch script
@Echo off
CScript //NoLogo "%~f0?.wsf"
Pause
Exit /b
----- Begin wsf script --->
<job><script language="VBScript">
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk Where DriveType = 3")
For Each objDisk in colDisks
intFreeSpace = objDisk.FreeSpace / 1024 / 1024 / 1024
intTotalSpace = objDisk.Size / 1024 / 1024 / 1024
pctFreeSpace = intFreeSpace / intTotalSpace
Wscript.Echo "Drive " & objDisk.DeviceID & " " & Round(intFreeSpace, 2) & _
"GB Of Free Space = " & FormatPercent(pctFreeSpace) & " available"
Next
</script></job>
<EDIT>Tidied code</EDIT>
Re: Question on Avialable hard drive output from batch?
Posted: 28 Apr 2014 16:19
by Dos_Probie
Thanks, guys
@penpen , Yours when changing as you suggested outputs a INCORRECT amount of free space.
@compo, Yours works CORRECTLY but reads ALL drives not just the local drive.
DP

Re: Question on Avialable hard drive output from batch?
Posted: 28 Apr 2014 17:42
by foxidrive
Dos_Probie wrote:Thanks, guys
@penpen , Yours when changing as you suggested outputs a INCORRECT amount of free space.
Is the figure being calculated larger than 2 GB? plain batch maths tops out there in the freespace/1024 method that penpen mentioned.
Re: How to get available hard drive space figure in power of
Posted: 28 Apr 2014 18:56
by Dos_Probie
Yes, it's much larger that 2 GB , actually 105 GB..DP
Re: How to get available hard drive space
Posted: 28 Apr 2014 19:45
by foxidrive
A little tweak of compo's code gives c: drive. The change is in line 3.
Code: Select all
<!-- : Begin batch script
@Echo off
CScript //NoLogo "%~f0?.wsf" |find /i "c:"
Pause
Exit /b
----- Begin wsf script --->
<job><script language="VBScript">
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk Where DriveType = 3")
For Each objDisk in colDisks
intFreeSpace = objDisk.FreeSpace / 1024 / 1024 / 1024
intTotalSpace = objDisk.Size / 1024 / 1024 / 1024
pctFreeSpace = intFreeSpace / intTotalSpace
Wscript.Echo "Drive " & objDisk.DeviceID & " " & Round(intFreeSpace, 2) & _
"GB Of Free Space = " & FormatPercent(pctFreeSpace) & " available"
Next
</script></job>
Re: How to get available hard drive space
Posted: 29 Apr 2014 04:14
by penpen
Dos_Probie wrote:@penpen , Yours when changing as you suggested outputs a INCORRECT amount of free space.
You misunderstood me:
It is no suggestion but an explanation, why your code seems to output the correct value. Marking the important parts with red:
penpen wrote:So KB doesn't store the real amount of free disk space in KB: only FreeSpace/1000 (/ == div == integer division without rest).
The correct value should be: FreeSpace/1024 (default math division).
Side notes:
Batch is using div and no default math.
The error your first code does (in the above notation, using default math) is
e == 1 - (1024^3/(1000*1036^2)) == 0.0004153784231004308224385444463 ~= 0.0415%
So if your FreeSpace value does not exceed 1/e == 2407,4432960091874820556991099627 GB then your code will return the correct value without rounding.
If you want the correct result with rounding, then your code returns the correct value, if your FreeSpace value must be smaller than 0.5/e == 1203.7216480045937410278495557535 GB
penpen
Re: How to get available hard drive space
Posted: 29 Apr 2014 08:35
by einstein1969
Dos_Probie wrote:The below code will give me my CORRECT Local Drive Free space (as show in My Computer) when increasing 1024 to 1036. Is this just a issue with batch files doing the math or what?
Code: Select all
@echo off
for /f "skip=1 usebackq delims==" %%i in (`wmic logicaldisk where "mediatype='12'" get caption`) do (
call :doit %%i )
:doit
set driveletter=%1
if {%driveletter%}=={} goto :EOF
for /f "usebackq delims== tokens=2" %%x in (`wmic logicaldisk where "DeviceID='%driveletter%'" get FreeSpace /format:value`) do set FreeSpace=%%x
for /f "usebackq delims== tokens=2" %%x in (`wmic logicaldisk where "DeviceID='%driveletter%'" get Size /format:value`) do set Size=%%x
set LocalDrv=%cd:~0,2%
set FreeMB=%FreeSpace:~0,-10%
set SizeMB=%Size:~0,-10%
set /a HDPercent=100 * FreeMB / SizeMB
set /a KB=%FreeSpace:~0,-4%
set /a MB = KB/1036
set /a GB = MB/1036
Echo %LocalDrv% Drive: %GB% GB Of Free Space = %HDPercent%%% Available..
Pause>nul
I agree with penpen.
This code use KB, MB, GB and is about ok. But Windows use KiB, MiB, GiB and so on. ( Ki stand for
Kibi etc.)
You
need adjust or
change the script to work in binary mode and not decimal mode
This table is for adjust or conversion decimal<-->binary
Gibi-#Inconsistent_use_of_unitsCode: Select all
Prefix Bin ÷ Dec Dec ÷ Bin Percentage difference
kilo 1.024 0.9766 +2.4% or −2.3%
mega 1.049 0.9537 +4.9% or −4.6%
giga 1.074 0.9313 +7.4% or −6.9%
tera 1.100 0.9095 +10.0% or −9.1%
peta 1.126 0.8882 +12.6% or −11.2%
exa 1.153 0.8674 +15.3% or −13.3%
zetta 1.181 0.8470 +18.1% or −15.3%
yotta 1.209 0.8272 +20.9% or −17.3%
and use MiB=MB/0.9537 or MiB=MB/1.049 (I don't have checked this)
Edit: Correct the link.
einstein1969
Re: Question on Avialable hard drive output from batch?
Posted: 29 Apr 2014 08:49
by Compo
Dos_Probie wrote:@compo, Yours works CORRECTLY but reads ALL drives not just the local drive.
DP :roll:
It was difficult to tell from your code what you were looking for, the following 'fix' uses the current directory since you appeared to use %CD% in your original example.
Code: Select all
<!-- : Begin batch script
@Echo off
CScript //NoLogo "%~f0?.wsf"
Pause
Exit /b
----- Begin wsf script --->
<job><script language="VBScript">
Set objShell = CreateObject("Wscript.Shell")
strPath = objShell.CurrentDirectory
strDrive = Left(strPath, 2)
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * From Win32_LogicalDisk Where DeviceID = '" & strDrive & "'")
For Each objDisk in colDisks
intFreeSpace = objDisk.FreeSpace / 1024 / 1024 / 1024
intTotalSpace = objDisk.Size / 1024 / 1024 / 1024
pctFreeSpace = intFreeSpace / intTotalSpace
Wscript.Echo "Drive " & strDrive & " " & Round(intFreeSpace, 2) & _
"GB Of Free Space = " & FormatPercent(pctFreeSpace) & " available"
Next
</script></job>
(the current directory if not set in the batch script prior to the wsf instruction will be that of the script itself).<EDIT>If I understand what you were trying to do in your original offering, the below,
although inaccurate, should have been all you required.
Code: Select all
@Echo off
SetLocal
For /f "UseBackQ Tokens=1-2 Delims==" %%A In (`WMIc LogicalDisk Where^
"DeviceID = '%CD:~,2%'" Get FreeSpace^, Size /Value`) Do (If "%%B" NEq "" (
Call Set _%%A=%%B))
Set/a _FreePercent=%_FreeSpace:~,-3% / %_Size:~,-5%
Set/a _FreeSpace=%_Freespace:~,-3% / 1036 /1036
Echo(Drive %CD:~,2% %_FreeSpace% GB Of Free Space = %_FreePercent%%% available
Pause>Nul
Depending upon your drive sizes and the possibility of reaching the 32-bit number limitations, you may need to replace the appropriate lines with:Code: Select all
Set/a _FreePercent=%_FreeSpace:~,-6% / %_Size:~,-8%
Set/a _FreeSpace=%_Freespace:~,-6% / 1048
</EDIT>
Re: How to get available hard drive space
Posted: 29 Apr 2014 10:45
by einstein1969
There is a problem with output of wmic too...
This is accurate and work until 1PetaByte using above table for output in GiB.
This is an examples for freespace only. You may adapt for Tera byte output in future easily.
Code: Select all
@echo off
for /f "skip=1 usebackq delims==" %%i in (`wmic logicaldisk where "mediatype='12'" get caption`) do (
call :doit %%i )
goto :eof
:doit
set driveletter=%1
if {%driveletter%}=={} goto :EOF
rem add patch for wmic output
for /f "usebackq delims== tokens=2" %%x in (`wmic logicaldisk where "DeviceID='%driveletter%'" get FreeSpace /format:value`) do for %%y in (%%x) do set FreeSpace=%%y
rem 1PetaByte
rem set freespace=112589990684262
rem using MB for getting three digit after the comma. Precision of 3 digit.
set MB=%FreeSpace:~0,-6%
if Not defined MB set MB=0
rem workaround for batch precision
if %MB% lss 214748 (
set /A GiB=MB*9313/10000
) else set /A GiB=MB/1074*1000
echo %1 FreeSpace: %freespace% Byte - %GiB:~0,-3%.%GiB:~-3% GiB
goto :eof
einstein1969
Re: How to get available hard drive space
Posted: 29 Apr 2014 11:21
by Compo
einstein1969 wrote:Code: Select all
rem workaround for batch precision
if %MB% lss 214748 (
set /A GiB=MB*9313/10000
) else set /A GiB=MB/1074*1000
Using your accuracy
Code: Select all
@Echo off
SetLocal
For /f "UseBackQ Tokens=1-2 Delims==" %%A In (`WMIc LogicalDisk Where^
"DeviceID = '%CD:~,2%'" Get FreeSpace^, Size /Value`) Do If "%%B" NEq "" (
Call Set _%%A=%%B)
Rem Set/a _FreePercent=%_FreeSpace:~,-3% / %_Size:~,-5%
Set/a _FreePercent=%_FreeSpace:~,-6% / %_Size:~,-8%
If %_FreeSpace:~,-6% lss 214748 (Set/a _FreeSpace=%_FreeSpace:~,-6%*9313/10000
) Else (Set/a _FreeSpace=%_FreeSpace:~,-6%/1074*1000)
Echo(Drive %CD:~,2% %_FreeSpace:~,-3% GiB Of Free Space = %_FreePercent%%%^
available
Pause>Nul
TBH I see no real reason for accuracy when using integer math which rounds down
Re: How to get available hard drive space
Posted: 29 Apr 2014 11:53
by einstein1969
Compo wrote:einstein1969 wrote:Code: Select all
rem workaround for batch precision
if %MB% lss 214748 (
set /A GiB=MB*9313/10000
) else set /A GiB=MB/1074*1000
Using your accuracy
Code: Select all
@Echo off
SetLocal
For /f "UseBackQ Tokens=1-2 Delims==" %%A In (`WMIc LogicalDisk Where^
"DeviceID = '%CD:~,2%'" Get FreeSpace^, Size /Value`) Do If "%%B" NEq "" (
Call Set _%%A=%%B)
Rem Set/a _FreePercent=%_FreeSpace:~,-3% / %_Size:~,-5%
Set/a _FreePercent=%_FreeSpace:~,-6% / %_Size:~,-8%
If %_FreeSpace:~,-6% lss 214748 (Set/a _FreeSpace=%_FreeSpace:~,-6%*9313/10000
) Else (Set/a _FreeSpace=%_FreeSpace:~,-6%/1074*1000)
Echo(Drive %CD:~,2% %_FreeSpace:~,-3% GiB Of Free Space = %_FreePercent%%%^
available
Pause>Nul
TBH I see no real reason for accuracy when using integer math which rounds down
I have done 3 digit precision for compare with 2 digit precision windows freespace. The error of integer math is not visible until we get range extreme. But there is the REMAINDER if we can go over...
Code: Select all
C: FreeSpace: 1779224576 Byte - 1.656 GiB
D: FreeSpace: 3993055232 Byte - 3.718 GiB
E: FreeSpace: 10647683072 Byte - 9.915 GiB
F: FreeSpace: 6824042496 Byte - 6.355 GiB
Code: Select all
Drive E: 9 GiB Of Free Space = 18% available
The free space on my E: volume is 10647683072 Byte = 10647683072/1024/1024/1024 = 9,9164276123046875 (near 10GiB)
The difference about 9.916 and 9.915 is because the above Table report 9313 and this is truncate.
Real value is 1 / (1024*1024*1024) = 0.00 ... 931322574615478515625....
And for the truncate of %FreeSpace:~,-6%
einstein1969
Re: How to get available hard drive space
Posted: 29 Apr 2014 12:10
by Dos_Probie
Thanks everyone on the script choices, I know PowerShell and Vbs would do a better job but just wanted to stick with pure batch, anyway will be using the Einstein revised script by Compo which gives me the results from a variable that I am looking for..
DP

Re: How to get available hard drive space
Posted: 29 Apr 2014 21:50
by Liviu
I can see that the issue has been resolved to everybody's satisfaction, but still have a side comment on this.
Compo wrote:TBH I see no real reason for accuracy when using integer math which rounds down
While it's true that the builtin integer division truncates (rounds down), it's also easy to use it to "round to nearest", instead.
Code: Select all
set/a truncated = a / b
set/a nearest = (a + b/2) / b
For low precision arithmetics, such as GBs and whole number percents, this is often enough to get integer results right. Below is a rewrite of the code in the original post...
Code: Select all
@echo off & setlocal
for /f "usebackq skip=1" %%X in (`
wmic logicaldisk where "mediatype='12'" get caption
`) do call :drive %%X
endlocal & goto :eof
:drive
if "%~1"=="" goto :eof
set "freeB=" & set "sizeB="
for /f "usebackq skip=1 tokens=1,2" %%X in (`
wmic logicaldisk where "DeviceID='%1'" get freespace^,size
`) do if not defined freeB (set "freeB=%%X" & set "sizeB=%%Y")
set/a freeMB = %freeB:~0,-6% & set/a sizeMB = %sizeB:~0,-6%
set/a freePCT = (100 * freeMB + sizeMB / 2) / sizeMB
call :mb2gib freeMB freeGiB & call :mb2gib sizeMB sizeGiB
echo Drive %1 %freeGiB% GB free / %sizeGiB% GB size = %freePCT%%% available (= %freeB% / %sizeB%)
goto :eof
:mb2gib
@rem double 1000/1024 mb->mib correction
set/a %2 = (125 * ((125 * %1 + 64) / 128) + 64) / 128
@rem 1/1024 mib->gib conversion
set/a %2 = (%2 + 512) / 1024
...which gives accurate numbers in the majority of cases up to about 10 TB drives.
For 100% accuracy to the last digit and beyond, see
http://www.dostips.com/forum/viewtopic.php?p=20173#p20173. Squashman's link in the second post to the long division.bat still works, despite Judago's site being officially "abandoned" for a while now.
Liviu