I want to know disk available size for particular drive say D, in GB.
I am using below wmic command,
wmic logicaldisk get size,freespace,caption
but it is giving info about each drive, I want for particular drive only and that even in GB.
for /f "delims=" %%a in ('wmic logicaldisk where ^"DeviceID^=^'D:^'^" get size^,freespace^,caption /format:Wmiclivalueformat.xsl^|find "="') do #set %%a
As the numbers could be pretty big and overflows the integers you can get get the free space in GB by getting a substring (be grateful that this requires only division by powers of 10 - though it's not pretty accurate as the real division should be by 1024):
set freespaceinGB=%freespace:~0,-10%
set freespaceinGB_MOD=%freespace:~-10,-8%
echo %freespaceinGB%,%freespaceinGB_MOD%
This dual routine shows the free space on all drives. You can use the main batch file to find the space free on a single drive.
#echo off
for %%A in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do if exist %%A:\ call :bytesfree.bat %%A
pause
goto :EOF
:: Below is the batch file that returns the freespace from the letter in `%1`
#echo off
:bytesfree.bat - Salmon Trout
for /f "tokens=1-3 delims= " %%A in ('dir %1: ^| find "bytes free"') do set bytesfree="%%C"
echo Wscript.echo Formatnumber(eval(WScript.Arguments(0)/1073742268), 2, True,, False) > "%temp%\Calculate.vbs"
for /f "delims=" %%A in ('cscript //nologo "%temp%\Calculate.vbs" %bytesfree%') do set GBfree=%%A & del "%temp%\Calculate.vbs"
set "GBFree= %GBFRee%"
set GBFree=%GBFRee:~-12%
echo %1 %GBfree% GB free
goto :EOF
If you know the VB script then Check this Microsoft link this might resolve your issue.
http://technet.microsoft.com/en-us/library/ee198873.aspx
You just need to copy that code in notepad and save it as .vbs format and execute the file from commandline. command will be like this. cscript filename.vbs
I have a batch file that verifies HDD, Mem, OS and CPU arch, I ripped it a bit to fit your needs. Just set the wanted drive followed by :.
To convert the bytes to GB, I first trim in 1000 until the value can fit in 32bits and only then I divide in 1024. (cmd can only handle 32 bit integers).
#echo off setlocal EnableDelayedExpansion
rem UNIT is used to convert from Bytes to GB
rem 0 - B, 1 - KB, 2 - MB, 3 - GB
SET DRIVE="C:"
REM check all local drives for minimum space requirement
:Local_Drives_space_check
for /F "skip=1 tokens=1,2" %%a in ('wmic LogicalDisk Where DeviceID^=!DRIVE! Get FreeSpace') do (
if not "%%b"=="" (
set /A UNIT=0
set _tmp=%%a
call :TRIM !_tmp! space
echo drive !_drive:~0,1! has !space!GB free space
)
)
)
goto :end
REM :TRIM should get value to trim and a var name to store answer
REM examle: call :TRIM 536870912000 space
REM answer will be 512GB even though correct answer is 500GB
REM cmd.exe cannot handle numbers larger then 32bit
:TRIM
set _tmp=%1
set %2=
set /A %2=!_tmp! >nul 2>nul
if not defined %2 (
set _tmp=!_tmp:~0,-3!
set /A UNIT=!UNIT!+1
call :TRIM !_tmp! %2
goto :eof
)
:GB
if !UNIT! LSS 3 (
set /A %2=!%2!/1024
set /A UNIT=!UNIT!+1
)
if !UNIT! LSS 3 goto :GB
goto :eof
:end
Related
I'm a biologist, with no coding knowledge, trying to create a script that reads every *rprt.txt file in a folder.
In line 11 of each file, the fifth word is a number, If that number is 6000<number<14000 then I want to read the fifth word in line 13 and if that number is greater than 600. Copy the file into another folder in that directory.
At this point I've tried a lot of things. I know the next code is exiting the loop but is the best I got.
#echo off
for %%f in (*rprt.txt) do set "name=%%f" &goto first
:first
for /F "skip=10 tokens=5" %%i in (%name%) do set "var1=%%i" &goto nextline
:nextline
for /F "skip=12 tokens=5" %%i in (%name%) do set "var2=%%i" &goto nextline2
:nextline2
if %var1% geq 6000 (if %var2% geq 600 echo.%name% >> valid.txt)
I've also tried this to test the for loop but I don't understand what's wrong. This prints "echo is off" 3 times
#echo off
for %%f in (*rprt.txt) do (set "name=%%f" & echo %name% >> valid.txt)
#ECHO OFF
SETLOCAL
rem The following settings for the directories and filenames are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
FOR %%e IN ("%sourcedir%\*rprt.txt") DO (
rem %%e has filename
SET "line11="
FOR /f "usebackqskip=10tokens=5" %%y IN ("%%e") DO IF NOT DEFINED line11 (
SET "line11=y"
SET "line13="
FOR /f "usebackqskip=12tokens=5" %%o IN ("%%e") DO IF NOT DEFINED line13 (
SET "line13=y"
IF %%y gtr 6000 IF %%y lss 14000 IF %%o gtr 600 ECHO COPY "%%e" "%destdir%"
)
)
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around "%%e" can be omitted.
I'm assuming that the values in token 5 of the two lines are guaranteed numeric.
You were definitely on the right track, but the code for validating that something is a number can get kinda weird if you're not used to seeing it (in this case, I remove everything that isn't a digit and then return 1 if there's anything remaining) and the way that GTR and LSS work can also be confusing since it's based on ASCII values so words report as greater than numbers.
The script expects the reports to be in their own folder and the output folder to be in its own folder, and both of these folders should be in the same folder as the script, as opposed to the script being in the same folder as the input files.
#echo off
setlocal enabledelayedexpansion
set "input_directory=%~dp0\input"
set "output_directory=%~dp0\output"
pushd "%input_directory%"
for %%A in (*_rprt.txt) do (
for /f "tokens=5" %%B in ('findstr /n /r "^" "%%~A" ^| findstr "11:"') do set "line_11_num=%%B"
for /f "tokens=5" %%B in ('findstr /n /r "^" "%%~A" ^| findstr "13:"') do set "line_13_num=%%B"
call :isNumber !line_11_num! n[11]
call :isNumber !line_13_num! n[13]
set /a "valid_report=!n[11]!+!n[13]!"
if "!valid_report!"=="0" (
if !line_11_num! GTR 6000 if !line_11_num! LSS 14000 (
if !line_13_num! GTR 600 (
copy "%%~A" "%output_directory%"
)
)
)
)
exit /b
::------------------------------------------------------------------------------
:: Determines if a given string is a positive integer
::
:: Arguments: %1 - The value to check
:: %2 - The variable to store the result in
:: Returns: 0 if the number is a positive integer, 1 otherwise
::------------------------------------------------------------------------------
:isNumber
set "is_number=0"
for /f "delims=0123456789" %%A in ("%~1") do set "is_number=1"
set "%~2=%is_number%"
exit /b
The files and lines processed by for /F command must be processed completelly until the file ends; you can not "cut" the process at the middle with a goto command because the whole process is cancelled.
This means that all lines of all files must be processed with nested for /F commands and you must insert some type of control in order to "omit" the rest of lines that are not the 11 or 13. If the files are numerous or very large, this can take some time.
You can also take just the lines 11 and 13 via findstr commands, but anyway the execution of a couple of findstr commands connected via a pipe also takes some time.
You must be aware that any variable that takes its value inside a compound command (like for or if) must be accessed using !delayedExpansion! instead of %standardExpansion%. There are a lot of questions/answers in this site about this point.
My solution below takes a different approach: it reads just the first 13 lines of each file via a redirection instead of for /F command or findstr. If the files are few and small, this method would be similar in time to the other ones. However, I think this method is simpler and easier to understand.
#echo off
setlocal EnableDelayedExpansion
rem Read every *rprt.txt file in this folder
for %%f in (*rprt.txt) do (
rem Read line 11 and 13 of this file via a redirection
< "%%f" (
rem Skip first 10 lines
for /L %%i in (1,1,10) do set /P "dummy="
rem Read line 11 and line 13
set /P "line11="
set /P "dummy="
set /P "line13="
)
rem Get the number in line 11 and compare it
for /F "tokens=5" %%i in ("!line11!") do set "num=%%i"
if 6000 lss !num! if !num! lss 14000 (
rem Get the number in line 13 and compare it
for /F "tokens=5" %%i in ("!line13!") do set "num=%%i"
if !num! gtr 600 copy "%%f" anotherFolder
)
)
This code returns the disk size and space in GB. The problem is, it's only using C and i have to hard-code it.
What i'm trying is, it should iterate over all of the disks and i shouldn't have to write the disk part myself. All of my experiments were failure, i couldn't solve.
for /f "tokens=1-3" %%n in ('"WMIC LOGICALDISK GET Name,Size,FreeSpace | find /i "C:""') do set free=%%n& set total=%%p
set free=%free:~0,-3%
set /a free=%free%/1049
set total=%total:~0,-3%
set /a total=%total%/1049
set /a free=%free%/1024
echo C: Space Free- %free% GB
set /a total=%total%/1024
echo C: Space total- %total% GB
Something like this? It is a little sloppy but I think it does what you are asking for using the batch you (mostly) wrote.
I am using a batch function to get the variables out of the for /f loop. You could have also used delayed expansion. I find the whole !syntax! annoying but it seems that most people prefer it to batch functions.
#echo off
for /f "tokens=1-3" %%n in ('"WMIC LOGICALDISK GET Name,Size,FreeSpace"') do call :calculate "%%n" "%%o" "%%p"
goto :EOF
:calculate
set free=%~1
set drive=%~2
set total=%~3
if "%drive%"=="" goto :EOF
if not "%drive:~1%"==":" goto :EOF
echo ---- information for drive %drive% ----
set free=%free:~0,-3%
set /a free=%free%/1049
set total=%total:~0,-3%
set /a total=%total%/1049
set /a free=%free%/1024
echo Free- %free% GB
set /a total=%total%/1024
echo Total- %total% GB
goto :EOF
Below is part of a script i've previously written to grab drive information that is echoed to screen, written to a text file and also into a CSV.
#echo off
set "pathBackup=C:\backup"
set "infoFileName=%computername%_DriveSize.txt"
set "csvFile=All_DriveSizes.csv"
::Fix for CSV format output error on some systems
if exist "%WINDIR%\System32\wbem\en-us\csv.xsl" (
set csvformat="%WINDIR%\System32\wbem\en-us\csv"
) else (
set csvformat=csv
)
:: Get Drive Partition information
echo. - Looking for Drive sizes
setlocal EnableDelayedExpansion
for /f "skip=2 tokens=2-5 delims=," %%a in ('wmic logicaldisk where (DriveType^="3"^) get DeviceID^,FreeSpace^,Size^,VolumeName /format:%csvformat%') do (
set "diskID=%%a"
set "diskSpace=%%b"
set "diskSize=%%c"
set "diskName=%%d"
set /a diskSize1=!diskSize:~0,-4! / 107374
if "0"=="!diskSize1!" (
set /a diskSize1=!diskSize! / 1048576
set diskSize1=0.!diskSize1:~0,-2!
)
set /a diskSpace1=!diskSpace:~0,-4! / 107374
if "0"=="!diskSpace1!" (
set /a diskSpace1=!diskSpace! / 1048576
set diskSpace1=0.!diskSpace1:~0,-2!
)
set driveSizes=!driveSizes!"[%%a] %%d (!diskSize1!:!diskSpace1!)",
)
endlocal&if "_%~2"=="_" (set driveSizes=%driveSizes:~0,-1%)
:: Create non CSV variable for use in CSV file creation
set driveSizescsv=%driveSizes:"=%
set driveSizescsv="%driveSizescsv%"
The bit that echos to screen and writes to text file...
echo PC Drives : [Drive] Label (Size GB:Free GB)>>"%pathBackup%\%infoFileName%"
echo PC Drives : [Drive] Label (Size GB:Free GB)
:: Write individual drives one at a time
setlocal EnableDelayedExpansion
for %%i in (%driveSizes:,= %) do (
set driveSizes1=%%i
echo. !driveSizes1:"=!
set driveSizes2=!driveSizes1:"=!
echo. !driveSizes2!>>"%pathBackup%\%infoFileName%"
)
endlocal
The bit that writes to a csv
echo %computername%,%driveSizescsv% >>"%pathBackup%\%csvfile%"
Output example..
PC Drives : [Drive] Label (Size GB:Free GB)
[C:] Windows (79:42)
[D:] Database Volume (599:90)
[E:] Log File (39:31)
As the wmic command can take a while, and arithmetic can be particularly tricky in pure batch, here are a couple of additional options for you, which leverage other built-in scripting languages:
This complete batch-file uses powershell:
#"%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoP^
"[System.IO.DriveInfo]::GetDrives()|?{$_.IsReady -Eq $True}|"^
"Select #{N='Drive';E={$_.Name.TrimEnd('\')}},"^
"#{N='Size (GiB)';E={[Double]('{0:N2}' -F ($_.TotalSize/1GB))}},"^
"#{N='Free (GiB)';E={[Double]('{0:N2}' -F ($_.AvailableFreeSpace/1GB))}}|FL
#"%__AppDir__%timeout.exe" /T 5 /NoBreak>NUL
And this even quicker batch-file uses the vbscript engine of wsh:
<!-- :
#"%__AppDir__%cscript.exe" //NoLogo "%~f0?.wsf"
#"%__AppDir__%timeout.exe" /T 5 /NoBreak>NUL
#Exit /B
-->
<Job><Script Language="VBScript">
Set o=CreateObject("Scripting.FileSystemObject")
For Each Drv In o.Drives:If Drv.IsReady=True Then
WScript.Echo "Drive="&Drv.DriveLetter&":"&VBCrLf&_
"Size="&Round(Drv.TotalSize/1073741824,2)&" GiB"&VBCrLf&_
"Free="&Round(Drv.FreeSpace/1073741824,2)&" GiB"
End If:Next
</Script></Job>
How can I get drive the valid drive letters from A to Z with the "for loop" in windows command line (cmd.exe)?
Example, list all files in a drive root folder, should be something like (conceptual):
for %f in (A..Z) do dir %f:\
or aproximating existing functionality:
for /L in (A, Z, 1) do echo %f:\
Close, but it's more like this.
for %%p in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do if not exist %%p:\nul set FREEDRIVELETTER=%%p
EDIT: Here is a powershell way, not sure if off-topic for your needs
Loops the Upper Case Alphabet
65..90 | foreach {[char]$_;Write-Host "Do Something"}
or Lower Case Alphabet
97..122 | foreach {[char]$_;Write-Host "Do Something"}
Maybe this will work from a batch file.
#ECHO OFF
start /b /wait powershell.exe "97..122 | foreach {$a=[char]$_ ;dir $a:\}"
PAUSE
To loop through all drive letters without explicitly stating them you could use forfiles (which is delivered with all Windows versions past Vista, I believe) and its capability to expand hex. codes 0xHH, together with exit to set the exit code and the hidden variable =ExitCode to convert the exit code to a hexadecimal value, like in this example code:
#echo off
for /L %%C in (0x41,1,0x5A) do (
cmd /C exit %%C
for /F %%D in ('
forfiles /P "%~dp0." /M "%~nx0" /C "cmd /C echo 0x%%=ExitCode:~-2%%"
') do echo %%D:\
)
This is quite slow though, because there are several cmd instances opened and closed.
To loop through all available drives, including network drives and also such established by subst, you could use the following code, based on wmic:
for /F "skip=1" %%C in ('wmic LogicalDisk get DeviceID') do for /F %%D in ("%%C") do echo %%D\
To loop through all local drives, you could use the following code, again based on wmic:
for /F "skip=1" %%C in ('wmic Volume where "DriveLetter is not Null" get DriveLetter') do for /F %%D in ("%%C") do echo %%D\
To loop through all local drives, but based on mountvol, you could use the following code instead:
for /F %%C in ('mountvol ^| find ":\"') do echo %%C
Finally, for the sake of completeness, to loop through all drives that have been established by subst, use the this code:
for /F "delims=\" %%C in ('subst') do echo %%C\
The best way I found was using WMI
wmic volume get "caption"
gives just the valid drive letters...
Still searching for a way to do it without external tools/libs/modules (like WMI)
To add onto the answer of aschipfl, here is how you can programatically generate a string variable that contains all the alphabet letters for iterating through, (both upper and lower) though its kinda clunky:
#ECHO OFF
setlocal enabledelayedexpansion
FOR /F "tokens=1,2" %%a IN ('ECHO 65 90 ^& ECHO 97 122') DO (
FOR /L %%i IN (%%a,1,%%b) DO (cmd /c exit %%i & set alpha=!alpha! !=exitcodeAscii!))
echo %alpha%
pause
I was working on doing this to use with findstr, but it will work here as well. If you want to only generate the upper or lower letters I'll leave that exercise to the reader.
After generating the string this way you can use the variable in aschipfl's answer above:
for %%p in (%alpha%) do if not exist %%p:\nul set FREEDRIVELETTER=%%p
Here you go, you can iterate through all drives with a for loop now.
#echo off
setlocal enableDelayedExpansion
cls
REM getting the output from fsutil fsinfo drives and putting it in the ogdrives variable
FOR /F "tokens=* USEBACKQ" %%F IN (`fsutil fsinfo drives`) DO (
SET ogdrives=%%F
)
REM making the drives variable the same as the ogdrives variable so it can be manipulated
set drives=!ogdrives!
REM formating the out so that it looks like 1+1+1+... for every drive that is connected
set drives=!drives:Drives^: =!
set drives=!drives:^:\=1!
set drives=!drives: =+!
REM still formating to find out how many drives there are, this bit gets rid of any letters there are
set charms=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
for /L %%N in (10 1 62) do (
for /F %%C in ("!charms:~%%N,1!") do (
set drives=!drives:%%C=!
)
)
REM last for finding out the number, this removes the last characters since it is a leading + that shouldnt be there
set drives=!drives:~0,-1!
REM num is now the variable that contains the number of drives connected
set /a num=!drives!
REM reseting the drives variable to the original output so it can be manipulated again
set drives=!ogdrives!
REM this time it is being formated to list the drives as a solid string of drive letters like ABCD
set drives=!drives:Drives^: =!
set drives=!drives:^:\=!
set drives=!drives: =!
REM this is to iterate through that string of drive letters to seperate it into multiple single letter variables that are correlated to a number so they can be used later
:loop
REM the iter variable holds how many times this has looped so that when it hits the final drive it can exit
set /a iter=!iter!+1
REM the pos variable is the position in the string of drive letters that needs to be taken out for this iteration
set /a pos=!iter!-1
REM this sets the driveX variable where X is the drives correlated number to the letter of that drive from the long string of drive letters by using the pos variable
set drive!iter!=!drives:~%pos%,1!
REM this is checking to see if all drives have been assigned a number and if it has it will exit the loop
if !iter!==!num! goto oloop
goto loop
:oloop
REM drives are stored in variables %driveX% where X represents the drive number
REM the number of drives are stored in the %num% variable
REM below is an example for iterating through drives
REM this is an example of how to use the information gathered to iterate through the drives
REM we are using a for loop from 1 to the number of drives connected
for /L %%n in (1 1 !num!) do (
REM for every drive that is connected this will be ran
REM %%n contains a number which will increase since its a for loop
REM the drive driveX variable can then be used since drive1=A and drive2=B etc
echo drive %%n is !drive%%n!
REM you can see how i have embedded a variable inside a variable to create an array of sorts.
)
pause
exit
REM the actual variable names are drive1 drive2 drive3 but so that we can iterate through them we can just use a for loop and put the number in the variable
REM one way you can use this is with the where command since it will only search one drive at a time
REM you can do this like this
for /L %%n in (1 1 !num!) do (
where /R !drive%%n!:\ *.txt
)
REM this will return a list of all txt files in the entire system since it searches all drives.
I would like help making a batch script to test if there is a certain amount of storage available in a drive in Winodws 7, thanks in advance.
fsutil volume diskfree C: | find /i "avail free"
I had this squirreled away from a previous request.
#echo off
set "low="
for /f "tokens=3" %%a in ('dir c:\ /-p 2^>nul') do set "size=%%a"
for /f "tokens=1-4 delims=," %%a in ("%size%") do (
if "%%d"=="" set low=1
set gb=%%a
set mb=%%b
)
if %gb%%mb% LEQ 2000 set low=1
If defined low (
echo email here with %size%
echo WARNING: Drive C: has %size% free
) else (
echo Drive C: has %gb%.%mb% free GB
)
pause
Can you recommend a way to list files on a WinXP disk that have a total file name (drive+folder+subfolder+filename+ext) greater than some value or MAX_PATH? Ideally this would be in batch or VB script. Thanks in advance.
#echo off
setlocal
if "%~1%~2"=="%~2%~1" (
echo Usage: drive maxlength
echo Example: %0 d: 200
goto :EOF
)
for /F %%A in ('dir /S/B/A:-D "%~d1\*" 2^>nul') do call :chkpath "%%~A" %2
goto :EOF
:chkpath
set #=%~1%
set len=0
:longer
if defined # (set "#=%#:~1%"&set /A len += 1&goto longer)
if %len% GTR %2 echo.%~1
goto :EOF
I would imagine that windows scripting host is faster...