Summary: Learn how to use Windows PowerShell to determine the amount of fragmentation of your hard disk drives.
Hey, Scripting Guy! One of the things that annoys me is that the “new” defragmenter program in Windows 7 does not return any information. I guess from a user standpoint, it is OK—and it runs as a service, and that is OK. But I enjoyed seeing the reports. Perhaps it is the geek in me. Is there something Windows PowerShell can do about this?
—NB
Hello NB,
Microsoft Scripting Guy, Ed Wilson, here. Believe it or not, it has turned cold down here in Charlotte, North Carolina. At this very minute, it is a beautiful sunny day, but the temperature has not risen above 48 degrees Fahrenheit (8 degrees Celsius, according to my Windows PowerShell conversion module).
Beginning with Windows Vista, the defrag program runs as a scheduled task. This task appears in the Task Scheduler utility, as shown in the following image.
I manually edited the command line of the scheduled task because I have a solid-state drive (SSD)—drive C, and I did not want the defrag program running against that drive. To ensure this, I modified the switches to cause the program to only defragment my drive E.
When defrag runs (either an analysis or an actual defragmentation session), an event is written to the Application log. As seen in the following image, the information is less than illuminating.
This is where our understanding of WMI methods comes into play. It also proves the value of the report I produced last week of implemented WMI methods.
“What has all this got to do with WMI and with methods?” you may ask.
I will tell you…the Win32_Volume WMI class (first available in Windows Server 2003, but not available in Windows XP) contains a method called DefragAnalysis. The cool thing about the DefragAnalysis method is that it returns an instance of the Win32_DefragAnalysis WMI class. This sounds a bit complicated, and in VBScript, it is actually rather complicated. In Windows PowerShell, however, it is a cinch!
The first thing we need to do is to start Windows PowerShell as an Administrator. Right-click the Windows PowerShell icon and choose Run as an Administrator from the Tasks menu, as shown in the following image.
Now that we have a Windows PowerShell console running with Administrator rights, I use the Get-WmiObject cmdlet to retrieve an instance of the Win32_Volume WMI class that represents my drive E. I store the returned object in the $drive variable. Next, I simply call the DefragAnalysis method. Remember, when calling methods, the use of parentheses is required. The two commands and the associated output are shown here.
PS C:\> $drive = Get-WmiObject -Class Win32_Volume -Filter “DriveLetter = ‘e:'”
PS C:\> $drive.DefragAnalysis()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 3
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
DefragAnalysis : System.Management.ManagementBaseObject
DefragRecommended : False
ReturnValue : 0
A return value of 0 means that there were no errors. Groovy, everything is copacetic. Except for one glaring problem—this command returns no more information than what is contained in the event log.
Remember when I said that this method returns an instance of the Win32_DefragAnalysis WMI class? Yes? Great. Now in the output, it shows us the following line.
DefragAnalysis : System.Management.ManagementBaseObject
This tells me that the DefragAnalysis property contains an object. The best way to retrieve this object, is to store the returned objects in a variable. This technique and the associated output from the command is shown here.
PS C:\> $drive = Get-WmiObject -Class Win32_Volume -Filter “DriveLetter = ‘e:'”
PS C:\> $report = $drive.DefragAnalysis()
PS C:\> $report.DefragAnalysis
__GENUS : 1
__CLASS : Win32_DefragAnalysis
__SUPERCLASS :
__DYNASTY : Win32_DefragAnalysis
__RELPATH : Win32_DefragAnalysis
__PROPERTY_COUNT : 27
__DERIVATION : {}
__SERVER : MRED1
__NAMESPACE : ROOT\cimv2
__PATH : \\MRED1\ROOT\cimv2:Win32_DefragAnalysis
AverageFileSize : 976
AverageFragmentsPerFile : 1
AverageFreeSpacePerExtent : 1822187520
ClusterSize : 4096
ExcessFolderFragments : 0
FilePercentFragmentation : 0
FragmentedFolders : 0
FreeSpace : 350030282752
FreeSpacePercent : 69
FreeSpacePercentFragmentation : 0
LargestFreeSpaceExtent : 349548830720
MFTPercentInUse : 100
MFTRecordCount : 39423
PageFileSize : 0
TotalExcessFragments : 2
TotalFiles : 37513
TotalFolders : 874
TotalFragmentedFiles : 2
TotalFreeSpaceExtents : 192
TotalMFTFragments : 2
TotalMFTSize : 40370176
TotalPageFileFragments : 0
TotalPercentFragmentation : 0
TotalUnmovableFiles : 10
UsedSpace : 150074404864
VolumeName :
VolumeSize : 500104687616
As you can see from this output, the DefragAnalysis method returns some very useful information.
There is another way to call WMI methods, and I will show this to you now.
The Windows PowerShell cmdlet Invoke-WmiMethod is used to invoke WMI methods. It accepts the name of the method to run, an input object (or WMI class name), and any arguments that might be needed. Unfortunately, unlike the Set-WmiProperty cmdlet that I discussed yesterday, the Invoke-WMiMethod cmdlet uses an array for input (as opposed to a hash table like the Set-WmiProperty).
To use the Invoke-WmiMethod cmdlet, I first use the Get-WmiObject cmdlet to retrieve an instance of the Win32_Volume WMI class that is associated with my drive E. Next, I call the Invoke-WmiMethod to pass the input object that is stored in the $drive variable, and I use the name parameter to call the DefragAnalysis method. This method requires no arguments. The command and its associated output are shown here.
PS C:\> $drive = Get-WmiObject -Class Win32_Volume -Filter “DriveLetter = ‘e:'”
PS C:\> Invoke-WmiMethod -InputObject $drive -Name DefragAnalysis
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 3
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
DefragAnalysis : System.Management.ManagementBaseObject
DefragRecommended : False
ReturnValue : 0
NB, you can easily put the previous commands into a .PS1 file and make a script out of it. If you like the analysis report that is generated by the DefragAnalysis method, you might even redirect the output to a text file, and use the Task Scheduler to Run the Script on a Regular Basis.
NB, that is all there is to using the DefragAnalysis method and Windows PowerShell to determine the level of fragmentation of your hard disk drives. Join me tomorrow when I will have a guest blog about Microsoft Exchange Server from guest blogger, Nicolas Blank. Nicolas is really cool, and the article is excellent. You will not want to miss it.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
0 comments