Iterate over disks and output the size and space - windows

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>

Related

Bat file that copy text.files after applying 2 filters

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
)
)

Batch File to execute all .exe in a folder with count

I have quite a few exe files, I want to run them with a single batch file. As far as I understand, these two codes work for me;
for %%a in ("\*.exe") do start "" "%%\~fa"
for %%i in (\*.exe) do start "" /b "%%i"
But that cmd screen closes when all files are run. What I want is this: That cmd screen will not close when the process is finished and will show me the result (counting if possible), a code that can count how many of these .exe files work and how many fail.
So for example;
87 files blocked
13 files could not be blocked
Something like this? Is this possible?
Maybe you can get an inspiration from this batch below. It works through program exit code. It spawns all executable, wait for their completion, then count how much failed / succeeded.
It should also work with well-designed GUI program, not only command-line based ones.
It's a rough/basic answer, you may need to refine it according to your exact needs.
#echo off
setlocal enableextensions enabledelayedexpansion
REM Use marker files for getting results.
set OK_EXT=.SUCCESS
set FAIL_EXT=.FAILURE
REM Purge all possible marker files.
del /q *!OK_EXT! *!FAIL_EXT! > NUL 2>&1
set /a count=0
REM Parse all executables
for %%E in (*.exe) do (
echo Launching: %%~nxE
REM Create two marker files for each executable.
echo.>%%~nE!OK_EXT!
echo.>%%~nE!FAIL_EXT!
REM Start the executable, delete the WRONG marker.
REM I would have prefered to use "touch" to create the good one instead, but not standard on Windows.
start %comspec% /C "%%~nxE && ( del /q %%~nE!FAIL_EXT! ) || ( del /q %%~nE!OK_EXT! )"
set /a count +=1
)
REM Now, "count" contains the number of executables launched.
echo All processes launched.
echo.
:loop
echo Waiting for results...
set /a curr=0
REM Simply count the number of marker files. Must be equal to "count" when everything is finished.
for /F "usebackq tokens=*" %%C in (`dir /b *!OK_EXT! *!FAIL_EXT!`) do (
set /A curr+=1
)
if !curr! GTR !count! (
set /a curr-=!count!
echo Still !curr! processes running...
timeout /t 2
goto :loop
)
echo All results found.
echo.
echo Parsing results...
set /a ok_exe=0
set ok_exe_list=
set /a fail_exe=0
set fail_exe_list=
REM Parse all marker files.
for /F "usebackq tokens=*" %%C in (`dir /b *!OK_EXT! *!FAIL_EXT!`) do (
REM And set counters + list according to the marker file type (OK or FAILED).
if /I "%%~xC"=="!OK_EXT!" (
set /A ok_exe+=1
set ok_exe_list=!ok_exe_list! %%~nC
) else (
set /A fail_exe+=1
set fail_exe_list=!fail_exe_list! %%~nC
)
)
REM Simple display.
echo Programs without error: !ok_exe!/!count!
echo !ok_exe_list!
echo.
echo Programs with error: !fail_exe!/!count!
echo !fail_exe_list!
echo.
goto :eof

Windows Script to replace windows lock screen picture with random photo

The Issue: Group policies don;t allow me to change the lock screen to slideshow or spotlight but i am local admin on the pc and by replacing C:\Windows\Web\Screen\Screen.jpg i can change the lock screen picture.
Solution: create a batch/CMD/PS script that runs every xx minutes and copies a random picture from a source folder to replace C:\Windows\Web\Screen\Screen.jpg
i found a possible script in this article that could work but how do i modify it for my purpose and if i schedule it in task scheduler to run every 30 minutes would a Batch file run in the background without interference or would a CMD script or Powershell script be a better solutions?
see code below:
#echo off & setlocal
set "workDir=C:\source\folder"
::Read the %random%, two times is'nt a mistake! Why? Ask Bill.
::In fact at the first time %random% is nearly the same.
#set /a "rdm=%random%"
set /a "rdm=%random%"
::Push to your path.
pushd "%workDir%"
::Count all files in your path. (dir with /b shows only the filenames)
set /a "counter=0"
for /f "delims=" %%i in ('dir /b ^|find "."') do call :sub1
::This function gives a value from 1 to upper bound of files
set /a "rdNum=(%rdm%*%counter%/32767)+1"
::Start a random file
set /a "counter=0"
for /f "delims=" %%i in ('dir /b ^|find "."') do set "fileName=%%i" &call :sub2
::Pop back from your path.
popd "%workDir%"
goto :eof
:: end of main
:: start of sub1
:sub1
::For each found file set counter + 1.
set /a "counter+=1"
goto :eof
:: end of sub1
:: start of sub2
:sub2
::1st: count again,
::2nd: if counted number equals random number then start the file.
set /a "counter+=1"
if %counter%==%rdNum% (
:: OUTPUT ALERT BOX with FILENAME
MSG * "%fileName%"
)
goto :eof
:: end of sub2
IMO PowerShell is by far superior to batch in this case
dir C:\source\folder\*.jpg |Get-Random|Copy -Dest C:\Windows\Web\Screen\Screen.jpg -Force
You might wrap it in a batch/cmd line
powershell -Nop -C "dir C:\source\folder\*.jpg |Get-Random|Copy -Dest C:\Windows\Web\Screen\Screen.jpg -Force"

Need a batch file or a shell file that will take the current calendar month, and make directories for each day.

this is my first time posting on here, so I apologize if I do something wrong.
I need a batch file or a shell file that I can run at the beginning of the month to make directories with folder names in the following format YYYYMMDD for every day of that month. So essentially I will have a folder called (Let's use an example here and just say reports.
Inside the reports folder I need folders 20140901 20140902 all through the calendar month.
So far I have this code:
echo var D = new Date() > tmp.js
echo D = (D.getFullYear()*100+D.getMonth()+1)*100+D.getDate() >> tmp.js
echo WScript.Echo( 'set YYYYMMDD='+D ) >> tmp.js
echo #echo off > tmp.bat
cscript //nologo tmp.js >> tmp.bat
call tmp.bat
mkdir %YYYYMMDD%
I get that you can make a folder based on the local date as well, however I am not sure the logic required to tell it to "skip ahead until 10/1/2014.
Any help would be greatly appreciated.
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /f "tokens=1-3delims=./- " %%a IN ("%date%") DO (
CALL :SETsz yy %%c
CALL :SETsz mm %%b
)
IF %yy% lss 2000 SET /a yy+=2000
SET cdate=31
FOR %%a IN (2 2 2 4 6 9 11) DO IF %%a==%mm% SET /a cdate-=1
SET /a cdate=((%yy%*100)+%mm%)*100+%cdate%
SET /a yy=%yy% %% 4
IF %yy%%mm%==02 SET /a cdate+=1
FOR /L %%a IN (1%cdate:~-2%,-1,101) DO ECHO(MD reports\!cdate!&SET /a cdate-=1
GOTO :EOF
:setsz
SET cdate=%2
IF %cdate:~0,1%==0 (SET %1=%cdate:~1%) ELSE (SET %1=%2)
GOTO :eof
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
This is made way more complex because you haven't told us which particular date format you use. It should work with any separator, but I used my format dd/mm/yyyy for testing. If you use suppressed-leading-zero or two-digit years, it should work as-is.
If you use a leading dayname, then tokens will need to be changed to 2-4 in place of 1-3. The particular fields %%b and %%c used in the first for "loop" would need to be %%a, %%b or %%c depending on the sequence you use in your date format.
You can test the routine by using
set date=1/02/2012
(for example) in the line directly before the "FOR /f ..." line. Normally, I'd warn against attempting to change date as it's a "magic variable" established by the system and overriding it can cause chaos. In this case however, it follows a setlocal command, so the date-override inserted will be backed out when the routine ends; hence it's safe during testing.
The first four lines of this code will give you reliable YY DD MM YYYY HH Min Sec variables in XP Pro and higher.
The for loop will simply make 31 folders for that year and month when it is run.
#echo off
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
for /L %%a in (1,1,31) do if %%a LSS 10 (md %YYYY%%MM%0%%a) else (md %YYYY%%MM%%%a)
pause
Magoo your answer worked. I really appreciate it.
Here is what I finally ended up using.
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /f "tokens=2-4delims=./- " %%a IN ("%date%") DO (
CALL :SETsz yy %%c
CALL :setsz mm %%a
)
IF %yy% lss 2000 SET /a yy+=2000
SET cdate=31
FOR %%a IN (2 2 2 4 6 9 11) DO IF %%a==%mm% SET /a cdate-=1
SET /a cdate=((%yy%*100)+%mm%)*100+%cdate%
SET /a yy=%yy% %% 4
IF %yy%%mm%==02 SET /a cdate+=1
FOR /L %%a IN (1%cdate:~-2%,-1,101) DO MD C:\Users\spoling\Desktop\!cdate!&SET /a cdate-=1
GOTO :EOF
:setsz
SET cdate=%2
IF %cdate:~0,1%==0 (SET %1=%cdate:~1%) ELSE (SET %1=%2)
GOTO :eof

Disk size in Windows for particular drive

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

Resources