Wednesday, 2 May 2012

Automating Backups of Lync 2010 Configuration

As we planned for Lync DR it became clear that I needed a way to create backups of our Lync server and user configuration and so that we could restore service in an alternate site in the event of a disaster.

Lync provides Lync PowerShell cmdlets in the Lync Management Shell for backing up some data (the CMS and LIS databases), there is a resource kit tool for backing up Response Groups, and the DbImpExp.exe tool for backing up user data in the event you need to re-home users to another pool and their primary registrar is unavailable. The DbImpExp tool is limited in that for a Lync Server 2010, Standard Edition server you must run it locally because the SQL instance is configured to only accept local connections.

To bring these tools together, and to centralise the process for taking Lync config backups, I created this script. It requires the Lync 2010 resource kit and the Lync admin tools installed where it is run. It will enumerate the topology and back up RGS data for all app pools and user data for all registrars. You'll need to make sure that WinRM is configured to accept remote connections on Lync Standard Edition servers so that the DbImpExp command can be invoked remotely.


#
# Backup-LyncConfig.ps1
# Written by Ben Lye - www.onesimplescript.com
#
# This script will back up the configuration of all Lync Server 2010 servers in the topology
# It is designed to be run centrally and store all the backups in a central location
#
# The Lync Resource Kit in order to back up response groups:
# (http://www.microsoft.com/en-us/download/details.aspx?id=21165)
#
# The Lync support tools are required to back up Lync user data, and PowerShell Remoting must be
# enabled on Standard Edition servers in order to run the backup remotely.
#

# Import the Lync PowerShell Module
Import-Module Lync

# Import the resource kit script for backing up response groups
Import-Module 'C:\Program Files\Microsoft Lync Server 2010\ResKit\RgsImportExport.ps1'

# Define a path to store all the backup files
$BackupPath = "C:\LyncBackups\Backups\"

# Get the date string to use in the file names
# Use ddd-HH00 will result in strings like Wed-1000, meaning files will be overwritten weekly
# and also hourly if the script is run more than once an hour
# Other strings could be used so that files were overwritten daily, or not at all
$Datestamp = Get-Date -Format ddd-HH00

# Export the Central Management Store data
Write-Host
Write-Host "Exporting Central Management Store"

# Set the full local path of the backup file
$CmsBackupFile = $BackupPath + $Datestamp + "_CsCmsConfig.zip"

# Check if backup file already exists, remove it if it does
If (Test-Path $CmsBackupFile ) { Remove-Item $CmsBackupFile }

# Export the CMS configuration
Export-CsConfiguration –FileName $CmsBackupFile

# Export the LIS Data
Write-Host
Write-Host "Exporting Location Information Store"

# Set the full local path of the backup file
$LisBackupFile = $BackupPath + $Datestamp + "_CsLisConfig.zip"

# Check if backup file already exists, remove it if it does
If (Test-Path $LisBackupFile) { Remove-Item $LisBackupFile }

# Export the LIS configuration
Export-CsLisConfiguration –FileName $LisBackupFile

# Back up the response groups
Write-Host
Write-Host "Exporting Response Group Configuration"

# Get the Application Server services - App Services are where response groups run
$AppServices = Get-CsService -ApplicationServer

# Loop through each App Service
ForEach ($Service in $AppServices) {
 Write-Host $Service.PoolFqdn

 # Set the full local path of the backup file, including the FQDN of the app server
 $RgsBackupFile = $BackupPath + $Datestamp + "_" + $($Service.PoolFqdn) + "_RgsConfig.zip"

 # Check if backup file already exists, remove it if it does
 If (Test-Path $RgsBackupFile) { Remove-Item $RgsBackupFile }

 # Export the Response Group configuration
 Export-CsRgsConfiguration ApplicationServer:$($Service.PoolFqdn) –FileName $RgsBackupFile
}

# Back up the user data
Write-Host 
Write-Host "Exporting user data"
# Get all the UserServers - these are the servers containing the user-specific data
$UserServices = Get-CsService -UserServer

# Loop through the UserServers
ForEach ($Service in $UserServices) {
 # Output the name of the pool we are backing up
 Write-Host $Service.PoolFqdn

 # Determine the database server and instance name for the pool
 $DBServer = $Service.UserDatabase.Split(":")[1]
 
 # Get the user database service for the pool
 $DBService = Get-CsService -UserDatabase -PoolFqdn $DBServer

 # If a SQL instance is used append it to the database path
 If ($DBService.SqlInstanceName) { 
  $DBPath = $DBServer + "\" + $DBService.SqlInstanceName 
 } Else {
  $DBPath = $DBServer
 }
 
 # Check if this is an Enterprise or Standard Edition pool
 # On Standard Edition the User Database service is co-located on the pool server and cannot be accessed remotely
 # On Enterprise Edition the User Database service is not co-located and can be accessed remotely

 # Get the details of the pool
 $Pool = Get-CSPool $Service.PoolFqdn
 
 If ($Pool.Services -like "*UserDatabase*") { 
  # This is a Standard Edition pool, run the command on the remote server and copy the files back
  # Invoke the command on the remote server using PowerShell remoting
  Invoke-Command -ComputerName $Service.PoolFqdn -ArgumentList $DBPath -ScriptBlock {
   param($DBPath) 
   $DBImpExp = "C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"; 
   & $DBImpExp /hrxmlfile:"C:\Windows\Temp\CsUserBackupFile.xml" /sqlserver:$DBPath
  }
  
  # Define remote and local file names so that he file can be copied locally
  $RemoteFile = "\\" + $Service.PoolFqdn + "\" + "C$\Windows\Temp\CsUserBackupFile.xml"
  $LocalFile = $BackupPath + $DateStamp +"_" + $($Service.PoolFqdn)+ "_UserData.xml"
  
  # Copy the file locally
  Copy-Item $RemoteFile $LocalFile 
  
 } Else { 
  # This is an enterprise pool, run the command locally
  # Set the name of the backup file based on the pool FQDN and current date/time
  $LocalFile = $BackupPath + $DateStamp +"_" + $($Service.PoolFqdn)+ "_UserData.xml"
  
  # Set the  path to the DBImpExp execuatable on the remote machine
  $DBImpExp = "C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"; 
  
  # Run the backup command
  & $DBImpExp /hrxmlfile:$LocalFile /sqlserver:$DBPath 
 }
 
 Write-Host
}

 
Download Script

A description of the process for backing up Lync configuration data can be found here:
http://technet.microsoft.com/en-us/library/hh202170.aspx

Information about permissions required for backing up Lync data is here:
http://technet.microsoft.com/en-us/library/hh202171.aspx

- Ben

3 comments:

  1. It works great, this solved my backup plan for Lync perfectly as I'm not all that good at scripting. I just need to structure it so it takes daily backups and then set up a schedule to to offload it to another server. Thanks a lot for this!

    ReplyDelete
  2. Do you have any script to restore?

    ReplyDelete
  3. Restoring is a bit more complicated - it depends what you need to restore, where, and why.

    - Ben

    ReplyDelete