Frag Out!

When it comes to sluggish hard drives, this handy script will help keep you moving.

I’ve been spending a fair chunk of my weekends playing Xbox’s premier game, Halo, when I should be changing the car’s oil or walking the dog. In Halo, whenever one of your Marines throws a fragmentation grenade, he announces it by yelling “Frag out,” thus giving you time to avoid the blast. What better lead for a column in which the featured script is one that defragments your hard drives? Besides, who among us hasn’t been tempted, on occasion, to drop a grenade on a server that’s grinding to a slow crawl due to a fragmented drive?

Pull Pin…Take Cover
A fragmented drive can cause more problems than simply slow read/write performance. For starters, the drive hardware has to work harder to retrieve and write data. In extreme cases, this can shorten the life of your hard drive. Furthermore, fragmented data takes up more drive space due to disk cluster sizes. The larger the drive and the larger each cluster, the more space is wasted. While using NTFS and dynamic disks can mitigate these issues somewhat, there’s still no substitute for keeping fragmented files to a minimum. The following script will defrag every drive on the computer and record the status of each defrag operation in a log file, thus enabling you to take the “frag out.” (See, I told you I’d make the connection!)

<?xml version="1.0" ?>
<package>
<comment>
DefragDrives.wsf
This script runs the command-line DEFRAG utility via the WScript.Shell object on each drive of the local computer
</comment>

<job>
   <runtime>
      <description>

      This script defragments all local drives
      </description>
      <example>

      C:\CScript DefragDrives /LogFile:[path and filename]
      </example>
      <named

      name="LogFile"
      helpstring="The path and filename to write
      the defrag report"
      type="string"
      required="true"
      />
      </runtime>
      <object id=
"objShell" progid="WScript.Shell"/>
      <object id=
"objFSO" progid="Scripting.FileSystemObject"/>
      <script language=
"VBScript">
      <![CDATA[
      Option Explicit Dim colDrives, clsDrive, objFile,
      sLogFile, iReturn
      sLogFile=WScript.Arguments.Named.Item("LogFile")
      Set colDrives = objFSO.Drives

      'Open the log file and enter the date/time
      Set objFile = objFSO.OpenTextFile(sLogFile, 8, True)
      objFile.WriteLine
      objFile.WriteLine Date & " " & Time & vbCRLF
      objFile.Close

      For Each clsDrive in colDrives
         If clsDrive.DriveType = 2 Then '2=Fixed drive
             iReturn = objShell.Run("defrag " & clsDrive
             & " -f", 1, TRUE)

      'Open the file and write the defrag report
      Set objFile = objFSO.OpenTextFile(sLogFile, 8, True)
      Select Case iReturn 'Get the return value
         Case 0
            objFile.WriteLine "Drive " & clsDrive
            & " Successfully defragmented."
         Case 1
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag can celled manually."
         Case 2
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag failed! Command-line error!"
         Case 4
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag Failed! Insufficient memory!"
         Case 6
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag failed! System error!"
         Case 7
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag failed! Insufficient drive space!"
         Case Else
            objFile.WriteLine "Drive " & clsDrive
            & " Defrag failed! Unknown error!"
         End Select
            objFile.Close
         End If
      Next
      ]]>

      </script>
   </job>
</package>

The Select Case section skips a couple of numbers, namely, 3 and 5. These return codes both correspond to “Unknown Errors.” By structuring the Select Case section as we have, these (and any other return codes not already specified) will be picked up by the “Case Else” line, and the script will notify you that it experienced an “Unknown Error.” No need to explicitly check for every possible return code.

Those of you who’ve followed this column for any length of time know that my philosophy is to use the simplest method possible to accomplish the task at hand. In this case, I’m combining the organizational strength of the Windows Script Host with the efficiency of the defrag command-line utility. The result is quite a nice little script that can be scheduled to run overnight on any or all of your servers to keep drive hardware humming and disk performance high.

Because the bulk of the functionality comes from shelling to the command line and running defrag, I chose to only open the log file when I had something to write to it. Ordinarily, I wouldn’t keep opening and closing a file over the course of a script. However, because the defrag operation can take hours for each drive, I didn’t want to leave this file open.

The defrag utility returns a value to the shell object after defragmentation is complete (or fails). I then use a Select Case statement to determine the result of the operation and write the data to the log file. This occurs for every fixed drive connected to the computer—floppies, CD-ROMS, removable drives, network shares and RAM disks are skipped.

To run this script, simply type this at the command line:

Cscript DefragDrives.wsf /LogFile:c:\logfilename.txt

Over the next few months, I’m going to feature scripts that were created as a direct result of e-mails I’ve received from readers asking me to show them how to accomplish a specific task. Most of the topics will be based upon those e-mails, but there’s still time to make requests. Just put “Scripting” in the subject line and send them my way.

Featured