function Invoke-SSHCommand {
<#
.SYNOPSIS
Invoke SSH Command on a Remote Computer
.DESCRIPTION
Invoke-SSHCommand uses PuTTY's plink.exe to execute a SSH command on a remote system
.EXAMPLE
Invoke-SSHCommand -Command "uname -a" -ComputerName "myComputer"

DESCRIPTION
-----------
Run uname against the remote computer

.EXAMPLE
$user = "testuser"
$userpw = Read-Host -Prompt "Enter Password" -AsSecureString
Invoke-SSHCommand -Command "touch /tmp/PowerShellHasBeenHere" -ComputerName "myComputer" -UserName $user -SecurePassword $userpw

DESCRIPTION
-----------
Creates a blank file in /tmp on the remote computer.  This time we are passing the user name and password
as parameters
#>

    [CmdletBinding()] param (
        [Parameter(Mandatory=$true)] [String]$ComputerName,
        [Parameter(Mandatory=$true)] [String]$Command,
        [Parameter(Mandatory=$false)] [String]$PathToPlink="C:\Program Files (x86)\PuTTY\plink.exe",
        [Parameter(Mandatory=$false)] [String]$UserName,
        [Parameter(Mandatory=$false)] [Security.SecureString]$SecurePassword,
        [Parameter(Mandatory=$false)] [Switch]$AutoAcceptKeys
    )

    process {
    
        #check for plink.exe file
        Write-Host ""
        if(! (Test-Path $PathToPlink) ) {
            Write-Host "ERROR: $PathToPlink not found" -ForegroundColor Magenta
            return
        }
        #get username if not passed
        if(!$UserName) {
            $UserName = Read-Host -Prompt "Enter User Name"
        }
        #get password if not passed
        if(!$SecurePassword) {
            $SecurePassword = Read-Host -Prompt "Enter Password" -AsSecureString
        }
        Write-Host ""
        
        #convert from secure pw for command execution
        $pw = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword))
        
        #formulate plink command
        if($AutoAcceptKeys) {
            $plinkCommand = "`"echo yes | `"$PathToPlink`" -ssh -l $UserName -pw $pw $ComputerName `"$Command`"`""
        }
        else {
            $plinkCommand = "`"`"$PathToPlink`" -ssh -l $UserName -pw $pw $ComputerName `"$Command`"`""
        }
        
        #run plink command
        $result = cmd /c $plinkCommand
        
        return $result
    }
}

function Get-HPOAFirmwareVersion {
<#
.SYNOPSIS
Get OA Firmware Version
.DESCRIPTION
Get-HPOAFirmwareVersion will return the firmware version on the OA specified
.EXAMPLE
Get-HPOAFirmwareVersion -OAHostName "HPOA1"

DESCRIPTION
-----------
This command will return the version of firmware installed on HPOA1
.EXAMPLE
$SecurePassword = Read-Host "Enter Password" -AsSecureString
Get-HPOAFirmwareVersion  -OAHostName "HPOA1" -UserName "Administrator" -SecurePassword $SecurePassword

DESCRIPTION
-----------
This command specifys the login credentials for the OA so you don't get prompted
#>
    [CmdletBinding()] param (
        [parameter(Mandatory=$true)] [string]$OAHostName,
        [parameter(Mandatory=$false)] [string]$UserName,
        [parameter(Mandatory=$false)] [System.Security.SecureString]$SecurePassword,
        [Parameter(Mandatory=$false)] [Switch]$AutoAcceptKeys
    )
    PROCESS {
    
        #get missing params
        if( ! $UserName ) {
            $UserName = Read-Host "Enter UserName"
        }
        if( ! $SecurePassword ) {
            $SecurePassword = Read-Host "Enter Password for $UserName" -AsSecureString
        }
        
        if($AutoAcceptKeys) {
            $oaInfo = Invoke-SSHCommand -ComputerName $OAHostName -Command "show oa info" -UserName $UserName -SecurePassword $SecurePassword -AutoAcceptKeys | ?{$_ -match "Firmware Ver."}
        }
        else {
            $oaInfo = Invoke-SSHCommand -ComputerName $OAHostName -Command "show oa info" -UserName $UserName -SecurePassword $SecurePassword | ?{$_ -match "Firmware Ver."}
        }
        
        return $oaInfo
    }
}

function Update-HPOAFirmware {
<#
.SYNOPSIS
Update OA Firmware from FTP site
.DESCRIPTION
Update-HPOAFirmware will attempt to upgrade OA firmware from a bin file hosted on an FTP server
.EXAMPLE
Update-HPOAFirmware -OAHostName "HPOA1" -FTPConnectionString "ftp://iss:tools4AL@ftp.usa.hp.com/OAfw/hpoa370.bin"

DESCRIPTION
-----------
This command will update HPOA1 to firmware 3.70 using the user iss and password tools4AL from HP's OA firmware FTP repo
.EXAMPLE
$SecurePassword = Read-Host "Enter Password" -AsSecureString
Update-HPOAFirmware -OAHostName "HPOA1" -FTPConnectionString "ftp://myftpserver/hpoa370.bin" -UserName "Administrator" -SecurePassword $SecurePassword

DESCRIPTION
-----------
This command will update HPOA1 from myftpserver to 3.70 using anonymous ftp.  The username and password for the OA
are specified here to prevent being prompted later
#>
    [CmdletBinding()] param (
        [parameter(Mandatory=$true)] [string]$OAHostName,
        [parameter(Mandatory=$true)] [string]$FTPConnectionString,
        [parameter(Mandatory=$false)] [switch]$MakeActiveIfStandby,
        [parameter(Mandatory=$false)] [string]$UserName,
        [parameter(Mandatory=$false)] [System.Security.SecureString]$SecurePassword,
        [Parameter(Mandatory=$false)] [Switch]$AutoAcceptKeys
    )
    PROCESS {
        
        #get missing params
        if( ! $UserName ) {
            $UserName = Read-Host "Enter UserName"
        }
        if( ! $SecurePassword ) {
            $SecurePassword = Read-Host "Enter Password for $UserName" -AsSecureString
        }
        
        try {
        
            #get current and new firmware version to check if update is required
            ###if user changes filename or HP changes it's bin filename format, this method of version check will no longer work and exception will hopefully be caught###
            $oaCurrentFirm = Get-HPOAFirmwareVersion -OAHostName $OAHostName -UserName $UserName -SecurePassword $SecurePassword
            $currentVersion = [int]($oaCurrentFirm.Substring($oaCurrentFirm.IndexOf(':')+2, 4)).Replace(".","")
            $newBinFileName = $FTPConnectionString.Substring($FTPConnectionString.LastIndexOf('/')+1,$FTPConnectionString.Length-$FTPConnectionString.LastIndexOf('/')-1)
            $newVersion = [int]$newBinFileName.Substring(4,3)
            
            #update needed
            if($newVersion -gt $currentVersion) { 
            
                $oaRole = Invoke-SSHCommand -ComputerName $OAHostName -Command "show oa status" -UserName $UserName -SecurePassword $SecurePassword | ?{$_ -match "Role:"}
                
                if($oaRole -eq $null -or $oaRole -eq "") {
                    Write-Host "`nERROR: Invoking command on $OAHostName`n" -ForegroundColor Magenta
                    return
                }
                
                #if OA is standby either try to make active or exit
                if($oaRole -match "Standby") {
                    
                    if(! $MakeActiveIfStandby) {
                        Write-Host "`nOA $OAHostName is the Standby OA"
                        $answer = Read-Host "Would you like to attempt to fail over to Active [y/n] "
                        
                        if($answer -ne "y") {
                            return
                        }
                    }
                    
                    $standbyToActive = Invoke-SSHCommand -ComputerName $OAHostName -Command "force takeover" -UserName $UserName -SecurePassword $SecurePassword
                    
                    #wait for OA to become the active
                    while ($oaRole -notmatch "Active") {
                        Start-Sleep -Seconds 60
                        $oaRole = Invoke-SSHCommand -ComputerName $OAHostName -Command "show oa status" -UserName $UserName -SecurePassword $SecurePassword | ?{$_ -match "Role:"}
                    }
                }
                
                #perform update if OA is active
                if($oaRole -match "Active") {
                    $oaUpdate = Invoke-SSHCommand -ComputerName $OAHostName -Command "UPDATE IMAGE $FTPConnectionString" -UserName $UserName -SecurePassword $SecurePassword
                }
                #otherwise OA is not active so exit
                else {
                    Write-Host "`nERROR: $OAHostName couldn't be made active`n" -ForegroundColor Magenta
                    return
                }
            }
            else {
                $oaUpdate = "No Update Required for $OAHostName"
            }
            return $oaUpdate
            
        }
        catch {
            Write-Host "`nERROR: Check FTP location and make sure you don't rename the bin file" -ForegroundColor Magenta
            Write-Host "`n$_`n" -ForegroundColor Magenta
        }
    }
}