Backing up Exchange configuration

This is currently a work-in -progress. A recent outage caused by a configuration change in Exchange has made me realize we need some sort of configuration change control. To that end, I’ve got this script for backing up the configuration objects in Exchange. At this point is useful for backup up the objects as clixml files, which can be used to compare to current objects to see what’s changed, or help recreate configuration objects if necessary.

Starting with a root backup folder, it creates a set of subfolders (Server, UM, Transport, Database, and Policy), and then subfolders within those for each object type. All of this is laid out in the $Ex_Object_Folders, so it can be re-organized by changing that hash table. The object types are specified as the noun-part of whatever get-* command will return that object, and it uses the objet’s GUID as the file name.

On the first run it will create the necessary folders and get and export the object types listed for each one. On subsequent runs it will check the .whenchanged property of the object in Exchange, and compare it to the lastwritetime of the backup file it has for that object. If it’s changed since it was last exported the export is refreshed.

I’m hoping to get this set up as a Subversion repository and letting that provide the versioning. Welcome any comments from anyone who’s done anything similar, or has suggestions on a better way to do this.

In any case you’re welcome to use it, or any bits of it that look useful. You’ll need to specify a path to the root folder where you want your backups to be, and the name of an Exchange server to use for the session, since it’s written to not require an EMS shell.



$Target_Directory = '<Exchange backup directory root path>'
$ExchangeServer = '<Exchange server to use for session>'

$VerbosePreference = 'Continue'

$SessionParams = 
   @{
     ConfigurationName = 'MicroSoft.Exchange'
     ConnectionURI     = "http://$ExchangeServer/powershell/"
     Authentication    = 'Kerberos'
     ErrorAction       = 'Stop'
    }

$ExSession = New-PSSession @SessionParams

$Ex_Object_Folders = 
   @{
     Server =    @(
                   'MailboxServer',
                   'TransportServer',
                   'ClientAccessServer',
                   'UMServer'
                  )

     UM =        @(
                   'UMDialPlan'
                   'UMAutoAttendant'
                   'UMIPGateway'
                   'UMHuntGroup'
                  )

     Transport = @(
                    'TransportRule',
                    'JournalRule',
                    'SendConnector',
                    'ReceiveConnector',
                    'ForeignConnector',
                    'RoutingGroupConnector',
                    'AcceptedDomain',
                    'RemoteDomain'
                   )

     Database =   @(
                    'MailboxDatabase',
                    'PublicFolderDatabase',
                    'DatabaseAvailabilityGroup'
                   )

     Policy =     @(
                    'ActiveSyncMailboxPolicy',
                    'AddressBookPolicy',
                    'EmailAddressPolicy',
                    'ManagedFolderMailboxPolicy',
                    'OwaMailboxPolicy',
                    'RetentionPolicy',
                    'RetentionPolicyTag',
                    'RoleAssignmentPolicy',
                    'SharingPolicy',
                    'ThrottlingPolicy',
                    'UMMailboxPolicy'
                   )
    }
     
#Folder maintenance:

$DirParams = @{
                ItemType    =  'Directory'
                Verbose     =  $true
                ErrorAction =  'Stop'
              }

Write-Verbose "Checking target root folder"
if ( -not ( Test-Path $Target_Directory ) )
  { New-Item  @DirParams -Path $Target_Directory }

Write-Verbose "Checking Object folders"
foreach ($Ex_Object_Folder in $Ex_Object_Folders.keys)
   {
    if ( -not ( test-path "$Target_Directory\$Ex_Object_Folder\" ) )
      { New-Item @DirParams -Path $Target_Directory\$Ex_Object_Folder }

    foreach ( $Ex_Object_Type in $Ex_Object_Folders.$Ex_Object_Folder )
       {
        if ( -not ( test-path "$Target_Directory\$Ex_Object_Folder\$Ex_Object_Type" ) )
          { New-Item @DirParams -Path $Target_Directory\$Ex_Object_Folder\$Ex_Object_Type }
       }
    }

#Update backups of changed objects

foreach ($Ex_Object_Folder in $Ex_Object_Folders.keys)
 {
   foreach ( $Ex_Object_Type in $Ex_Object_Folders.$Ex_Object_Folder )
     {
       Write-Verbose "******************************************************`n"
      
      Write-Verbose "Checking for $Ex_Object_Type backups."
      $LastBackups = @{}
      $Config_Export_FIles = Get-ChildItem "$Target_Directory\$Ex_Object_Folder\$Ex_Object_Type\*.clixml"
      Foreach ($Config_Export_FIle in $Config_Export_FIles)
       {
         $LastBackups[$Config_Export_FIle.basename] = $Config_Export_FIle.LastWriteTime 
       }
     
      Write-Verbose "Found $($Config_Export_FIles.count) $Ex_Object_Type backup files."

      Write-Verbose "Getting $Ex_Object_Type object configs from Exchange."

       $SB = [ScriptBlock]::Create("Get-$Ex_Object_Type ")

       $Ex_Object_Configs =
         @(Invoke-Command -ScriptBlock $SB -Session $ExSession)

       Write-Verbose "Found $($Ex_Object_Configs.Count) Exchange $Ex_Object_Type objects."

       #Check for updated configs in Exchange.
       foreach ($Ex_Object_Config in $Ex_Object_Configs)
         {
           if ( $Ex_Object_Config.WhenChanged -gt $LastBackups["$($Ex_Object_Config.guid)"] )
             { 
               Write-Verbose "$Ex_Object_Type $($Ex_Object_Config.Name) has been updated since last backup."
               Write-Verbose "Last change: $($Ex_Object_Config.WhenChanged) Last backup: $($LastBackups["$($Ex_Object_Config.guid)"])"
               $Ex_Object_Config | 
               Export-Clixml "$Target_Directory\$Ex_Object_Folder\$Ex_Object_Type\$($Ex_Object_Config.guid).clixml" -Verbose
             }
         }
      }
  }        
    
  Remove-PSSession $ExSession         
        
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s