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!
@ECHO OFF
for %%x in (*.xml) do call :File_File "%%~tx" %%~x pause goto :eof
:File_File
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
Set FilePath=%year%\%month%\%day%
IF NOT EXIST %FilePath% MD %FilePath% move %2 "%FilePath%\%2"
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.0
1.04
Windows 2.0
2.11
Windows 3.0
3
Windows NT 3.1
3.10.528
Windows for Workgroups 3.11
3.11
Windows NT Workstation 3.5
3.5.807
Windows NT Workstation 3.51
3.51.1057
Windows 95
4.0.950
Windows NT Workstation 4.0
4.0.1381
Windows 98
4.1.1998
Windows 98 Second Edition
4.1.2222
Windows Me
4.90.3000
Windows 2000 Professional
5.0.2195
Windows XP
5.1.2600
Current SP3
Windows XP Professional x64 Edition
5.2.3790
Windows Vista
6.0.6000
6.0.6002 with SP2
Windows 7
6.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 7
6.1
Windows Server 2008 R2
6.1
Windows Server 2008
6.0
Windows Vista
6.0
Windows Server 2003 R2
5.2
Windows Server 2003
5.2
Windows XP 64Bit Edition
5.2
Windows XP
5.1
Windows 2000
5.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.:
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...