Defrag Exchange Database & Boost Server Performance

Shini Mohan | Modified: December 19, 2024 | Exchange | 6 Minutes Reading

Admins know that in order to clean up the server they must defrag the Exchange Database from time to time. However, the real struggle is how to go about this process. There is no one button on the EAC that says defrag.

Admins have to instead use highly technical and often confusing PowerShell commands that may be thrown in previously unseen errors. Not to worry as this tutorial is more than enough to study and apply the process. Let us begin by highlighting the requirements behind this task.

Why do Admins Have to Defrag the Exchange Database at All?

Regular use puts stress on the server. One such repetitive task is the creation and subsequent deletion of user mailboxes on the Exchange environment.

Moreover, if admins put the Exchange Server in maintenance mode they can see the current health status of their infrastructure. Making it easier to determine whether or not it is the right time to undergo such a process.

This often leads to the accumulation of empty but unusable storage known as white space. Despite not storing any of the actual data this white is considered occupied. Reducing the true free space left for the Exchange Server tasks.

If not cleaned up timely it can clog up the entire server and render it useless.

Mailboxes are not the only things that take up storage, there are also log files that keep track of all changes to swell up to occupy a significant chunk of the storage database.

The only manual method available to remedy this issue is to use the defragmentation process.

Now you know why defragmentation is important let us see what admins must do first in order to have a clean defrag.

Check if You Need to Defrag Exchange Database and If So Which One?

Exchange Servers can contain multiple databases not every one of them would require defragmentation. So selecting the correct one becomes a very critical decision for the admins.

Start with a database-level diagnosis of the Exchange Server,

Admins need not perform any steps manually the following custom cmdlet does all the calculations for them.

Open a new Windows PowerShell ISE module on the workstation you are using to conduct the defragmentation of Exchange Database

Paste the following code there. 

function Get-ExchangeDatabaseFragmentation {
    <#
    .SYNOPSIS
    Checks Exchange Server mailbox databases for fragmentation.

    .DESCRIPTION
    Calculates whitespace percentage, estimates space required for defragmentation, and displays the full database path separately.

    .PARAMETER Threshold
    Whitespace percentage threshold for flagging databases. Default is 20%.

    .EXAMPLE
    Get-ExchangeDatabaseFragmentation -Threshold 15

    .OUTPUT
    Fragmentation details and defragmentation space requirements in a table, and database paths displayed vertically.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [int]$Threshold = 20
    )

    try {
        $databases = Get-MailboxDatabase -Status
        $results = @()
        foreach ($db in $databases) {
            $dbStats = Get-MailboxStatistics -Database $db.Identity
            if (-not $dbStats) {
                Write-Warning "No statistics found for database $($db.Name)."
                continue
            }
            $totalSize = $db.DatabaseSize.ToBytes()
            $whitespaceSize = $db.AvailableNewMailboxSpace.ToBytes()
            if ($totalSize -and $whitespaceSize -and $totalSize -gt 0) {
                $actualSize = $totalSize - $whitespaceSize
                $whitespacePercentage = ($whitespaceSize / $totalSize) * 100
                $spaceRequired = $actualSize * 1.1
                # Convert sizes to MB for display
                $totalSizeMB = [Math]::Round($totalSize / 1MB, 2)
                $whitespaceSizeMB = [Math]::Round($whitespaceSize / 1MB, 2)
                $actualSizeMB = [Math]::Round($actualSize / 1MB, 2)
                $spaceRequiredMB = [Math]::Round($spaceRequired / 1MB, 2)
                $results += [PSCustomObject]@{
                    Database            = $db.Name
                    DatabasePath        = $db.EdbFilePath # Path is stored
                    TotalSize           = "$totalSizeMB MB"
                    Whitespace          = "$whitespaceSizeMB MB"
                    ActualSize          = "$actualSizeMB MB"
                    SpaceRequired       = "$spaceRequiredMB MB"
                    WhitespacePercentage = [math]::Round($whitespacePercentage, 2)
                    ActionNeeded        = $whitespacePercentage -gt $Threshold
                }
            } else {
                Write-Warning "Unable to calculate whitespace for database $($db.Name)."
            }
        }

        # Output the results table (WITHOUT DatabasePath)
        $results | Sort-Object WhitespacePercentage -Descending | Format-Table Database, TotalSize, Whitespace, ActualSize, SpaceRequired, WhitespacePercentage, ActionNeeded -AutoSize
        # Output database paths vertically if results exist
        if ($results) {
            Write-Host ""
            Write-Host "Database Paths:"
            $results | ForEach-Object {
                Write-Host "  Database: $($_.Database)"
                Write-Host "  Path: $($_.DatabasePath)"
                Write-Host "--------------------------------------------------"
            }
        } else {
            Write-Host "No databases found."
        }
        return $results
    } catch {
        Write-Error "An error occurred: $_"
    }
}

Output

There is no need to run the program on ISE just go to the File > Save As >
ExchangeDatabaseFragmentation.ps1

Create a new folder Scripts/Custom Cmdlets and save this file there.

Keep the path in the clipboard by copying it. You will need it later.

Back up the databases by creating a copy you can use PowerShell or do it manually on your own.

Now open a new Exchange Management Shell Window

Type cls and press Enter to clear out all redundant text.

Then, cd “parent/folder/path/of/script” 

Call the script by typing

. .\ExchangeDatabaseFragmentation.ps1

Use the script in the same way you would use any other PowerShell cmdlet i.e. by typing
Get-ExchangeDatabaseFragmentation -Threshold 20

If there are no errors you should see a screen similar to this.

Here you can see a list of all databases on your server with the comments on whether or not defragmentation is required.

The script also calculated the amount of space you would need to perform the defragmentation if you choose to do so.

Saving a lot of time and effort on the part of the admin.

Now you know on which database to perform Defragmentation let’s see the steps to do it via the code itself.

Steps to Use PowerShell to Defrag Exchange DB

Step 1: Continue in the Same EMS instance or Launch a New one but don’t close the existing Exchange Management Shell.

Step 2: Then, type cd followed by the folder path. You can copy-paste it from the custom cmdlet results, which you can find by scrolling up or going back to the old EMS instance.

Note that you only select up to the folder. Do not include the actual edb file part otherwise, you might see an error message. 

Your command will look like

cd  “C:\Program Files\Microsoft\Exchange Server\V15\Mailbox\Mailbox Database 0659294379\”

Note: We cannot perform defragmentation if the database is in a live state, so that is why we must demount it first. 

Step 3: Use:

Dismount-Database <Your_Database_Name>

Step 4: After the dismount is done you need to use the EseUtil command. This marks the beginning of database defragmentation and looks something like this.

Once the database is dismounted, use the below EseUtil command to start the defragmentation process.

Eseutil /d "Mailbox Database 0951235982.edb" /t "temp_0912395982.edb"

Defragmentation is not instantaneous, the time taken is directly proportional to the overall size 

Step 5: Remount the database to the Server, and type:

Mount-Database "Mailbox Database 0951235982"

Step 6: Rerun the custom cmdlet again to see the effects of defragmentation in detail.

In some cases, a faulty defrag operation may push the Exchange Server into an inconsistent state after a failed or dirty shutdown, making it necessary to address these issues before defragging. Another automated way to fix such issues would be to use the SysTools Exchange Recovery tool.

Conclusion

In this blog post, we gave a thorough explanation of how to defrag the Exchange Database. Admins can use the techniques described in this tutorial to reclaim the empty space that exists in their server after regular mailbox deletions.