The greatest challenge to any thinker is stating the problem in a way that will allow a solution

Bertrand Russell

By

On 26 Apr 2012

PowerShell

Tags: , , ,


I manage a number of Vyatta routers, for which the config changes irregularly.  And whilst I do keep an offline copy of their configs, I do this in a manual fashion, which means its not done reliably, which means its not a reliable backup solution.

Hence I crafted a simple PowerShell script which takes a backup of the routers config if its changed since the last backup…

The script makes use of the Renci SSH.NET library that I’ve used before, and uses the SFTP (SSH File Transfer Protocol, not be be confused with FTPS, FTP over SSL).   I’ve set-up a limited user account on the routers so that I know my script can cause no (well limited) harm, eg

set system login user script-user authentication plaintext-password password
set system login user script-user level operator

The script only takes backup’s of routers whose config has changed since the last backup was taken

 
$BackupDir = "D:\Backups\vyatta"         # Path to backup store
$VyattaUser = "script-user"
$VyattaPass = "password"
 
# Create master array list of router names
$Routers = @()
$Routers += "oca-ro-vy-w1"
$Routers += "oca-ro-vy-w2"
$Routers += "oca-ro-vy-w3"
 
# Functions ================================================================================================================
 
function New-SshSession ([string]$server, [string]$user, [string]$pass, [int]$port = 22) {
    #Write-Host "Create SSH Client - New-Object Renci.SshNet.SshClient($server, $port, $user, $pass)"
    $Client = New-Object Renci.SshNet.SshClient($server, $port, $user, $pass)
 
    try {
        $Client.Connect()
    } catch {
        throw $_
    }
 
    if ($Client.IsConnected) {
        Return $Client
    } else {
        throw "SSH client connect failed..!"
        Return 0
    }
}
 
function New-SshCommand ([Renci.SshNet.SshClient]$SshClient, [string]$command) {
    if ($SshClient.IsConnected) {
        $SshCommand = $SshClient.RunCommand($command)
    } else {
        throw "SshClient is not connected!"
    }
    Return $SshCommand
}
 
function Get-LastBackupDate ([string]$RouterName) {
    $files = Get-Item ($BackupDir + "\" + $RouterName + "*")
    if (!$files) {
        Return 0
    }
 
    # If more than one backup, find the latest date
    if ($files.count) {
        $LatestDate = 0
        foreach ($file in $files) {
            $DateBits = ($file.BaseName.Replace($RouterName + "_", "")).Split("-_")
            try {
                $DateStamp = Get-Date -Year $DateBits[0] -Month $DateBits[1] -Day $DateBits[2] -Hour $DateBits[3] -Minute $DateBits[4]
            } catch {
                Write-Host ("$RouterName - invalid date on filename " + $file.BaseName)
                Continue
            }
            if ($DateStamp -gt $LatestDate) {
                $LatestDate = $DateStamp
            }
        }
        Return $LatestDate
    } else {
        $DateBits = ($files.BaseName.Replace($RouterName + "_", "")).Split("-_")
        try {
            $DateStamp = Get-Date -Year $DateBits[0] -Month $DateBits[1] -Day $DateBits[2] -Hour $DateBits[3] -Minute $DateBits[4]
        } catch {
            Write-Host ("$RouterName - invalid date on filename " + $file.BaseName)
            Continue
        }
        Return $DateStamp
    }
}
 
# The Script   ===============================================================================================================
 
try {
    $RenciAss = [reflection.assembly]::LoadFrom( "C:\Users\simonstrutt\Documents\Scripts\lib\RenciSSH\Renci.SshNet3.5.dll" )
} catch {
    Write-Error $_
    throw "Unable to find/load the SshNet DLL"
    exit
}
 
# Go through each router and backup as required
foreach ($router in $Routers) {
    [datetime]$LastBackup = Get-LastBackupDate $router
 
    # Connect to router and get last save date of running config
    try {
        $SshClient = New-SshSession -server $router -user $VyattaUser -pass $VyattaPass
        $SshCommand = New-SshCommand -SshClient $SshClient -Command "ls -l --time-style=long-iso /opt/vyatta/etc/config/config.boot"
    } catch {
        Write-Host ("SSH fail $router: " + $_)
        Continue
    }
 
    if ($SshCommand.ExitStatus) {
        Write-Host ("SSH Cmd fail: " + $SshCommand.Error)
        Continue
    }
    [datetime]$ConfigLastChange = ( [regex]::Matches($SshCommand.Result, "\b201\d-(0|1)\d-[0-3]\d [0-2]\d:[0-5]\d") )[0].Value
 
    if ($ConfigLastChange -lt $LastBackup) {
        Write-Host ("$router backup NOT required, last change: " + $ConfigLastChange.ToString("yyyy-MM-dd HH:mm") + " last backup: " + $LastBackup.ToString("yyyy-MM-dd HH:mm"))
    } else {
        Write-Host ("$router backup IS required, last change: " + $ConfigLastChange.ToString("yyyy-MM-dd HH:mm") + " last backup: " + $LastBackup.ToString("yyyy-MM-dd HH:mm"))
 
        # Open up SFTP connection
        $SftpClient = New-Object Renci.SshNet.SftpClient($SshClient.ConnectionInfo)
        $SftpClient.Connect()
 
        # Prepare Rx'ing stream
        $RxFile = $BackupDir + "\" + $router + "_" + $ConfigLastChange.ToString("yyyy-MM-dd_HH-mm") + ".cfg"
        $RxFileStream = [System.IO.File]::Create($RxFile)
 
        # Write remote file from SFTP connection to local file
        $LengthExpected = ($SftpClient.Get("/opt/vyatta/etc/config/config.boot")).Length
        $SftpClient.DownloadFile("/opt/vyatta/etc/config/config.boot", $RxFileStream)
        if ( ($LengthExpected -ne $RxFileStream.Length)) {
            Write-Host ("Error: Inconsistent download, expected $LengthExpected bytes, received " + $RxFileStream.Length + " bytes!")
             $RxFileStream.Dispose()
        } else {
            $RxFileStream.Flush()
            $RxFileStream.Close()
            $RxFileStream.Dispose()
            Write-Host ("Written " + $LengthExpected + " bytes to $RxFile")
        }
 
        $SftpClient.Disconnect()
        $SftpClient.Dispose()
    }
 
    # Clear down connections and objects
    $SshCommand.Dispose() | Out-Null
    $SshClient.Disconnect() | Out-Null
    $SshClient.Dispose() | Out-Null
}

 


Leave a Reply

XHTML: You can use these tags if you know what they are: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

ERROR: si-captcha.php plugin says GD image support not detected in PHP!

Contact your web host and ask them why GD image support is not enabled for PHP.

ERROR: si-captcha.php plugin says imagepng function not detected in PHP!

Contact your web host and ask them why imagepng function is not enabled for PHP.