Wednesday, July 5, 2017

PowerShell Script to Backup AudioCodes Gateways (updated for 7.0 and 7.2)

A few years ago I created a PowerShell script that would backup AudioCodes gateways. It's gone through several iterations as AudioCodes has changed how they do authentication. Now with 7.0 and 7.2 out in the wild, I again found that I needed to update this script again to support the changes to the user interface.

Fortunately I've got great friends and Mitch Steiner had been messing with AudioCodes new API to pull some interesting metrics for our T2M Cloud and he let me know that he stumbled upon a way to pull the .ini configuration using the REST API. The new REST API reduced the amount of code to do a backup down to literally one line. Now obviously it would be cool to have a script that detected which AudioCodes version it was connected to, so it is more than just one line in the script below. I also found a way to "Burn" the configuration on 7.0 and 7.2 using the API. So that is part of the script and executes just before backup.

Couple of key items before you run the script below.
  • If you are running on a Windows 7 or other workstation you'll need to set your PowerShell Execution Policy.
  • Next you will need to install a package called cURL that is a command line tool for interacting with web pages. It is required to work with the Forms Based Auth that audiocodes uses. I used a new tool to install it called Chocolatey, which is the equivalent of RPM packages for Windows. Here is the page for cURL (http://chocolatey.org/packages/curl) and here is the main page for Chocolatey (http://chocolatey.org/)
  • PowerShell has an alias for curl that you'll need to remove. The command is Remove-Item alias:curl 
Without further adieu... I give you the AudioCodes backup script that will backup any 6.4, 6.6, 6.8, 7.0, or 7.2 AudioCodes Gateway/SBC. 

# Script to Backup AudioCodes Gateways# Created By Jonathan McKinney (blog.ucomsgeek.com)# Disclaimer: You running this script means you won't blame Jonathan McKinney or his employer if this breaks your stuff. This script is provided AS IS without warranty of any kind.

# User Modifiable Variables
$username = "Admin"
$password = "Admin"
$address = "m4000.ucomsgeek.com"
$backuppath = "c:\scripts\backups\"


# Variable Initialization
$filename = $null
$statuscodeeval = $null


#Function to detect if Forms Auth is present
function DetectAuthType ($ad)
{
    $loginurl = $null
    
    $loginurl = "http://" + $ad + "/api"
    $statuscode = curl -o null.txt $loginurl -w '%{http_code}'
    If ($statuscode -eq "404")
    {
        $loginurl = "http://" + $ad + "/"
        $statuscode = curl -o null.txt $loginurl -w '%{http_code}'
        Write-host `r`n "Status Code " $statuscode
        If ($statuscode -eq "401")
        {
            $statuscodeeval = "basic"
        }
        ElseIf ($statuscode -eq "203")
        {
            $statuscodeeval = "forms"
        }
        Else
        {
            $statuscodeeval = "neither"
        }
    }
    ElseIf ($statuscode -eq "401")
        {
            $statuscodeeval = "api"
        }
    Return $statuscodeeval
    Remove-Item null.txt
}


 # Function to Authenticate with Forms Auth
function AuthenticateForms ($un, $pw, $ad)
{
     $login1sregex = "\<s\>(\d*)\<\/s\>"
     $login1rregex = "\<r\>(.*)\<\/r\>"
     $a1 = $null
     $loginusername = $null
     $loginurl = $null
     $login1webpage = $null
     $login1spattern = $null
     $login1rpattern = $null
     $hashByteArray1 = $null
     $hashByteArray2 = $null
     $passwordhash = $null
     $resultwebpage = $null
     $formsbasedauth = $null
     
     Write-Host `r`n 'Forms Authentication' `r`n
     $login1username = "c1=" + $un
     $loginurl = "http://" + $ad + "/UE/Login"
     $login1webpage = curl $loginurl --data-urlencode "t=1" `
                                     --data-urlencode "c0=0" `
                                     --data-urlencode $login1username `
                                     --header "X-Requested-With: XMLHttpRequest" `
                                     -c cookiejar.txt `
                                     --header "Cookie: aclogname=; C2=ct" `
                                     --user-agent "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"

      $login1spattern = $login1webpage -split "`n" | Select-String -pattern $login1sregex -Allmatches | % { $_.Matches | % { $_.groups[1].Value } }

      $login1spattern = "s=" + $login1spattern
     $login1rpattern = $login1webpage -split "`n" | Select-String -pattern $login1rregex -Allmatches | % { $_.Matches | % { $_.groups[1].Value } }

      $cryptoServiceProvider = [System.Security.Cryptography.SHA256CryptoServiceProvider]
     $hashAlgorithm = New-Object $cryptoServiceProvider
     $hashByteArray1 = $hashAlgorithm.ComputeHash($([Char[]]$password))
     foreach ($byte in $hashByteArray1)
     {
          $a1 += "{0:x2}" -f $byte
     }
     
     $a2 = $username + ":" + $login1rpattern + ":" + $a1
     $hashByteArray2 = $hashAlgorithm.ComputeHash($([Char[]]$a2))

      foreach ($byte in $hashByteArray2)
     {
          $passwordhash += "{0:x2}" -f $byte
     }
     
     $passwordhash = "c1=" + $passwordhash
     $resultwebpage = curl $loginurl --data-urlencode "t=1" `
                                     --data-urlencode $login1spattern `
                                     --data-urlencode "c0=1" `
                                     --data-urlencode $passwordhash `
                                     --header "X-Requested-With: XMLHttpRequest" `
                                     -c cookiejar.txt `
                                     --header "Cookie: aclogname=; C2=ct" `
                                     --user-agent "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
}


# Function to Backup Gateway WITHOUT Forms Auth
function BackupBasic ($un, $pw, $ad, $path)
{
     $regex = "BOARD.*\.ini"
     $webclient = $null
     $configurl = $null
     $backupurl = $null
     $webpage = $null
     $pattern = $null
     $backupfilename = $null

     $webclient = new-object System.Net.WebClient
     $webclient.Credentials = New-Object System.Net.NetworkCredential($un, $pw)

     Write-Host `r`n 'Detecting .ini name' `r`n
     $configurl = "http://" + $ad + "/ConfigurationFile"
     $webpage = $webclient.DownloadString($configurl)
     $pattern = $webpage -split "`n" | Select-String -pattern $regex -Allmatches | % { $_.Matches | % { $_.Value } }
     Write-Host `r`n 'Detected Board Filename ' $pattern

      Write-Host `r`n 'Backing up ' $ad `r`n
     $backupurl = "http://" + $ad + "/FS/" + $pattern
     $backupfilename = $path + $pattern
     $webclient.DownloadFile($backupurl,$backupfilename)
     Write-Host `r
}


# Function to Detect the Backup Filename with Forms Auth for the Audiocodes Configuration File
function DetectFilenameForms ($ad)
{
     $fnregex = "BOARD.*\.ini"
     $configurl = $null
     $fnpat = $null
     $configwebpage = $null

     Write-Host `r`n 'Detecting .ini name' `r`n
     $configurl = "http://" + $ad + "/ConfigurationFile"
     $configwebpage = curl $configurl -b cookiejar.txt
     $fnpat = $configwebpage -split "`n" | Select-String -pattern $fnregex -Allmatches | % { $_.Matches | % { $_.Value } }

     Write-Host `r`n 'Detected Board Filename ' $fnpat
     return $fnpat
}


# Function to Backup Gateway with Forms Auth
function BackupGatewayForms ($ad, $path, $fn)
{
     $backupurl = $null
     $backupfilename = $null
     
     Write-Host `r`n 'Backing up ' $ad `r`n
     $backupurl = "http://" + $ad + "/FS/" + $fn
     $backupfilename = $path + $fn
     curl -o $backupfilename $backupurl -b cookiejar.txt
     Write-Host `r
}

function BackupGatewayAPI ($un, $pw, $ad, $path)
{
    $backupurlsc = $null
    $backupurlini = $null
    $backupfilename = $null
    $securepw = $null
    $cred = $null

    $backupurlsc = "http://" + $ad + "/api/v1/actions/saveConfiguration"
    $backupurlini = "http://" + $ad + "/api/v1/files/ini"
    $addressfilename = $ad.Replace(“.”,”-”)
    $backupfilename = $path + "BOARD.ini"
    Write-Host $backupfilename
    $securepw = ConvertTo-SecureString -String $pw -AsPlainText -Force
    $cred = new-object System.Management.Automation.PSCredential ($un, $securepw)
    Invoke-RestMethod $backupurlsc -Method post -Credential $cred
    Invoke-RestMethod $backupurlini -Method get -Credential $cred -OutFile $backupfilename -verbose
    
    Write-Host  `r
}


# Function to Logoff Audiocodes with Forms Auth after finishing work
function LogoffForms ($ad)
{
     $logoffurl = $null
     $logoffwebpage = $null
     
     $logoffurl = "http://" + $ad + "/PressLogOff"
     $logoffwebpage = curl $logoffurl -b cookiejar.txt
     Remove-Item cookiejar.txt
}


# Main Script

 $formsbasedauth = DetectAuthType $address

 if ($formsbasedauth -eq "forms")
{
     AuthenticateForms $username $password $address
     $filename = DetectFilenameForms $address
     BackupGatewayForms $address $backuppath $filename
     LogoffForms $address
}
ElseIf ($formsbasedauth -eq "basic")
{
     BackupBasic $username $password $address $backuppath
}
ElseIf ($formsbasedauth -eq "api")
{
     BackupGatewayAPI $username $password $address $backuppath
}
Else
{
     Write-Host "Something went really wrong... couldn't detect Authentication type... Might I suggest Wireshark"
}