<http://www.netikka.net/tsneti/info/tscmd160.htm>
Copyright © 2003-2010 by Prof. Timo Salmi  
Last modified Thu 15-Apr-2010 11:17:20

 
Assorted NT/2000/XP/.. CMD.EXE Script Tricks
From the html version of the tscmd.zip 1cmdfaq.txt file
To the Description and the Index
 

This page is edited from the 1cmdfaq.txt faq-file contained in my tscmd.zip command line interface (CLI) collection. That zipped file has much additional material, including a number of detached .cmd script files. It is recommended that you also get the zipped version as a companion.

Please see "The Description and the Index page" for the conditions of usage and other such information.




160} How do I get a list of all my folders with and sorted by size?

  @echo off & setlocal enableextensions enabledelayedexpansion
  ::
  :: Set the auxiliary file names

  set temp_=%temp%
  if defined mytemp set temp_=%mytemp%
  set FolderContent=%temp_%\FullContent.dir
  set SizeAndFolder=%temp_%\SizeAndFolder.dir
  set FolderList=%temp_%\FolderList.dir
  ::
  :: Make the folder list

  dir /s /-c "C:\" > "%FolderContent%"
  :: Traverse it
  findstr ".Directory.of. .File(s)." "%FolderContent%">"%SizeAndFolder%"
  set Flag=
  for /f "tokens=* delims= " %%a in (
    'type "%SizeAndFolder%"') do (
      if not defined Flag (
        set Folder=%%a
        set Flag=true
        ) else (
        set Size= %%a
        set Flag=
        echo !Size:~-20! !Folder!>>"%FolderList%"
        )
    )
  ::
  :: Show the result

  sort "%FolderList%"
  call :WarnIfExlamations
  ::
  :: Clean up

  for %%f in ("%FolderContent%" "%SizeAndFolder%" "%FolderList%") do (
    if exist %%f del %%f)
  endlocal & goto :EOF
  ::
  :: ======================================================

  :WarnIfExlamations
  setlocal enableextensions disabledelayedexpansion
  findstr "!" "%SizeAndFolder%">nul
  if %errorlevel% GTR 0 goto :EOF
  echo.
  echo Warning: Folder names with exclamation marks ^(!^) encountered
  endlocal & goto :EOF

The output might end with something like
     242904830 bytes Directory of C:\WINDOWS\system32\dllcache
     359978283 bytes Directory of C:\WINDOWS\$NtServicePackUninstall$
     429340336 bytes Directory of C:\WINDOWS\system32
     497131051 bytes Directory of C:\WINDOWS\ServicePackFiles\i386

Unfortunately, there is the familiar catch. Because of the enabled delayedexpansion any exlamation marks (!) in the names will be dropped.

Note that the solution above gives the size of the immediate folder. That is, the material in the subfolders does not accumulate in the size of a folder. A different answer is gotten with a VBScript-aided solution. If there are any subfolders in a folder, the material in the subfolders is fully included in the upper-level folder's size information. Furthermore, the VBS solution is not affected potential exclamation marks in the folder names.
  @echo off & setlocal enableextensions
  ::
  if "%~1"=="" (echo Usage: %~f0 "[FolderName]"&goto :EOF)
  set debug_=true
  set debug_=
  ::
  :: Build a Visual Basic Script

  set skip=
  set temp_=%temp%
  if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
  set vbs_=%temp_%\tmp$$$.vbs
  >"%vbs_%" findstr "'%skip%VBS" "%~f0"
  ::
  :: Run the script with Microsoft Windows Script Host Version 5.6

  if defined debug_ (
    type "%vbs_%"
    goto _cleanup)
  cscript //nologo "%vbs_%" "%~1"
  ::
  :_cleanup
  for %%f in ("%vbs_%") do if exist %%f del %%f
  endlocal & goto :EOF
  '
  'The Visual Basic Script
  '

  Function FolderSizeFn(folderspec) 'VBS
    Dim fso, f 'VBS
    Set fso = CreateObject("Scripting.FileSystemObject") 'VBS
    Set f = fso.GetFolder(folderspec) 'VBS
    FolderSizeFn = f.size 'VBS
  End Function 'VBS
  '
  Function TraverseSubFolders(StartFolderName) 'VBS
    Dim fso, f, f1, sf 'VBS
    Set fso = CreateObject("Scripting.FileSystemObject") 'VBS
    Set f = fso.GetFolder(StartFolderName) 'VBS
    Set sf = f.SubFolders 'VBS
    For Each f1 in sf 'VBS
      Wscript.Echo PadSpFn(FolderSizeFn(f1),15) & " " & f1 'VBS
      TraverseSubFolders(f1) 'VBS
    Next 'VBS
  End Function 'VBS
  '
  Function TraverseStartFolder(StartFolderName) 'VBS
    Dim fso, f 'VBS
    Set fso = CreateObject("Scripting.FileSystemObject") 'VBS
    Set f = fso.GetFolder(StartFolderName) 'VBS
    Wscript.Echo PadSpFN(FolderSizeFn(f),15) & " " & f 'VBS
  End Function 'VBS
  '
  Function PadSpFn (str, n) 'VBS
    PadSpFn = Right(String(n-1," ")&str,n) 'VBS
  End Function 'VBS ,
  '
  Set arg = WScript.Arguments 'VBS
  TraverseStartFolder(arg(0)) 'VBS
  TraverseSubFolders(arg(0)) 'VBS

An edited example of the output
  C:\_D\TEST>cmdfaq C:\_F\TEXT\ | sort
                0 C:\_F\TEXT\PROFOS
             9770 C:\_F\TEXT\EMAIL
            11264 C:\_F\TEXT\INFO
           339548 C:\_F\TEXT\LIST
           486585 C:\_F\TEXT\PROFLT
           573877 C:\_F\TEXT\OTHERS\PUBLICAT
          2311953 C:\_F\TEXT\BYROK
         12779759 C:\_F\TEXT\OTHERS
         19349999 C:\_F\TEXT

Let's return to the original task of getting with pure script the size of each folder counting only the size of files in it but not below the folder. At the same time avoid the poison character problem. The solution below does these, but it is very slow even on a fast computer.
  @echo off & setlocal enableextensions
  ::
  if "%~1"=="" (echo Usage: %~f0 "[FirstFolderName]"&goto :EOF)
  ::
  set tempdir_=%temp%\temp$$$.dir
  for %%f in ("%tempdir_%") do if exist %%f del %%f
  ::
  call :GetFolderSize "%~1">"%tempdir_%"
  for /f "tokens=*" %%a in ('dir /s /b /a:d "%~1"') do (
    call :GetFolderSize "%%a")>>"%tempdir_%"
  sort "%tempdir_%"
  ::
  for %%f in ("%tempdir_%") do if exist %%f del %%f
  endlocal & goto :EOF
  ::
  :: ====================================================

  :GetFolderSize
  setlocal enableextensions
  for /f "tokens=3" %%a in ('
    dir /-c "%~1"^|find " File(s) "') do (
      call :DisplayFolderInfo "%%a" "%~1")
  endlocal & goto :EOF
  ::
  :: ====================================================

  :DisplayFolderInfo
  setlocal enableextensions
  set var_=               %~1
  set var_=%var_:~-15%
  echo %var_% "%~2"
  endlocal & goto :EOF

The output could be e.g.
  C:\_D\TEST>cmdfaq "C:\_K"
                0 "C:\_K"
                0 "C:\_K\test & dir!"
           370725 "C:\_K\CATEYE"
          1091783 "C:\_K\SCANOHJE"
          2578410 "C:\_K\TOPFIELD\NotOk"
          4228788 "C:\_K\PMAX"
          4875161 "C:\_K\TPLINK"
         10934167 "C:\_K\TOPFIELD"

Not that it makes any difference, but in the above
  ::
  call :GetFolderSize "%~1">"%tempdir_%"
  for /f "tokens=*" %%a in ('dir /s /b /a:d "%~1"') do (
    call :GetFolderSize "%%a")>>"%tempdir_%"
  sort "%tempdir_%"
  ::
could as well be written as
  ::
  call :GetFolderSize "%~1">"%tempdir_%"
  for /r "%~1" %%a in (.) do (
    call :GetFolderSize "%%a")>>"%tempdir_%"
  sort "%tempdir_%"
  ::

References/Comments: (If a Google message link fails try the links within the brackets.)
  Google Groups Apr 27 2007, 7:17 am [M]