Thursday, February 21, 2013

freeing space, move uninstall packs

Any modern version of windows has many, many, updates over the course of its lifetime (2000, xp, vista, 7, etc...).  While you probably knew this already, you may not know that every time you install the windows updates (which are vital to keeping your system secure, and hopefully more stable), there is a folder created which stores some files in case you need to uninstall them.  This folder is under the windows system directory (usually c:\windows), and looks like $NtUninstalllKB######$ where ###### is some 6 digit number (and it may become 7 digits some years from now).

On server 2003, if you keep it up to date these files now take up a little less then a gig worth of space.  For most desktops this isn't an issue especially in an office, unless the person is filling up their hard drive with huge multi-media files.  On our servers at work though, drive C (where we have windows), was for some strange reason set to only 12gigs, and as some of these servers are in remote locations (I support offices in 7 different cities across the state), I can't just re-size the partition, and as it's a 6 year old server still under a support contract, I can't just add a drive, so I have to move whatever I can off of the drive.  There's the usual items of course, uninstall programs you don't need, move unneeded files, clear out the temp directories, empty the recycle bin, etc...., but I needed to be more aggressive, as some things just had to be on drive C that took up a huge amount of space.

If you do some checking, various sites, and Microsoft say that you should be able to remove the $NtUninstalllKB######$ folders, but me being the overly cautious sort, didn't want to just delete them, so I decided I want to move them to a different drive, but also still have windows be able to use them via junctions.  A junction is like a hard link for a directory under linux.  You can have a folder on a drive and you can have multiple junctions that also point to that folder, but as far as any programs are concerned they don't realize it's a junction they went through it just looks like another copy of the folder.

My script will move the $NtUninstalllKB######$ folders from c:\windows to a folder on another ntfs drive on the local machine and then create identical junctions for each of the folders on c:\windows that point to the new location.

Once you've cleared out a good amount of space on your drive, check out my script to alert you before you run out of space.  

You will need the sysinternals tool junction.exe
about junctions:

about the $NTUninstallKB##### folders

rem ----------------------script starts here-------------

@echo off

rem this is meant to make room on drive c for older servers
rem that have drive c be too small, but other drives where
rem drive c files can be moved to.

set junexe=d:\mis\single-progs\junction.exe
if not exist %junexe% goto error
rem no trailing backslash
set dstloc=e:\windows
if not exist %dstlock% goto error

echo processing %computername% at %date% %time%

rem extract current month, year, date, etc...
for /f "tokens=2" %%W in ('date /t') do set dater=%%W
rem for /f "tokens=1,2 delims=:" %%t in ('echo %time%') do set timer=%%t:%%u
for /f "tokens=1-3 delims=/" %%d in ('echo %dater%') do set curdate=%%f%%d%%e
for /f "tokens=3 delims=/" %%y in ('echo %dater%') do set curyear=%%y
for /f "tokens=1-3 delims=/" %%d in ('echo %dater%') do set curmonth=%%d
for /f "tokens=1-3 delims=/" %%d in ('echo %dater%') do set DOMC=%%e
rem only if the current month is february or later do we compute the last month
rem and set the lastmonth variable to year.
if %curmonth% GTR 1 set /a lastmonth=%curmonth% - 1
if "%curmonth%" == 01 set lastmonth=year
rem if the lastmonth is before november, add a zero in front of it
if %lastmonth% LSS 10 set lastmonth=0%lastmonth%


rem uninstall packs, take up almost 1gb on the server when uncompressed (compression can only do so much).

if exist %temp%\ntupdateuninstalls.lst del %temp%\ntupdateuninstalls.lst
for /f "tokens=5" %%d in ('dir /a:d c:\windows\?NtUninstallKB* ^|find /v "JUNCTION" ^|find /v "%curyear%"') do echo %%d >> %temp%\ntupdateuninstalls.lst
if "%lastmonth%" == "year" goto copyandlink
rem if we're in january just do last years stuff.
rem if we're in a latter month and it's less then 10 days into the current month, we don't want to move
rem last month's items, otherwise we'll move everything except for this months.

if %curdate% LSS 10 for /f "tokens=5" %%d in ('dir /a:d c:\windows\?NtUninstallKB* ^|find /v "JUNCTION" ^|find /i "%curyear%" ^|find /v "%curmonth%" ^|find /v "%lastmonth%"') do echo %%d >> %temp%\ntupdateuninstalls.lst

if %curdate% GEQ 10 for /f "tokens=5" %%d in ('dir /a:d c:\windows\?NtUninstallKB* ^|find /v "JUNCTION" ^|find /i "%curyear%" ^|find /v "%curmonth%"') do echo %%d >> %temp%\ntupdateuninstalls.lst


for /f %%l in ('type %temp%\ntupdateuninstalls.lst') do robocopy c:\windows\%%l %dstloc%\%%l /e /z /move

for /f %%l in ('type %temp%\ntupdateuninstalls.lst') do %junexe% c:\windows\%%l %dstloc%\%%l

rem for /f %%l in ('type %temp%\ntupdateuninstalls.lst') do compact /c %dstloc%\%%1

del %temp%\ntupdateuninstalls.lst
echo finished at %time%
goto end

echo you need to have junction.exe from sysinternals, and set
echo the junexe variable to point to the file, currently it's %junexe%
if exist %dstloc% goto end
echo make sure that you create a destination folder (perferably on a different drive
echo on a separate drive from your windows install) and set the dstloc variable
echo to reflect that location, currently it's %dstloc%
echo make sure to not end with a backslash
set /p mkdstloc=should I try to create %dstloc% (y/n):
if /i "%mkdstloc%" == "y" mkdir %dstloc%


rem ----------------------script ends here-------------

1 comment:

  1. I liked ur blog. Very nice. Keep it up