Get disk defrag status PowerShell
Introduction
Just over a week ago now at the end of my post on getting files older than a specified time in PowerShell I mentioned I would follow up with a PowerShell function that could be used to get the defragmentation status of disks on multiple machines, this blog post details that function and also contains a downloadable script version of the function for those who prefer to use a script than a function
Get disk defrag status with PowerShell
Ensuring that server disk volumes are not in a fragmented state can significantly improve the performance of your server operating environment, the Get-DefragStatus function listed below can be used to report on the defrag requirements of volumes on the servers specified, informing you which volumes require a disk defragmentation and also if there is sufficient space on the volume to allow an optimal disk defragmentation to take place.
The code for the Get-DefragStatus function can be found below followed by examples on how this function can be used. For those of you who prefer to download a script that can be used instead of the function, a script can be downloaded from here and used in the same way as the function is used in the examples at the foot of this article.
<#
.SYNOPSIS
Returns the defragmentation requirements of storage volumes.
.DESCRIPTION
Get-DefragStatus returns a list of volumes from the machines specified and lists if they require
a defragmentation and also if the volume has sufficient free space to allow a defragmentation
to be performed.
.INPUTS
System.String
You can pipe a string or an array of strings containing computer names or address to Get-DefragStatus.
.PARAMETER ComputerName
Specifies the names or IP addresses of computers which the program should run against. If no value is
specified then the program will run against the local machine.
.LINK
http://www.mywinkb.com/Get-disk-defrag-status-PowerShell
.EXAMPLE
C:\PS>Get-DefragStatus
This command returns the defrag requirements for all volumes on the machine on which it
is executed
.EXAMPLE
C:\PS>Get-DefragStatus -ComputerName Server01,Server02
This command returns the defrag requirements for all volumes on the computers Server01 & Server02
.EXAMPLE
C:\PS>Get-DefragStatus -ComputerName Server01,Server02 | Where-Object { $_.DefragRequired -eq $true }
This command returns all volumes on the computers Server01 & Server02 which require a disk defrag
#>Function Get-DefragStatus {
[CmdletBinding()]
[outputType([Object])]
param (
[parameter(ValueFromPipeline=$true)]
[string[]] $ComputerName = $env:computername
)
Process {
#Test if the computer specified exists, if it does continue, if it doesn’t write an error
foreach ($computer in $computername) {
Write-Verbose $("Attempting to connect to $computer")
if ($(Test-Connection -ComputerName $computer -Count 1 -Quiet) -eq $false) {
Write-Verbose "Connection Failed"
Write-Error $("Could not connect to computer: $computer")
}
Else {
Write-Verbose "Connection established"
#Get all local disks on the specified computer via WMI class Win32_Volume
Get-WmiObject -ComputerName $computer -Class win32_volume | Where-Object { $_.drivetype -eq 3 -and $_.driveletter -ne $null } |
#Perform a defrag analysis on each disk returned
ForEach-Object -begin {} -process {
#Initialise properties hashtable
$properties = @{}
#perform the defrag analysis
Write-Verbose $("Analyzing volume " + $_.DriveLetter + " on computer " + $computer)
$results = $_.DefragAnalysis()
#if the return code is 0 the operation was successful so output the results using the properties hashtable
if ($results.ReturnValue -eq 0) {
$properties.Add(‘ComputerName’,$_.__Server)
$properties.Add(‘DriveLetter’, $_.DriveLetter )
if ($_.DefragAnalysis().DefragRecommended -eq $true) { $properties.Add( ‘DefragRequired’,$true ) } else {$properties.Add( ‘DefragRequired’,$false)}
if (($_.FreeSpace / 1GB) -gt (($_.Capacity / 1GB) * 0.15)) { $properties.Add( ‘SufficientFreeSpace’,$true ) } else {$properties.Add( ‘SufficientFreeSpace’,$false)}
Write-Verbose "Analysis complete"
New-Object PSObject -Property $properties
}
#If the return code is 1 then access to perform the defag analysis was denied
ElseIf ($results.ReturnValue -eq 1) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: Access Denied")
}
#If the return code is 2 defragmentation is not supported for the device specified
ElseIf ($results.ReturnValue -eq 2) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: Defrag is not supported for this volume")
}
#If the return code is 3 defrag analysis cannot be performed as the dirty bit is set for the device
ElseIf ($results.ReturnValue -eq 3) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: The dirty bit is set for this volume")
}
#If the return code is 4 there is not enough free space to perform defragmentation
ElseIf ($results.ReturnValue -eq 4) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: The is not enough free space to perform this action")
}
#If the return code is 5 defragmentation cannot be performed as a corrupt Master file table was detected
ElseIf ($results.ReturnValue -eq 5) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: Possible Master File Table corruption")
}
#If the return code is 6 or 7 the operation was cancelled
ElseIf ($results.ReturnValue -eq 6 -or $results.ReturnValue -eq 7) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: The operation was cancelled")
}
#If the return code is 8 the defrag engine is already running
ElseIf ($results.ReturnValue -eq{
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: The defragmentation engine is already running")
}
#If the return code is 9 the script could not connect to the defrag engine on the machine specified
ElseIf ($results.ReturnValue -eq 9) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: Could not connect to the defrag engine")
}
#If the return code is 10 a degrag engine error occured
ElseIf ($results.ReturnValue -eq 10) {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: A defrag engine error occured")
}
#Else an unknown error occured
Else {
write-output ("Defrag analysis for disk " + $_.DriveLetter + " on computer " + $_.__Server + " failed: An unknown error occured")
}
} #Close ForEach loop for Defrag Analysis
} #Close else clause on test-computer if conditional} #Close ForEach loop on Test-Computer
} #End Process Block} #End Function
To begin using the function above simply copy and paste the code snippet into your Windows PowerShell console, you will then be able to use the function as detailed in the examples below. The beginning of the code snippet above contains the inline help for the function, which allows you to use the command ‘Get-Help Get-DefragStatus’ within your PowerShell console to retrieve help on using the function. Inside the body of the function the Win32_Volume WMI class is used to perform a defrag analysis on all local disks on the computers specified which have drive letters. The function uses a custom object to output the Defrag Required Status, Drive Letter, Computer Name and Sufficient Space Status for each volume on the servers specified when the function is run.
Examples of how to get the disk defrag status for a computer in PowerShell
In it’s simplest format the Get-DefragStatus function will list the defrag requirements of the machine on which the function was run, this can be done by simply running the Get-DefragStatus command on a computer. You can however use the function to return the defrag status of multiple machines at the same time, this is achieved by using the –ComputerName parameter. An example of using the Get-DefragStatus function to list the defrag requirements on two computers named Server01 and Server02 can be seen below.
Get-DefragStatus –ComputerName Server01,Server02
The output from the above command can be seen below.
DefragRequired DriveLetter ComputerName SufficientFreeSpace
——————– ———– ——————- ————————-
True C: SERVER01 True
False E: SERVER01 True
False C: SERVER02 True
True E: SERVER02 False
From the above output it can be seen that both the C:\ drive on Server01 and the E:\ drive on Server02 require a defragmentation, however the E:\ drive on Server02 does not have sufficient free space to allow an optimal disk defragmentation to be performed.
Review
With the examples above you can see how the Get-DefragStatus function can be used to help you stay on top of which disk volumes on your servers require a defragmentation. A review of the key points is as follows
- When the Get-DefragStatus command is run with no parameters the command will be run against the machine on which it was executed.
- The ComputerName parameter can be used to specify an array of computer names that the command should be run against.
- The command can take an array of computer names via the pipeline.
- Any errors encountered when analysing the defragmentation status of a particular server will be reported to the user via the output of the function.
- That’s all there is to using the function listed above to get disk defrag status in PowerShell, remember if you prefer to download a script rather than use a function then a script can be downloaded from here.
- That’s all for now, to stay in touch with new posts and PowerShell programs posted on the blog please follow me on twitter. I have now made a second disk defrag function available which will allow you to perform a disk defragmentation in PowerShell on the volumes returned from the Get-DefragStatus function listed in this post.

Sorry, I’m new to PS but feel this script could be handy for me. I need to run this against a couple of hundred machines. What is the best way of achieving this? I don’t fully understand the below statements. Where exactly in your script do I need to add my list of hostnames?
System.String
You can pipe a string or an array of strings containing computer names or address to Get-DefragStatus.
.PARAMETER ComputerName
Specifies the names or IP addresses of computers which the program should run against. If no value is specified then the program will run against the local machine.
Also I have a combination of Win7 64bit and XP 32bit machines within my environment. Will this return values for both? Is there a way to list the percentage fragmentation level in the output?
Hi Jo,
Thanks for your comments, this script should run against XP 32 bit and Win7 64 Bit with no problem yes, the easiest way to run this against a large number of computers would be to place the names of the computers you would like the script to run against in a .txt file, one entry per line, and then run the following command.
Get-Content C:\Computers.txt | Get-DefragStatus
Currently this will not list any percentage figures about the fragmentation level of the computers it is run against, it simply informs you whether or not a computer requires a disk defragmentation and if the machine has sufficient space to allow a disk defragmentation to occur. If you are interested in having the level of fragmentation output as a percentage though just let me know.
Cheers
Thanks for the response, much appreciated. The percentage level could be handy as I would use it as a way to prioritise which machines I’d work through first, but if it’s too much bother don’t worry about it, this is very helpful as it is!
Hi Jo,
Thanks for the scripts for defrag and get-defrag. When I run them against both Win7x64 and Win8x64 the get-defrag fails with “Defrag analysis for disk E: on computer WINDOWS failed: An unknown error occured”
any ideas?
Thanks in advance,
Raymond