Backing up your Lync 2013 preview environment

Now Lync 2013 public preview is out for some weeks, it is time to start sharing some of my experiences.

One of the most basic traps when using Lync is, from my experience, the absence of a good backup. Most commonly a SQL backup, VM snapshot or full disk backup are being made. but thats not enough! however, make sure you have those as well, just to be sure.

As none of the above backups are on the application level, it is hard – or even impossible –  to restore from a tragical application error. And since we’re (going to) run beta software, you should be prepared for that. As the software seems stable enough, any small deviation from the tested scenario’s might end up in a failure. And when the system is non functional, you might also not be able to backup (user) data or move users to another pool without losing data!
When working with some user accounts, or lets say test accounts, you don’t want to lose that data. And even if you don’t care about this, you don’t want to be in the position that you need to re-build the complete environment (again).

You can prevent this all by one simple script: An application-level back-up. It’s not there by out of the box, but the powershell commands to get to such back-up are!

Before I put the script in this blogpost, I want to point out it’s actually an updated version of the script written by Traci Herr on MSDN. My thanks go out to the people who created this in the first place. I’ve updated it to work with Lync 2013, and let it make use of the newer powershell commands available. It’s not too fancy, but clean, plain and simple.

What will be backed up?

  • CSConfig
  • LISConfig
  • RGSConfig
  • UserConfig
  • FileStore
  • Certificates
  • Voice Configuration
  • SQL Databases

*note: The filestore section looks foor *all* file shares. When in co-existence with your Lync 2010 environment, it will also back-up this file share. In some ocasions I changed this section to only include the 2013 one.

As for now the “standard edition” most probably will be the most common version, I”ve built the script to work on one of those. But with a simple change in the section  “variables” (change PoolName and SQLInstance variables)  this can be undone. I deliberately didn’t include them as command-line options, as the script must be fairly easy and able to run unattended.
Last but not least, for the SQL backup I recommend a full SQL backup rather than using this script, but it might come in handy some time. however, this section might need some update to be more universal and complete.

That said, here is the script:

# Backup Script for Microsoft Lync 2013
# Put this into "c:\backup" folder

cd c:\backup
Import-Module 'C:\Program Files\Common Files\Microsoft Lync Server 2013\Modules\Lync\Lync.psd1'

# Get FQDN

$sysinfo = Get-WmiObject -Class Win32_ComputerSystem
$fqdn = “{0}.{1}” -f $sysinfo.Name, $sysinfo.Domain

# variables

$PoolName = "$fqdn"
$SQLInstance = "$fqdn\rtc"

# Backup CSConfig

New-Item c:\backup\CSconfig -type directory -force
$CSconfigFile = "c:\backup\CSconfig\{0:yyyy.MM.dd-HH.mm}-CSconfig.zip" -f (Get-Date)
export-csconfiguration -Filename $CSconfigFile -Force:$True

# Backup LISConfig

New-Item c:\backup\LISconfig -type directory -force
$LISconfigFile = "c:\backup\LISconfig\{0:yyyy.MM.dd-HH.mm}-LISconfig.zip" -f (Get-Date)
export-cslisconfiguration -Filename $LISconfigFile

# Backup RGSConfig

New-Item c:\backup\RGSconfig -type directory -force
$RGSconfigFile = "c:\backup\RGSconfig\{0:yyyy.MM.dd-HH.mm}-RGSconfig.zip" -f (Get-Date)
Export-CsRgsConfiguration -FileName $RGSconfigFile -source $PoolName

# Backup UserConfig

New-Item c:\backup\UserConfig -type directory -force
$UserConfigFile = "c:\backup\UserConfig\{0:yyyy.MM.dd-HH.mm}-Userconfig.zip" -f (Get-Date)
Export-CsUserData -PoolFqdn $PoolName -FileName $UserConfigFile

# Backup FileStore

New-Item c:\backup\FileStore -type directory -force

Get-CSService -filestore | Select-Object UncPath,PoolFqdn | ForEach-Object {$Pool = "c:\backup\FileStore\"+$_.PoolFqdn; invoke-expression 'ROBOCOPY.EXE $_.UncPath $Pool *.* /E /B /PURGE /R:1 /W:2'}

# Backup Certificates with Private Keys

New-Item c:\backup\Cert -type directory -force
dir cert:\localmachine\my |   
Where-Object { $_.hasPrivateKey } |   
Foreach-Object { [system.IO.file]::WriteAllBytes(    
"c:\backup\Cert\$($_.thumbprint).pfx",     
($_.Export('PFX', 'secret')) ) }
cd c:\backup

# Backup Voice Configurations

New-Item c:\backup\Voice -type directory -force
$DialPlan = "c:\backup\Voice\{0:yyyy.MM.dd}-DialPlan.xml" -f (Get-Date)
Get-CsDialPlan | Export-Clixml -path $DialPlan
$VoicePolicy = "c:\backup\Voice\{0:yyyy.MM.dd}-VoicePolicy.xml" -f (Get-Date)
Get-CsVoicePolicy | Export-Clixml -path $VoicePolicy
$VoiceRoute = "c:\backup\Voice\{0:yyyy.MM.dd}-VoiceRoute.xml" -f (Get-Date)
Get-CsVoiceRoute | Export-Clixml -path $VoiceRoute
$PSTNUsage = "c:\backup\Voice\{0:yyyy.MM.dd}-PSTNUsage.xml" -f (Get-Date)
Get-CsPstnUsage | Export-Clixml -path $PSTNUsage
$VoiceConfiguration = "c:\backup\Voice\{0:yyyy.MM.dd}-VoiceConfiguration.xml" -f (Get-Date)
Get-CsVoiceConfiguration | Export-Clixml -path $VoiceConfiguration
$TrunkConfiguration = "c:\backup\Voice\{0:yyyy.MM.dd}-TrunkConfiguration.xml" -f (Get-Date)
Get-CsTrunkConfiguration | Export-Clixml -path $TrunkConfiguration

# Backup All SQL databases

New-Item c:\backup\SQL -type directory -force
osql -E -S $SQLInstance -i c:\backup\backup.sql

Save this in a *.ps1 file.

And:

DECLARE @name VARCHAR(50) -- database name 
DECLARE @path VARCHAR(256) -- path for backup files 
DECLARE @fileName VARCHAR(256) -- filename for backup 
DECLARE @fileDate VARCHAR(20) -- used for file name 

SET @path = 'C:\Backup\SQL' 

SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112) 

DECLARE db_cursor CURSOR FOR 
SELECT name 
FROM master.dbo.sysdatabases 
WHERE name NOT IN ('master','model','msdb','tempdb') 

OPEN db_cursor 
FETCH NEXT FROM db_cursor INTO @name 

WHILE @@FETCH_STATUS = 0 
BEGIN 
           SET @fileName = @path + @name + '_' + @fileDate + '.BAK' 
           BACKUP DATABASE @name TO DISK = @fileName 

           FETCH NEXT FROM db_cursor INTO @name 
END 

CLOSE db_cursor 
DEALLOCATE db_cursor

Save this as backup.sql.

Save both files to c:\backup on your Lync 2013 front-end server. Now you can run the PS1 powershell script manually (but elevated: “run as administrator”) to start the on-line backup process, or create a schedulded task to do so for you!

All output will be saved in c:\backup and will take approximately 50 MB, not counting the lync file share sizes. Zip it all and you have a complete application-level backup!

Make sure you run this periodically, and/or before making changes to the environment. you never now if, or when, something goes wrong. You are warned.

Leave a Reply

Your email address will not be published. Required fields are marked *