Thursday, 3 November 2011

Scripting Backups of NET UX2000 Gateways

As part of the Lync Server 2010 deployment I'm working on we have deployed a number of NET UX2000 media gateways. These gateways are working well, and have an excellent user interface, but one feature that is missing from the interface is the ability to make scheduled backups of the configuration.

To work around this limitation I wrote a PowerShell script which uses cURL to interact with the UX2000 web interface to create a backup of the configuration - cURL is "a command line tool for transferring data with URL syntax".

In a nutshell, the script creates an authenticated session by submitting a username and password to the login form, gets the session ID from the returned header, uses the authenticated session ID to get the backup file, then logs out.

Once the backup file is downloaded the script uses MD5 hashes to compare the new backup with the next most recent, and discards the new file if they are the same - this way I only have to save backup files when something in the configuration has actually changed.

This entire backup process takes just a few seconds for each UX2000 in my deployment - a massive time saving compared to creating all the backups manually, and because backups are only retained when something changes, I can schedule the script to run as often as I like.


# Record a transcript
Start-Transcript -Path ".\logfile.log"

# Set the working directory
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath

# Function to create an MD5 hash for file comparison
Function Get-MD5Hash ($Filename) {
  $MD5provider = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
  $FileInfo = New-Object System.IO.FileInfo($Filename)

  $Stream = $FileInfo.OpenRead()
  $MD5Bytes = $MD5provider.ComputeHash($Stream)
  [void] $Stream.Close()

  ForEach ($Byte in $MD5Bytes) {
   $Hash = $Hash + $Byte.ToString("X2")
  }
  Return $Hash
}

# Array of all the UX gateways
$Gateways = ( "ux2000-nyc.example.com",
           "ux2000-tyo.example.com",
           "ux2000-lon.example.com",
         )
         
# Login credentials
$Username = "admin"
$Password = "password"

# Backup each gateway
ForEach ($Gateway in $Gateways) {
 # Output the gateway name
 $Gateway
 
 # Create a folder for this gateway's backups
 If (-Not (Test-Path $Gateway.Split(".")[0])) { $Null = New-Item -Name $Gateway.Split(".")[0] -Type Directory}
  
 # Use the gateway name and the date to create the filename for this backup
 $Filename = "$($Gateway.Split(".")[0])\$($Gateway.Split(".")[0])_$(Get-Date -uformat "%Y-%m-%d-%H%M").tar.gz"

 # Create a temp file name
 $TempFilename = "$($Gateway.Split(".")[0])\$(Get-Date -uformat "%Y%m%d-%H%M").tmp"

 # Get the name of the most recent backup file
 $Backups = Get-ChildItem $Gateway.Split(".")[0] | Sort-Object -Property LastWriteTime -Desc
 If (($Backups | Measure-Object).Count -eq 1) {
  $PreviousFilename = $Gateway.Split(".")[0] + "\" + ($Backups).Name
 } ElseIf (($Backups | Measure-Object).Count -gt 1) {
  $PreviousFilename = $Gateway.Split(".")[0] + "\" + ($Backups)[0].Name
 } Else {
  $PreviousFilename = $Null
 }

 # Login to the UX and get the session ID
 $Login = .\curl --insecure https://$Gateway/cgi/login/login_do.php --data "username=$Username&password=$Password&passwordNonce-Hidden=password&loginbutton=Login" -i -s
 $SessionID = $Login[1].split("=;")[1]
 
 # Get the backup
 .\curl.exe --cookie PHPSESSID=$SessionID --insecure https://$Gateway/cgi/system/configBackup.php?action=backup --data "action=backup" -o $TempFilename
 
 # If we made a backup, and there is an older one, compare it to the last one and discard it if they are the same
 If (($PreviousFilename -ne $null) -and (Test-Path $TempFilename)) {

  # Get an MD5 Hash of both files
  $PreviousHash = Get-MD5Hash ("$PreviousFilename")
  $TempHash =  Get-MD5Hash ("$TempFilename")
  
  Write-Host
  Write-Host $PreviousFilename,"=",$PreviousHash
  Write-Host $TempFilename,"=",$TempHash
 
  # Remove today's backup file if the hashes match
  If ($TempHash -eq $PreviousHash) {
   Write-Host
   Write-Host "File hashes match, discarding temp file"
   Remove-Item $TempFilename
  } Else {
   Write-Host
   Write-Host "File hashes don't match, keeping backup file"
   Move-Item $TempFilename $Filename -Force
  }
 }
 
 $Logout = .\curl.exe --cookie PHPSESSID=$SessionID --insecure --silent https://$Gateway/cgi/login/logout.php
 Write-Host
 Write-Host
} 

Stop-Transcript
 
Download Script

In order to use this script in your own deployment you would need to change the $Username, $Password, and $Gateways variables to suit your needs, and the user account specified must exist on each gateway to be backed up.

The cURL executable needs to be in the same directory as the PowerShell script and working (try it in a command prompt first) - the current version of cURL needs the Visual C++ 2010 redistributable package installed.

- Ben

3 comments:

  1. Updated to support UX software release 2.0.0.

    - Ben

    ReplyDelete
  2. Updated to support UX software release 2.2.0

    - Ben

    ReplyDelete
  3. Awesome script....however, my configs are being backed up daily without changes. If I run the script back to back then the MD5 hash detect they are the same and skips. However, when I run this as a scheduled task it backs up everyday. The scheduled task (and the manual run) is running on a Virtual(VMware) Windows 2003 R2 server. Any ideas?

    ReplyDelete