VBScript: Analyze Volume Defragmentation


Hi there,

I found this script at:
http://www.activexperts.com/activmonitor/windowsmanagement/scripts/storage/diskdrives/physical/#AVD.htm

But it does'nt work.

This script will run on a Windows 2003 server and XP.

It analyzes the defragmentation status of all the volumes on a computer. This is equivalent to running defrag.exe with the command-line options -a (analyze) and -v (verbose).

Thanks for your help,
Rene
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colVolumes = objWMIService.ExecQuery("Select * from Win32_Volume")

For Each objVolume in colVolumes
    errResult = objVolume.DefragAnalysis(blnRecommended, objReport)
    If errResult = 0 then
        Wscript.Echo "Average file size: " & objReport.AverageFileSize
        Wscript.Echo "Average fragments per file: " & _
            objReport.AverageFragmentsPerFile
        Wscript.Echo "Cluster size: " & objReport.ClusterSize
        Wscript.Echo "Excess folder fragments: " & _
            objReport.ExcessFolderFragments
        Wscript.Echo "File percent fragmentation: " & _
            objReport.FilePercentFragmentation
        Wscript.Echo "Fragmented folders: " & objReport.FragmentedFolders
        Wscript.Echo "Free soace: " & objReport.FreeSpace
        Wscript.Echo "Free space percent: " & objReport.FreeSpacePercent
        Wscript.Echo "Free space percent fragmentation: " & _
            objReport.FreeSpacePercentFragmentation
        Wscript.Echo "MFT percent in use: " & objReport.MFTPercentInUse
        Wscript.Echo "MFT record count: " & objReport.MFTRecordCount
        Wscript.Echo "Page file size: " & objReport.PageFileSize
        Wscript.Echo "Total excess fragments: " & _
            objReport.TotalExcessFragments
        Wscript.Echo "Total files: " & objReport.TotalFiles
        Wscript.Echo "Total folders: " & objReport.TotalFolders
        Wscript.Echo "Total fragmented files: " & _
            objReport.TotalFragmentedFiles
        Wscript.Echo "Total MFT fragments: " & objReport.TotalMFTFragments
        Wscript.Echo "Total MFT size: " & objReport.TotalMFTSize
        Wscript.Echo "Total page file fragments: " & _
            objReport.TotalPageFileFragments
        Wscript.Echo "Total percent fragmentation: " & _
            objReport.TotalPercentFragmentation
        Wscript.Echo "Used space: " & objReport.UsedSpace
        Wscript.Echo "Volume name: " & objReport.VolumeName
        Wscript.Echo "Volume size: " & objReport.VolumeSize       
        If blnRecommended = True Then
           Wscript.Echo "This volume should be defragged."
        Else
           Wscript.Echo "This volume does not need to be defragged."
        End If
        Wscript.Echo
    End If
Next

Open in new window

LVL 10
ReneGeAsked:
Who is Participating?
 
RobSampsonConnect With a Mentor Commented:
Sure, run this with
cscript DefragStats.vbs

Regards,

Rob.
strComputer = "."
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const intForReading = 1
Set objShell = CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strTempFile = objFSO.GetFolder(Replace(WScript.ScriptFullName, WScript.ScriptName, "")).ShortPath & "DefragOutputTemp.txt"
Set colDrives = objWMIService.ExecQuery("SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType='3'")
WScript.Echo "Drive,Size,Free,Fragmentation,File Fragmentation"
For Each objDrive In colDrives
	strCommand = "cmd /c defrag " & objDrive.DeviceID & " -a > " & strTempFile
	objShell.Run strCommand, 0, True
	Set objDefrag = objFSO.OpenTextFile(strTempFile, intForReading, False)
	While Not objDefrag.AtEndOfStream
		strLine = objDefrag.ReadLine
		If InStr(strLine, "Fragmented") > 0 Then
			intSize = InStr(strLine, "Total,")
			strSize = Trim(Left(strLine, intSize + 4))
			intFree = InStr(strLine, "Free,")
			strFree = Trim(Mid(strLine, intSize + 7, (intFree + 4) - (intSize + 7)))
			strFragmented = Trim(Mid(strLine, intFree + 6))
			intPos = InStr(strFragmented, "(")
			If intPos > 0 Then
				strFileFragmented = Mid(strFragmented, intPos + 1)
				strFileFragmented = Trim(Left(strFileFragmented, Len(strFileFragmented) - 1))
				strFragmented = Trim(Left(strFragmented, intPos - 1))
			Else
				strFileFragmented = ""
			End If
			WScript.Echo objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
		ElseIf InStr(strLine, "this volume") > 0 Then
			WScript.Echo strLine
		End If
	Wend
	objDefrag.Close
	objFSO.DeleteFile strTempFile, True
Next

Open in new window

0
 
Psy053Commented:
Hey Rene,

The methods in the above script are the same as the ones I used to report Total Percentage Fragmentation and File PercentageFragmentation in the DiskSpace.VBS from your last question.

As per that previous script though, it will NOT work with XP, this is because the Win32_Volume Class was not available on XP and earlier.
0
 
ReneGeAuthor Commented:
Hey Psy,

It seems that I asked the wrong question.

Could there be another way to get fragmentation infos? Like maybe running Defrag.exe /A /V in the VBScript and capturing the infos?

Thanks,
Rene
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
RobSampsonCommented:
On XP, you will need to run
defrag c: -a > DefragAnalysis.txt

Regards,

Rob.
0
 
RobSampsonCommented:
Something like this would capture it.

Regards,

Rob.
Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec("defrag c: -a -v")
While objExec.Status
	WScript.Sleep 100
Wend
strDetails = objExec.StdOut.ReadAll
WScript.Echo strDetails

Open in new window

0
 
ReneGeAuthor Commented:
Thanks Rob,

Can this script:
-Get the info on all local drives
-Parse the data so I can get the output as:
Drive,FileFragmentation,TotalFragmentation

Thanks again,
Rene
0
 
RobSampsonCommented:
OK, this should work.

Regards,

Rob.
strComputer = "."
strOutput = "C:\Temp\Temp\Test Script\DefragReport.csv"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const intForReading = 1
Set objShell = CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strTempFile = objFSO.GetFolder(Replace(WScript.ScriptFullName, WScript.ScriptName, "")).ShortPath & "DefragOutputTemp.txt"
Set colDrives = objWMIService.ExecQuery("SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType='3'")
Set objOutput = objFSO.CreateTextFile(strOutput, True)
objOutput.WriteLine "Drive,Size,Free,Fragmentation,File Fragmentation"
For Each objDrive In colDrives
	strCommand = "cmd /c defrag " & objDrive.DeviceID & " -a > " & strTempFile
	objShell.Run strCommand, 0, True
	Set objDefrag = objFSO.OpenTextFile(strTempFile, intForReading, False)
	While Not objDefrag.AtEndOfStream
		strLine = objDefrag.ReadLine
		If InStr(strLine, "Fragmented") > 0 Then
			strSize = Trim(Split(Trim(strLine), ",")(0))
			strFree = Trim(Split(Trim(strLine), ",")(1))
			strFragmented = Split(Trim(strLine), ",")(2)
			strFileFragmented = Mid(strFragmented, InStr(strFragmented, "(") + 1)
			strFileFragmented = Trim(Left(strFileFragmented, Len(strFileFragmented) - 1))
			strFragmented = Trim(Left(strFragmented, InStr(strFragmented, "(") - 1))
			'WScript.Echo objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
			objOutput.WriteLine objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
		ElseIf InStr(strLine, "this volume") > 0 Then
			objOutput.WriteLine strLine
		End If
	Wend
	objDefrag.Close
	objFSO.DeleteFile strTempFile, True
Next
objShell.Run "excel """ & strOutput & """"

Open in new window

0
 
ReneGeAuthor Commented:
Rob,

Your script works, however, I get the following error message.

Many thanks and cheers,
Rene
ErrorMessage.png
0
 
RobSampsonCommented:
Slightly odd.....what is the output of the command when you run
defrag c: -a

Mine is

Analysis Report                         
    37.21 GB Total,  6.10 GB (16%) Free,  16% Fragmented (32% file fragmentation)

You should defragment this volume.


The error you get suggests there is no (XXX file fragmentation) section.

Regards,

Rob.
strComputer = "."
strOutput = "C:\Temp\Temp\Test Script\DefragReport.csv"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const intForReading = 1
Set objShell = CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strTempFile = objFSO.GetFolder(Replace(WScript.ScriptFullName, WScript.ScriptName, "")).ShortPath & "DefragOutputTemp.txt"
Set colDrives = objWMIService.ExecQuery("SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType='3'")
Set objOutput = objFSO.CreateTextFile(strOutput, True)
objOutput.WriteLine "Drive,Size,Free,Fragmentation,File Fragmentation"
For Each objDrive In colDrives
	strCommand = "cmd /c defrag " & objDrive.DeviceID & " -a > " & strTempFile
	objShell.Run strCommand, 0, True
	Set objDefrag = objFSO.OpenTextFile(strTempFile, intForReading, False)
	While Not objDefrag.AtEndOfStream
		strLine = objDefrag.ReadLine
		If InStr(strLine, "Fragmented") > 0 Then
			strSize = Trim(Split(Trim(strLine), ",")(0))
			strFree = Trim(Split(Trim(strLine), ",")(1))
			strFragmented = Split(Trim(strLine), ",")(2)
			intPos = InStr(strFragmented, "(")
			If intPos > 0 Then
				strFileFragmented = Mid(strFragmented, intPos + 1)
				strFileFragmented = Trim(Left(strFileFragmented, Len(strFileFragmented) - 1))
				strFragmented = Trim(Left(strFragmented, intPos - 1))
			Else
				strFileFragmented = ""
			End If
			'WScript.Echo objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
			objOutput.WriteLine objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
		ElseIf InStr(strLine, "this volume") > 0 Then
			objOutput.WriteLine strLine
		End If
	Wend
	objDefrag.Close
	objFSO.DeleteFile strTempFile, True
Next
objShell.Run "excel """ & strOutput & """"

Open in new window

0
 
ReneGeAuthor Commented:
I have a drive of 2.7TB. It's output is 2,795 GB

Therefore, since there is a ","  may I assume it may interfere with the parsing?

Thanks,
Rene
0
 
ReneGeAuthor Commented:
FYI: With your last modified script, I did not get the 800A0005 error.
0
 
RobSampsonCommented:
Yes, that is correct......in that case, I'll change the way it's parsing....
0
 
Psy053Connect With a Mentor Commented:
I've modified the previous script that I gave you so that it will detect XP or lower, and then use Defrag.exe to get the File Fragmentation and Total Fragmentation values
DiskSpace.vbs
0
 
RobSampsonCommented:
This should work now.

Regards,

Rob.
strComputer = "."
strOutput = "C:\Temp\Temp\Test Script\DefragReport.csv"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const intForReading = 1
Set objShell = CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strTempFile = objFSO.GetFolder(Replace(WScript.ScriptFullName, WScript.ScriptName, "")).ShortPath & "DefragOutputTemp.txt"
Set colDrives = objWMIService.ExecQuery("SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType='3'")
Set objOutput = objFSO.CreateTextFile(strOutput, True)
objOutput.WriteLine "Drive,Size,Free,Fragmentation,File Fragmentation"
For Each objDrive In colDrives
	strCommand = "cmd /c defrag " & objDrive.DeviceID & " -a > " & strTempFile
	objShell.Run strCommand, 0, True
	Set objDefrag = objFSO.OpenTextFile(strTempFile, intForReading, False)
	While Not objDefrag.AtEndOfStream
		strLine = objDefrag.ReadLine
		If InStr(strLine, "Fragmented") > 0 Then
			intSize = InStr(strLine, "Total,")
			strSize = Trim(Left(strLine, intSize + 4))
			intFree = InStr(strLine, "Free,")
			strFree = Trim(Mid(strLine, intSize + 7, (intFree + 4) - (intSize + 7)))
			strFragmented = Trim(Mid(strLine, intFree + 6))
			intPos = InStr(strFragmented, "(")
			If intPos > 0 Then
				strFileFragmented = Mid(strFragmented, intPos + 1)
				strFileFragmented = Trim(Left(strFileFragmented, Len(strFileFragmented) - 1))
				strFragmented = Trim(Left(strFragmented, intPos - 1))
			Else
				strFileFragmented = ""
			End If
			'WScript.Echo objDrive.DeviceID & VbCrLf & strSize & VbCrLf & strFree & VbCrLf & strFragmented & VbCrLf & strFileFragmented
			objOutput.WriteLine objDrive.DeviceID & "," & strSize & "," & strFree & "," & strFragmented & "," & strFileFragmented
		ElseIf InStr(strLine, "this volume") > 0 Then
			objOutput.WriteLine strLine
		End If
	Wend
	objDefrag.Close
	objFSO.DeleteFile strTempFile, True
Next
objShell.Run "excel """ & strOutput & """"

Open in new window

0
 
ReneGeAuthor Commented:
Cool that you thought about it... Thanks!

1) On my Server 2003, works like a charm
2) On my XP Pro,  I get the following error (see image)
3) I will use this script with "cscript" in a batch file. Would you mind modifying it so it can output on screen, not in a file?

Thanks again,
Rene
ErrorMessage.png
0
 
ReneGeAuthor Commented:
0
 
RobSampsonCommented:
Psy and I are writing different versions....my latest one should work standalone, writing to CSV....
0
 
ReneGeAuthor Commented:
==>psy
Sorry man, I did not realize it was you. I guess working 14h in a row does not help.
So my previous 2 messages were for you

==> Rob
Running your last script on both 2003 and XP, I get the following message

Thanks guys,
Rene
ErrorMessage.png
0
 
ReneGeAuthor Commented:
ErrorMessage in english
ErrorMessage.png
0
 
RobSampsonCommented:
That would mean Excel does not exist on that system, but you should still find the output file.  Change
objShell.Run "excel """ & strOutput & """"
to
objShell.Run "notepad """ & strOutput & """"

to have the file open in Notepad.

Rob.
0
 
ReneGeAuthor Commented:
==>Rob

I get it. I don't have Excel on that machine. So your script does work.
I need the output to be on screen anyway, would you mind changing the script to do so, and remove the Excel part?

Thanks,
Rene
0
 
ReneGeAuthor Commented:
Thanks guys,

I have what I need and you are geniuses!!!!!

Many thanks and lots of cheers,
Rene
0
 
Psy053Commented:
Here's an updated version of my script that will write to screen.

Just to troubleshoot the issue you had with it earlier, I have included an extra line that shows what the Version is, can you please report that version back here?
DiskSpace-ToScreen.vbs
0
 
RobSampsonCommented:
No problem. Thanks for the grade.

Regards,

Rob.
0
 
RobSampsonCommented:
Psy, if you want to ask for points for an assist, I won't object....

Rob.
0
 
Psy053Commented:
Rob, would you mind telling my why you chose to write the output to file for processing as opposed to using the StdOut that you had initially?
0
 
RobSampsonCommented:
I did that just so the output was silent, and you don't have the DOS prompt appear with the defrag, waiting for the StdOut.

Rob.
0
 
Psy053Commented:
Good thinking! Thankyou for responding.
0
 
ReneGeAuthor Commented:
Hi guys,

I arrived not long ago from work.

As for the points, I splitted them according to the level of contribution in this thread at the moment of closing it. I just hope it was fair. You both deserve 500 points and I feel bad not being able to give more.

==>Psy,
Windows Server 2003 : Version 5.2
Microsoft (R) Windows Script Host Version 5.6
>Get degrad infos works

Windows XP Pro : Version 5.1
Microsoft (R) Windows Script Host Version 5.7
>Get degrad infos does not work


Thanks and cheers,
Rene
0
 
RobSampsonCommented:
Oh yeah, I didn't notice you gave Psy an assist....that's fine with me.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.