Tuesday, 28 September 2010

How to create a script to automatically sort your files into folders based on creation date...

Ok – on to another script... and this one is sweet and simple. This script performs a filing task on files by date i.e. it will get all the files in a directory and move them into folders based on their date.

I have gone for the following file structure:

.\YYYY\MM\DD\my_file_n.file

Please note that this script has been tested for Windows 2003 Server ONLY (see previous post for determining version numbers) and may not work on your target system without some minor tweaking!

Right – onto the meat... first we have to loop through all the files in the directory (I have specified .XML files only) and extract the name (%%~x) and the timestamp (%%~tx):

for %%x in (*.xml) do call :File_File "%%~tx" "%%~x"

The next bit (as you can see above from the call to the method File_File) is to pass these to a procedure to parse the date, create the directory and move the file:

First we will have to extract the date parts (this is where your OS version or Date locale may trip you up – tweak as needed!) – you can see we specify the delimiters as ‘:’ and ’/’ to split the timestamp into the bits we need and then assign them to variables from the resulting 5 part array using the ‘%%a’ (first element) to ‘%%e’ (fifth element):


for /f "tokens=1-5 delims=/: " %%a in (%1) do set year=%%c&set month=%%b&set day=%%a&set hour=%%d&set minute=%%e

We then build the variable containing the file path where the file will be stored:

Set FilePath=%year%\%month%\%day%

We check to see if it exists and create it if not:

IF NOT EXIST %FilePath% MD %FilePath%

Then move the file:

move %2 "%FilePath%\%2"

Simples!



How to determine what version of Windows you are running...

Now, this can be important if, for instance, you need to do some parsing functions ‘in script’ based on OS specific environment variables and/or formats. For instance – ‘%date%’ formats can differ as can ‘%%~t’ type extractions (but we’ll go into examples of that later).

Anyway – a good place to start is the ‘ver’ command – this will return a string that essentially contains the OS name and version number in three parts namely Major Version, Minor Version and Build Number in the format:

Microsoft Windows XX [Version X.X.XXXX]

Here is an overview of the most common:

Windows 1.01.04
Windows 2.02.11
Windows 3.03
Windows NT 3.13.10.528
Windows for Workgroups 3.113.11
Windows NT Workstation 3.53.5.807
Windows NT Workstation 3.513.51.1057
Windows 954.0.950
Windows NT Workstation 4.04.0.1381
Windows 984.1.1998
Windows 98 Second Edition4.1.2222
Windows Me4.90.3000
Windows 2000 Professional5.0.2195
Windows XP5.1.2600Current SP3
Windows XP Professional x64 Edition5.2.3790
Windows Vista6.0.60006.0.6002 with SP2
Windows 76.1.7600


Happy days; we can just do the following then:

:search_ver
ver find "XP" > nul
if %ERRORLEVEL% == 0 goto win_xp_specific

ver find "2000" > nul
if %ERRORLEVEL% == 0 goto win_2000_specific

ver find "NT" > nul
if %ERRORLEVEL% == 0 goto win_nt_specific

ver find "98" > nul
if %ERRORLEVEL% == 0 goto win_98_specific

...etc...

goto win_unknown_specific


Now there is a trap here... you may have noticed that there are no Windows Server version numbers in that list – and this is the bitch – the ‘ver’ command will not return a full name for Windows OS’s from 2003 and above. And some of them share both major and minor versions with other Windows OS’s i.e. a ver command executed on a Windows Server 2003 machine might return the following:

Microsoft Windows [Version 5.5.3790]

Here is a list of Windows OS’s from 2003 and above with their Major and Minor version numbers:


Windows 76.1
Windows Server 2008 R26.1
Windows Server 20086.0
Windows Vista6.0
Windows Server 2003 R25.2
Windows Server 20035.2
Windows XP 64Bit Edition5.2
Windows XP5.1
Windows 20005.0


Of course you could map out all the build numbers in your batch file... but this would be a dark task to research indeed – and ultimately pointless as it reveals more information that we would ever need with regards to batch scripting.

So – the only way to get correct version information in a batch script for Windows versions of 2003 and above is to do the following (and I apologise to whomever I nicked this from – but, alas, batch script programming is a ‘lost art’ and we must nick and patch together as we go); we have to use the sysinfo utility on systems of 2003 and above:

%SystemRoot%\system32\systeminfo.exe

Note: The sysinfo utility may not exist in earlier versions so you may also want to check it exists first:

if not exist %SystemRoot%\system32\systeminfo.exe goto :search_ver

This will either continue to the next bit (below) or redirect your script to the ‘ver’ command (as above). The next bit we have to do is extract the “OS Name” line from the output of the sysinfo utility... we do this by first dumping it to a temporary file:

systeminfo | find "OS Name" > %TEMP%\OSNAME.TMP

And then parsing the file with the ‘:’ delimiter to extract the exact text we want into the ‘osname’ variable:

FOR /F "usebackq delims=: tokens=2" %%i IN (%TEMP%\OSNAME.TMP) DO set osname=%%i

We can then scan this variable for our operating system by name i.e.:

echo %osname% find "Windows 7" > nul
if %ERRORLEVEL% == 0 goto win_7_specific

echo %osname% find "Windows Server 2008" > nul
if %ERRORLEVEL% == 0 goto win_2008_specific

echo %osname% find "Windows Vista" > nul
if %ERRORLEVEL% == 0 goto win_vista_specific

echo %osname% find "2003" > nul
if %ERRORLEVEL% == 0 goto win_2003_specific

...etc...

goto win_unknown_specific


Hope this helps!



Welcome

Hello,

This is not really a blog but a resource for me to store some cunning batch scripts. I am a systems developer who has been in the industry for 20 years. When I first started batch scripts were something that we all knew how to do... but alas my skills have rusted.

There are many experts out there - and this is not for you. This is more of a "Noddy's Guide" to batch scripting with examples of some useful ones put here as and when I have to make them.

I find that the same problems present themselves over and over and I have to continually re-invent the wheel with regards to writing scripts - hopefully this 'blog' will save me (and others googling for that elusive script) some time in the long run...