Friday, February 4, 2011

DataBase's OnLine Defrag is silent as bad cholesterol - Exchange 2007

And is true...Before you know it, you have clogged arteries..and your databases ..broken .So the code below will check the events 700-701-702-703-704 see the table below.

As Microsoft states as best practices :
"Monitoring online defragmentation enables you to verify that defragmentation of every Exchange database is completing often enough (at least every two weeks, as a best practice). Monitoring online defragmentation may also enable you to decrease the online maintenance window, which has the following advantages:
  • Allows more time for database backup.
  • Validates that online checksumming and page zeroing can be introduced within the current online maintenance window.
Microsoft Exchange Server 2007 Service Pack 1 (SP1) introduces the following improvements to help you monitor online defragmentation:
  • Extended information for Event 703 allows you to more easily monitor online defragmentation pass completions.
  • Two extended Extensible Storage Engine (ESE) performance counters for monitoring the effectiveness and efficiency of online defragmentation have been added for use with Performance Monitor (which is called Reliability and Performance Monitor in Windows Server 2008)."
This code will generate two types fo outputs:

With errors (not completed)
Name                    : DATABASE1-SG04
Identity                : SERVER\STORAGEGROUP\DATABASE1-SG04
EdbFilePath             : N:\STORAGEGROUP\DATABASE1-SG04
DefragStart             :
DefragEnd               :
DefragDuration          :
DefragInvocations       :
DefragDays              :
DefragInterrupts        :
DefragError             : unexpected error :-327.--> this is a critical error, you shold repair the DB ( : 20/01/2011
DefragStillRunningDays  : 13  ----> 13 days running

Without errors (completed)
Name                    : DATABASE-SG05
Identity                : SERVER\STORAGEGROUP\DATABASE-SG05
EdbFilePath             : P:\DATABASE\DATABASE-SG05.edb
DefragStart             : 03/02/2011 04:54 
DefragEnd               : 03/02/2011 04:54
DefragDuration          : 28976 seconds.
DefragInvocations       : 2 time[s].
DefragDays              : 1
DefragInterrupts        : 03/02/2011 09:59  ---> Backup interruptions
DefragError             :
DefragStillRunningSince :
DefragStillRunningDays  :

The event 705 is preceded for the event 447 , this issue indicates that a corrupt page link was detected in a B-Tree.

Online defragmentation has failed because of some issues in this tree. Event 447 suggests that a B-tree consists a corrupt page link. The most common reasons for this problem to occur are:

Note: It is not safe to continue using such corrupted database as a bad page link indicates logical database corruption at ESE level. Also, you should ensure that no antivirus software is scanning the Exchange database files.

    • Check the Application log carefully for related events and patterns that may relate to this event. Check the System log carefully for related events and patterns including any errors related to hardware, drives, controllers, or the file system. If there are any such errors, replace the hardware, update the hardware system files, or repair the file system to prevent any future errors. Do this before proceeding to the next step
    • If the Exchange store database is running, use ExMerge to merge your data to .pst files, delete the database, create a blank database, and then run ExMerge t databases to a blank database.
    • If the database is running, you may also move all the mailboxes to another store, delete the affected database, create a new database, and then move all the mailboxes back.
    • If the Exchange store database will not mount, the suggested remedy is to restore from online backup before the errors appear in the Application log.
    • If the Exchange store database will not mount and there is no backup, the last resort is to repair the database by running eseutil /p and then repeatedly running isinteg -fix until there are no fixes reported. Finally, run ExMerge, create a blank store, and use ExMerge to move the data back in.
-----------------------begin code
$srv = Get-ExchangeServer |where {$_.IsMailboxServer -eq 'True'}

$output = @()
$dmtf = [System.Management.ManagementDateTimeconverter]
$Startdate = $dmtf::ToDmtfDateTime( (Get-Date).AddDays(-1).Date )
$free = @{Name="WhiteSpace(MB)";Expression={[int]$_.InsertionStrings[0]}}

foreach ($dbserver in $srv){

# Get the mailbox databases from the server
$mbdatabases = Get-MailboxDatabase -Server $ | Sort-Object -Property Name

# Get the public folder databases from the server
$pfdatabases = Get-PublicFolderDatabase -Server $ | Sort-Object -Property Name

# Create an array for the databases
$databases = @()

# Check if mailbox databases were found on the server
If ($mbdatabases) {
      # Loop through the databases
      ForEach ($mdb in $mbdatabases) {
            # Create an object to store information about the database
            $db = "" | Select-Object Name,Identity,EdbFilePath,DefragStart,DefragEnd,DefragDuration,DefragInvocations,DefragDays,DefragInterrupts,DefragError,DefragStillRunningSince,DefragStillRunningDays
            # Populate the object
            $db.Name = $mdb.Name.ToString()
            $db.Identity = $mdb.Identity.ToString()
            $db.EdbFilePath = $mdb.EdbFilePath.ToString()
            # Add this database to the array
            $databases = $databases + $db

# Check if public folder databases were found on the server
If ($pfdatabases) {
      # Loop through the databases
      ForEach ($pfdb in $pfdatabases) {
            # Create an object to store information about the database
            $db = "" | Select-Object Name,Identity,EdbFilePath,DefragStart,DefragEnd, DefragDuration,DefragInvocations,DefragDays,DefragInterrupts,DefragError,DefragStillRunningSince,DefragStillRunningDays
            # Populate the object
            $db.Name = $pfdb.Name.ToString()
            $db.Identity = $pfdb.Identity.ToString()
            $db.EdbFilePath = $pfdb.EdbFilePath.ToString()
            # Add this database to the array
            $databases = $databases + $db

# Retrieve the events from the local Application log, filter them for ESE messages
$logs = Get-WMIObject Win32_NTLogEvent -ComputerName $  -Filter "LogFile='Application' AND Timewritten>='$startdate' AND sourceName='ESE' AND CategoryString='Online Defragmentation'  "

# Loop through each of the databases and search the event logs for relevant messages
ForEach ($db in $databases) {

      # Create the search string to look for in the Message property of each log entry
      $s = "*" + $db.EdbFilePath + "*"

      # Search for an event 701 or 703, meaning that online defragmentation finished
      $end = $logs | where {
            $_.Message -like "$s" -and ($_.eventcode -eq 701 -or $_.eventcode -eq 703)
      } | select-object -First 1

      # Search for the first event 700 which preceeds the finished event
      $start = $logs | where {
            $_.Message -like "$s" -and $_.eventcode -eq 700 -and $_.Index -le $end.Index
      } | select-object -First 1
  $interr = $logs | where {
            $_.Message -like "$s" -and $_.eventcode -eq 704
      } | select-object -First 1
 $defError = $logs | where {
            $_.Message -like "$s" -and $_.eventcode -eq 705
      } | select-object -First 1

 $defStillRun = $logs | where {

            $_.Message -like "$s" -and $_.eventcode -eq 702
      } | select-object -First 1

      # Make sure we found both a start and an end message
      if ($start -and $end  ) {

            # Get the start and end times
  $st= $start.TimeGenerated

  $et= $end.TimeGenerated


           $db.DefragStart = $stD + "/" + $stM + "/" +  $stY + " " + $stH + ":"  + $stMs
            $db.DefragEnd = $etD  + "/" + $etM + "/" + $etY  + " " + $etH + ":" + $etMs

            # Parse the end event message for the number of seconds defragmentation ran for
            $end.Message -match "This pass started on .* and ran for a total of .* seconds" >$null
     #$db.DefragStart = $Matches[0].Split(" ")[4] + " restarted."
            $db.DefragDuration = $Matches[0].Split(" ")[11] + " seconds."

            # Parse the end event message for the number of invocations and days
            $end.Message -match "requiring .* invocations over .* days" > $null
            $db.DefragInvocations = $Matches[0].Split(" ")[1] + " time[s]."
            $db.DefragDays = $Matches[0].Split(" ")[4]

  #$interr.Message -match "was interrupted and terminated." >$null
  if ($interr) {
  $it= [string]$interr.TimeGenerated
       $db.DefragInterrupts=$itD  + "/" + $itM + "/" + $itY  + " " + $itH + ":" + $itMs
          } else {

            if ($defError -and $defStillRun) {

            $defError.Message -match "after encountering unexpected error .*" >$null
            $db.DefragError = "unexpected error :" + $Matches[0].Split(" ")[4]

     $defStillRun.Message -match "pass started on .* and has been running for .* days" >$null 
     $db.DefragStillRunningSince = $Matches[0].Split(" ")[3]
     $db.DefragStillRunningDays = $Matches[0].Split(" ")[9]

      # Add the data for this database to the output
      $output = $output + $db
# Print the output

------end code

Don't happy.



  1. Remarkable issues here. I'm very satisfied to see your post. Thanks so much and I'm having a look forward to contact you. Will you kindly drop me a e-mail?
    my web site - Repair edb files

    1. I'm glad to help!!! please feel free to contact me at


Note: Only a member of this blog may post a comment.