サンプルバックアップスクリプト

アプライアンスUIから設定 > アクション > バックアップの作成を使用する方法以外に、スクリプトを作成して実行し、アプライアンスのバックアップファイルを自動的に作成およびダウンロードすることもできます。

下記のサンプルのbackup.ps1スクリプトでは、REST呼び出しを使用してアプライアンスのバックアップファイルの作成とダウンロードを行うPowerShellスクリプトのサンプルを示しています。このサンプルスクリプトを、PowerShellバージョン3.0を実行するWindowsシステム上のファイルにカットアンドペーストし、ご使用の環境に合わせてスクリプトを編集してカスタマイズしてください。

定期的に対話モードまたはバッチモードで自動的に実行されるようにバックアップスクリプトをスケジュール設定できます(毎日バックアップすることをお勧めします)。スクリプトを対話形式で実行できるのは、バックアップ管理者またはインフラストラクチャ管理者の権限を持つユーザーのみです。

  • スクリプトを対話形式で実行するには、パラメーターを指定しないでください。アプライアンスのホスト名、アプライアンスのユーザー名とパスワード、およびバッチモード実行用にこれらのパラメーターを保存するためのファイルの名前を入力するように、スクリプトから求められます。バックアップ管理者またはインフラストラクチャ管理者の役割を持つユーザーの名前とパスワードを入力します。ユーザー名とパスワードは、暗号化されてから保存されます。

    最初は対話型でスクリプトを実行することをお勧めします。これで、最初の実行で作成したパラメーターファイルを使用して、バックグラウンドで自動的に実行するようにスクリプトのスケジュールを設定できます。

  • スクリプトをバッチモードで実行するには、パラメーターを含んでいるファイル名をコマンドラインに指定します。

パフォーマンスを向上させるには、SSLオプションを使用してcURLをインストールすることをお勧めします。サンプルスクリプトはcURLなしでも動作しますが、大きいバックアップファイルをダウンロードするのに数時間かかる場合があります。cURLをダウンロードするには、以下のURLを参照してください。

http://curl.haxx.se/download.html

注記:

Microsoft Visual C++再頒布可能パッケージ、MSVCR100.dllファイルのインストールが必要になる場合もあります。このファイルは以下のURLで入手できます。

PATH環境変数にcURLのパスが含まれていることを確認してください。

サンプルスクリプト

サンプルスクリプトは、以下の呼び出しを行ってバックアップファイルを作成し、ダウンロードします。

  1. queryfor-credentials()を呼び出し、ユーザーに入力を求めるか、ファイルから値を読み取って、アプライアンスのホスト名、ユーザー名、およびパスワードを取得します。

  2. login-appliance()を呼び出し、バックアップRESTコールを許可するために使用するセッションIDを取得するREST要求を発行します。

  3. backup-appliance()を呼び出し、バックアップを開始するREST要求を発行します。

  4. waitFor-completion()を呼び出し、バックアップが完了するまでポーリングを発行してバックアップステータスを取得するREST要求を発行します。

  5. get-backupResource()を呼び出し、ダウンロードURIを取得するREST要求を発行します。

  6. download-backup()を呼び出し、バックアップをダウンロードするREST要求を発行します。

サンプルのbackup.ps1スクリプト

# (C) Copyright 2012-2014 Hewlett Packard Enterprise Development LP
###########################################################################################################################
# Name:     backup.ps1
# Usage:    {directory}\backup.ps1 or {directory}\backup.ps1 filepath
# Parameter: $filepath: optional, uses the file in that path as the login credentials. ie: host address, username,
#           password, and, optionally, the Active Directory domain name
# Purpose:  Runs the backup function on the appliance and downloads it onto your machine's drive
#           in current user's home directory
# Notes:    To improve performance, this script uses the curl command if it is installed.  The curl command must
#           be installed with the SSL option.
#           Windows PowerShell 3.0 must be installed to run the script
###########################################################################################################################

#tells the computer that this is a trusted source that we are connecting to (brute force, could be refined)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

$global:interactiveMode = 0

# The scriptApiVersion is the default Api version (if the appliance supports this level
# or higher).  This variable may be changed if the appliance is at a lower Api level.
$global:scriptApiVersion = 3
# Using this Api version or greater requires a different interaction when creating a backup.
Set-Variable taskResourceV2ApiVersion -option Constant -value 3

try {
  #this log must be added if not already on your computer
  New-EventLog -LogName Application -Source backup.ps1 -ErrorAction stop
}
catch [System.Exception]
{
  #this is just to keep the error "already a script" from showing up on the screen if it is already created
}

##### Querying user for login info #####
function queryfor-credentials ()
{
  <#
        .DESCRIPTION
            Gathers information from User if in manual entry mode (script ran with zero arguments) or
            runs silently and gathers info from specified path (script ran with 1 argument)

        .INPUTS
            None, this function does not take inputs.

        .OUTPUTS
            Returns an object that contains the login name, password, hostname and
            ActiveDirectory domain to connect to.

        .EXAMPLE
            $variable = queryfor-credentials #runs function, saves json object to variable.
    #>

  if ($args[0] -eq $null)
  {

    Write-Host "Enter appliance name (https://ipaddress)"
    $appliance = Read-Host

    # Correct some common errors
    $appliance = $appliance.Trim().ToLower()
    if (!$appliance.StartsWith("https://"))
    {
       if ($appliance.StartsWith("http://"))
       {
          $appliance = $appliance.Replace("http","https")
       } else {
          $appliance = "https://" + $appliance
       }
    }

    Write-Host "Enter username"
    $username = Read-Host -AsSecureString | ConvertFrom-SecureString

    Write-Host "Enter password"
    $SecurePassword = Read-Host -AsSecureString | ConvertFrom-SecureString

    Write-Host "If using Active Directory, enter the Active Directory domain"
    Write-Host "  (Leave this field blank if not using Active Directory.)"
    $ADName = Read-Host

    Write-Host "Would you like to save these credentials to a file? (username and password encrypted)"
    $saveQuery = Read-Host

    $loginVals = [pscustomobject]@{ userName = $username; password = $SecurePassword;
                  hostname = $appliance; authLoginDomain = $ADName }
    $loginJson = $loginVals | convertTo-json

    $global:interactiveMode = 1

    if ($saveQuery[0] -eq "y") #enters into the mode to save the credentials
    {
      Write-Host "Enter file path and file name to save credentials  (example: C:\users\bob\machine1.txt)"
      $storagepath = Read-Host

      try
      {
        $loginJson | Out-File $storagepath -NoClobber -ErrorAction stop
      }
      catch [System.Exception]
      {
        Write-Host $_.Exception.message
        if ($_.Exception.getType() -eq [System.IO.IOException]) # file already exists throws an IO exception
        {
          do
          {
            Write-Host "Overwrite existing credentials for this machine?"
            [string]$overwriteQuery = Read-Host
            if ($overwriteQuery[0] -eq 'y')
            {
              $loginJson | Out-File $storagepath -ErrorAction stop
              $exitquery = 1
            }
            elseif ($overwriteQuery[0] -eq 'n')
            {
              $exitquery = 1
            }
            else
            {
              Write-Host "Please respond with a y or n"
              $exitquery = 0
            }

          } while ($exitquery -eq 0)
        }
        else
        {
          Write-Host "Improper filepath or no permission to write to given directory"
          Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Improper filepath, $storagepath " $_.Exception.message
          return
        }
      }

      $savedLoginJson = Get-Content $storagepath

      Write-Host "Run backup?"

      $continue = 0
      do
      {
        $earlyExit = Read-Host
        if ($earlyExit[0] -eq 'n')
        {
          return
        }
        elseif ($earlyExit[0] -ne 'y')
        {
          Write-Host "Please respond with a y or n"
        }
        else
        {
          $continue = 1
        }

      } while ($continue -eq 0)

    }
    else
    {
      return $loginJson
    }
  }
  elseif ($args.count -ne 1)
  {
    Write-Host "Incorrect number of arguments, use either filepath parameter or no parameters."
    return

  }
  else
  {
    foreach ($arg in $args)
    {
      $storagepath = $arg
    }
    try
    {
      $savedLoginJson = Get-Content $storagepath -ErrorAction stop
    }
    catch [System.Exception]
    {
      Write-Host "Login credential file not found. Please run script without arguments to access manual entry mode."
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Login credential file not found. Please run script without arguments to access manual entry mode."
      return

    }
  }
  return $savedloginJson
}

##### getApiVersion: Get X_API_Version #####
function getApiVersion ([int32] $currentApiVersion,[string]$hostname)
{
  <#
        .DESCRIPTION
            Sends a web request to the appliance to obtain the current Api version.
      Returns the lower of: Api version supported by the script and Api version
      supported by the appliance.

        .PARAMETER currentApiVersion
      Api version that the script is currently using

        .PARAMETER hostname
            The appliance address to send the request to (in https://{ipaddress} format)

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            Outputs the new active Api version

        .EXAMPLE
            $global:scriptApiVersion = getApiVersion()
    #>

  # the particular Uri on the Appliance to reqest the Api Version
  $versionUri = "/rest/version"

  # append the Uri to the end of the IP address to obtain a full Uri
  $fullVersionUri = $hostname + $versionUri

  # use setup-request to issue the REST request api version and get the response
  try
  {
    $applianceVersionJson = setup-request -Uri $fullVersionUri -method "GET" -accept "application/json" -contentType "application/json"
    if ($applianceVersionJson -ne $null)
    {
      $applianceVersion = $applianceVersionJson | convertFrom-Json
      $currentApplianceVersion = $applianceVersion.currentVersion
      if ($currentApplianceVersion -lt $currentApiVersion)
      {
        return $currentApplianceVersion
      }
      return $currentApiVersion
    }
  }
  catch [System.Exception]
  {
    if ($global:interactiveMode -eq 1)
    {
      Write-Host $error[0].Exception.Message
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $error[0].Exception.Message
    }
  }
}

##### Sending login info #####
function login-appliance ([string]$username,[string]$password,[string]$hostname,[string]$ADName)
{
  <#
        .DESCRIPTION
            Attempts to send a web request to the appliance and obtain an authorized sessionID.

        .PARAMETER username
            The username to log into the remote appliance

        .PARAMETER password
            The correct password associated with username

        .PARAMETER hostname
            The appliance address to send the request to (in https://{ipaddress} format)

        .PARAMETER ADName
            The Active Directory name (optional)

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            Outputs the response body containing the needed session ID.

        .EXAMPLE
            $authtoken = login-appliance $username $password $hostname $ADName
    #>

  # the particular Uri on the Appliance to reqest an "auth token"
  $loginUri = "/rest/login-sessions"

  # append the Uri to the end of the IP address to obtain a full Uri
  $fullLoginUri = $hostname + $loginUri
  # create the request body as a hash table, then convert it to json format
  if ($ADName)
  {
    $body = @{ userName = $username; password = $password; authLoginDomain = $ADName } | convertTo-json
  }
  else    # null or empty
  {
    $body = @{ userName = $username; password = $password } | convertTo-json
  }

  # use setup-request to issue the REST request to login and get the response
  try
  {
    $loginResponse = setup-request -Uri $fullLoginUri -method "POST" -accept "application/json" -contentType "application/json" -Body $body
    if ($loginResponse -ne $null)
    {
      $loginResponse | convertFrom-Json
    }
  }
  catch [System.Exception]
  {
    if ($global:interactiveMode -eq 1)
    {
      Write-Host $error[0].Exception.Message
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $error[0].Exception.Message
    }
  }
}

##### Executing backup ######
function backup-Appliance ([string]$authValue,[string]$hostname)
{
  <#
        .DESCRIPTION
            Gives the appliance the command to start creating a backup

        .PARAMETER authValue
            The authorized sessionID given by login-appliance

        .PARAMETER hostname
            The location of the appliance to connect to (in https://{ipaddress} format)

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            The task Resource returned by the appliance, converted to a hashtable object

        .EXAMPLE
            $taskResource = backup-Appliance $sessionID $hostname
    #>

  # append the REST Uri for backup to the IP address of the Appliance
  $bkupUri = "/rest/backups/"
  $fullBackupUri = $hostname + $bkupUri

  # create a new webrequest and add the proper headers (new header, auth, is needed for authorization
  # in all functions from this point on)
  try
  {
    if ($global:scriptApiVersion -lt $taskResourceV2ApiVersion)
    {
      $taskResourceJson = setup-request -Uri $fullBackupUri -method "POST" -accept "application/json" -contentType "application/json" -authValue $authValue
    }
    else
    {
      $taskUri = setup-request -Uri $fullBackupUri -method "POST" -accept "application/json" -contentType "application/json" -authValue $authValue -returnLocation $true
      if ($taskUri -ne $null)
      {
        $taskResourceJson = setup-request -Uri $taskUri -method "GET" -accept "application/json" -contentType "application/json" -authValue $authValue
      }
    }
    if ($taskResourceJson -ne $null)
    {
      return $taskResourceJson | ConvertFrom-Json
    }
  }
  catch [System.Exception]
  {
    if ($global:interactiveMode -eq 1)
    {
      Write-Host $error[0].Exception.Message
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $error[0].Exception.Message
    }
  }
}

##### Polling to see if backup is finished ######
function waitFor-completion ([object]$taskResource,[string]$authValue,[string]$hostname)
{
  <#
        .DESCRIPTION
            Checks the status of the backup every twenty seconds, stops when status changes from running to a different status

        .PARAMETER taskResource
            The response object from the backup-appliance method

        .PARAMETER authValue
            The authorized session ID

        .PARAMETER hostname
            The appliance to connect to (in https://{ipaddress} format)

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            The new task resource object, which contains the Uri to get the backup resource in the next function

        .EXAMPLE
            $taskResource = waitFor-Completion $taskResource $sessionID $hostname
    #>

  # extracts the Uri of the task Resource from itself, to poll repeatedly
  $taskResourceUri = $taskResource.uri
  if ($taskResourceUri -eq $null)
  {
    # Caller will provide the error message
    return
  }

  # appends the Uri to the hostname to create a fully-qualified Uri
  $fullTaskUri = $hostname + $taskResourceUri

  # retries if unable to get backup progress information
  $errorCount = 0
  $errorMessage = ""

  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Backup initiated."
    Write-Host "Checking for backup completion, this may take a while."
  }

  # a while loop to determine when the backup process is finished
  do
  {

    try
    {
      # creates a new webrequest with appropriate headers
      $taskResourceJson = setup-request -Uri $fullTaskUri -method "GET" -accept "application/json" -authValue $authValue -isSilent $true
      # converts the response from the Appliance into a hash table
      $taskResource = $taskResourceJson | convertFrom-Json
      # checks the status of the task manager
      $status = $taskResource.taskState
    }
    catch
    {
      $errorMessage = $error[0].Exception.Message
      $errorCount = $errorCount + 1
      $status = "RequestFailed"
      Start-Sleep -s 15
      continue
    }

    # Update progress bar
    if ($global:interactiveMode -eq 1)
    {
      $trimmedPercent = ($taskResource.completedSteps) / 5
      $progressBar = "[" + "=" * $trimmedPercent + " " * (20 - $trimmedPercent) + "]"
      Write-Host "`r Backup progress: $progressBar " $taskResource.completedSteps "%" -NoNewline
    }

    # Reset the error count since progress information was successfully retrieved
    $errorCount = 0

    # If the backup is still running, wait a bit, and then check again
    if ($status -eq "Running")
    {
      Start-Sleep -s 20
    }

  } while (($status -eq "Running" -or $status -eq "RequestFailed") -and $errorCount -lt 20);

  # if the backup reported an abnormal state, report the state and exit function
  if ($status -ne "Completed")
  {
    if ($global:interactiveMode -eq 1)
    {
      Write-Host "`n"
      Write-Host "Backup stopped abnormally"
      Write-Host $errorMessage
    }
    else
    {
      #log error message
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Backup stopped abnormally"
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $errorMessage
    }
    return $null
  }

  # upon successful completion of task, outputs a hash table which contains task resource
  else
  {
    Write-Host "`n"
    $taskResource
    return
  }
}

##### Gets the backup resource #####
function get-backupResource ([object]$taskResource,[string]$authValue,[string]$hostname)
{
  <#
        .DESCRIPTION
            Gets the Uri for the backup resource from the task resource and gets the backup resource

        .PARAMETER taskResource
            The task resource object that we use to get the Uri for the backup resource

        .PARAMETER authValue
            The authorized sessionID

        .PARAMETER hostname
            the appliance to connect to (in https://{ipaddress} format)

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            The backup resource object

        .EXAMPLE
            $backupResource = get-BackupResource $taskResource $sessionID $applianceName
    #>

  # the backup Resource Uri is extracted from the task resource
  if ($global:scriptApiVersion -lt $taskResourceV2ApiVersion)
  {
    $backupUri = $taskResource.associatedResourceUri
  }
  else
  {
    $backupUri = $taskResource.associatedResource.resourceUri
  }
  if ($backupUri -eq $null)
  {
    # Caller will provide the error message
    return
  }
  # construct the full backup Resource Uri from the hostname and the backup resource uri
  $fullBackupUri = $hostname + $backupUri

  # get the backup resource that contains the Uri for downloading
  try
  {
    # creates a new webrequest with appropriate headers
    $backupResourceJson = setup-request -Uri $fullBackupUri -method "GET" -accept "application/json" -auth $authValue
    if ($backupResourceJson -ne $null)
    {
       $resource = $backupResourceJson | convertFrom-Json
       if ($global:interactiveMode -eq 1)
       {
         Write-Host "Obtained backup resource.  Now downloading.  This may take a while ..."
       }
       $resource
       return
    }
  }
  catch [System.Exception]
  {
    if ($global:interactiveMode -eq 1)
    {
      Write-Host $error[0].Exception.Message
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $error[0].Exception.Message
    }
  }
}

##### Function to download the backup file #####
function download-Backup ([PSCustomObject]$backupResource,[string]$authValue,[string]$hostname)
{
  <#
        .DESCRIPTION
            Downloads the backup file from the appliance to the local system.  Tries to use the
            curl command.  The curl command has significantly better performance especially for
            large backups.  If curl isn't installed, invokes download-Backup-without-curl to
            download the backup.

        .PARAMETER backupResource
            Backup resource containing Uri for downloading

        .PARAMETER authValue
            The authorized sessionID

        .PARAMETER hostname
            The IP address of the appliance

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            The absolute path of the download file

        .EXAMPLE
            download-backup $backupResource $sessionID https://11.111.11.111
    #>

  $downloadUri = $hostname + $backupResource.downloadUri
  $fileDir = [environment]::GetFolderPath("Personal")
  $filePath = $fileDir + "\" + $backupResource.id + ".bkp"
  $curlDownloadCommand = "curl -o " + $filePath + " -s -f -L -k -X GET " +
    "-H 'accept: application/octet-stream' " +
    "-H 'auth: " + $authValue + "' " +
    "-H 'X-API-Version: $global:scriptApiVersion' " +
    $downloadUri
  $curlGetDownloadErrorCommand = "curl -s -k -X GET " +
    "-H 'accept: application/json' " +
    "-H 'auth: " + $authValue + "' " +
    "-H 'X-API-Version: $global:scriptApiVersion' " +
    $downloadUri

  try
  {
    $testCurlSslOption = curl -V
    if ($testCurlSslOption -match "SSL")
    {
        invoke-expression $curlDownloadCommand
    }
    else
    {
        if ($global:interactiveMode -eq 1)
        {
          Write-Host "Version of curl must support SSL to get improved download performance."
        }
        else
        {
          Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Version of curl must support SSL to get improved download performance"
        }

        return download-Backup-without-curl $backupResource $authValue $hostname
    }

    if ($LASTEXITCODE -ne 0)
    {
        $errorResponse = invoke-expression $curlGetDownloadErrorCommand
        if ($global:interactiveMode -eq 1)
        {
          Write-Host "Download using curl error: $errorResponse"
        }
        else
        {
          Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Download error: $errorResponse"
        }

        if (Test-Path $filePath)
        {
           Remove-Item $filePath
        }
        return
    }

    if ($global:interactiveMode -eq 1)
    {
      Write-Host "Backup download complete!"
    }
  }
  catch [System.Management.Automation.CommandNotFoundException]
  {
    return download-Backup-without-curl $backupResource $authValue $hostname
  }
  catch [System.Exception]
  {
    Write-Host "Not able to download backup"
    Write-Host $error[0].Exception
    return
  }

  return $filePath
}

##### Function to download the Backup file without using the curl command #####
function download-Backup-without-curl ([PSCustomObject]$backupResource,[string]$authValue,[string]$hostname)
{
  <#
        .DESCRIPTION
            Downloads the backup file from the appliance to the local system (without using curl)

        .PARAMETER backupResource
            Backup resource containing Uri for downloading

        .PARAMETER authValue
            The authorized sessionID

        .PARAMETER hostname
            The IP address of the appliance

        .INPUTS
            None, does not accept piping

        .OUTPUTS
            The absolute path of the download file

        .EXAMPLE
            download-backup-without-curl $backupResource $sessionID https://11.111.11.111
    #>

  # appends Uri ( obtained from previous function) to IP address
  $downloadUri = $hostname + $backupResource.downloadUri
  $downloadTimeout = 43200000 # 12 hours
  $bufferSize = 65536 # bytes

  # creates a new webrequest with appropriate headers
  [net.httpsWebRequest]$downloadRequest = [net.webRequest]::create($downloadUri)
  $downloadRequest.method = "GET"
  $downloadRequest.AllowAutoRedirect = $TRUE
  $downloadRequest.Timeout = $downloadTimeout
  $downloadRequest.ReadWriteTimeout = $downloadTimeout
  $downloadRequest.Headers.Add("auth", $authValue)
  $downloadRequest.Headers.Add("X-API-Version", $global:scriptApiVersion)
  # accept either octet-stream or json to allow the response body to contain either the backup or an exception
  $downloadRequest.accept = "application/octet-stream;q=0.8,application/json"

  # creates a variable that stores the path to the file location. Note: users may change this to other file paths.
  $fileDir = [environment]::GetFolderPath("Personal")

  try
  {
    # connects to the Appliance, creates a new file with the content of the response
    [net.httpsWebResponse]$response = $downloadRequest.getResponse()
    $responseStream = $response.getResponseStream()
    $responseStream.ReadTimeout = $downloadTimeout

    #saves file as the name given by the backup ID
    $filePath = $fileDir + "\" + $backupResource.id + ".bkp"
    $sr = New-Object System.IO.FileStream ($filePath,[System.IO.FileMode]::create)
    $responseStream.CopyTo($sr,$bufferSize)
    $response.close()
    $sr.close()
    if ($global:interactiveMode -eq 1)
    {
      Write-Host "Backup download complete!"
    }
  }
  catch [Net.WebException]
  {
    $errorMessage = $error[0].Exception.message

    #Try to get more information about the error
    try {
      $errorResponse = $error[0].Exception.InnerException.Response.getResponseStream()
      $sr = New-Object IO.StreamReader ($errorResponse)
      $rawErrorStream = $sr.readtoend()
      $error[0].Exception.InnerException.Response.close()
      $errorObject = $rawErrorStream | convertFrom-Json
      if (($errorObject.message.length -gt 0) -and
          ($errorObject.recommendedActions.length -gt 0))
      {
        $errorMessage = $errorObject.message + " " + $errorObject.recommendedActions
      }
    }
    catch [System.Exception]
    {
      #Use exception message
    }

    if ($global:interactiveMode -eq 1)
    {
      Write-Host $errorMessage
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $errorMessage
    }
    return
  }

  return $filePath
}

function setup-request ([string]$uri,[string]$method,[string]$accept,[string]$contentType = "",[string]$authValue = "",[object]$body = $null,[bool]$isSilent=$false, [bool]$returnLocation=$false)
{
  try
  {
    [net.httpsWebRequest]$request = [net.webRequest]::create($uri)
    $request.method = $method
    $request.accept = $accept

    $request.Headers.Add("Accept-Language: en-US")
    if ($contentType -ne "")
    {
      $request.ContentType = $contentType
    }
    if ($authValue -ne "")
    {
      $request.Headers.Item("auth") = $authValue
    }
    $request.Headers.Item("X-API-Version") = $global:scriptApiVersion
    if ($body -ne $null)
    {
      $requestBodyStream = New-Object IO.StreamWriter $request.getRequestStream()
      $requestBodyStream.WriteLine($body)
      $requestBodyStream.flush()
      $requestBodyStream.close()
    }

    # attempt to connect to the Appliance and get a response
    [net.httpsWebResponse]$response = $request.getResponse()

    if ($returnLocation)
    {
        $taskUri = $response.getResponseHeader("Location")

        $response.close()
        return $taskUri
    }
    else
    {
        # response stored in a stream
        $responseStream = $response.getResponseStream()
        $sr = New-Object IO.StreamReader ($responseStream)

        #the stream, which contains a json object, is read into the storage variable
        $rawResponseContent = $sr.readtoend()
        $response.close()
        return $rawResponseContent
    }
  }
  catch [Net.WebException]
  {
    $errorMessage = $error[0].Exception.message

    #Try to get more information about the error
    try {
      $errorResponse = $error[0].Exception.InnerException.Response.getResponseStream()
      $sr = New-Object IO.StreamReader ($errorResponse)
      $rawErrorStream = $sr.readtoend()
      $error[0].Exception.InnerException.Response.close()
      $errorObject = $rawErrorStream | convertFrom-Json
      if (($errorObject.message.length -gt 0) -and
          ($errorObject.recommendedActions.length -gt 0))
      {
        $errorMessage = $errorObject.message + " " + $errorObject.recommendedActions
      }
    }
    catch [System.Exception]
    {
      #Use exception message
    }

    if ($isSilent) {
        throw $errorMessage
    }
    elseif ($global:interactiveMode -eq 1)
    {
      Write-Host $errorMessage
    }
    else
    {
      Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message $errorMessage
    }

    #No need to rethrow since already recorded error
    return
  }
}


##### Start of function calls #####

#gets the credentials from user, either manual entry or from file
$savedLoginJson = queryfor-credentials $args[0]
if ($savedLoginJson -eq $null)
{
  #if an error occurs, it has already been logged in the queryfor-credentials function
  return
}

#extracts needed information from the credential json
try
{
  $savedLoginJson = "[" + $savedLoginJson + "]"
  $savedloginVals = $savedLoginJson | convertFrom-Json
  $SecStrLoginname = $savedloginVals.userName | ConvertTo-SecureString -ErrorAction stop
  $loginname =
  [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecStrLoginName))
  $hostname = $savedloginVals.hostname
  $SecStrPassword = $savedloginVals.password | ConvertTo-SecureString -ErrorAction stop
  $password =
  [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecStrpassword))
  $adname = $savedloginVals.authLoginDomain
}
catch [System.Exception]
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Failed to get credentials: " + $error[0].Exception.Message
  }
  else
  {
    Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Failed to get credentials: " + $error[0].Exception.Message
  }
}

#determines the active Api version
$global:scriptApiVersion = getApiVersion $global:scriptApiVersion $hostname
if ($global:scriptApiVersion -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Could not determine appliance Api version"
  }

  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Could not determine appliance Api version"
  return
}

#sends the login request to the machine, gets an authorized session ID if successful
$authValue = login-appliance $loginname $password $hostname $adname
if ($authValue -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Failed to receive login session ID."
  }
  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Failed to receive login session ID."
  return
}

#sends the request to start the backup process, returns the taskResource object
$taskResource = backup-Appliance $authValue.sessionID $hostname
if ($taskResource -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Could not initialize backup"
  }

  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Could not initialize backup"
  return
}

#loops to keep checking how far the backup has gone
$taskResource = waitFor-completion $taskResource $authValue.sessionID $hostname
if ($taskResource -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Could not fetch backup status"
  }

  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Could not fetch backup status"
  return
}

#gets the backup resource
$backupResource = get-backupResource $taskResource $authValue.sessionID $hostname
if ($backupResource -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Could not get the Backup Resource"
  }
  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Could not get the Backup Resource"
  return
}

#downloads the backup file to the local drive
$filePath = download-Backup $backupResource $authValue.sessionID $hostname
if ($filePath -eq $null)
{
  if ($global:interactiveMode -eq 1)
  {
    Write-Host "Could not download the backup"
  }
  Write-EventLog -EventId 100 -LogName Application -Source backup.ps1 -Message "Could not download the backup"
  return
}

if ($global:interactiveMode -eq 1)
{
  Write-Host "Backup can be found at $filePath"
  Write-Host "If you wish to automate this script in the future and re-use login settings currently entered,"
  Write-Host "then provide the file path to the saved credentials file when running the script."
  Write-Host "ie: " $MyInvocation.MyCommand.Definition " filepath"
}
else
{
  Write-Host "Backup completed successfully."
  Write-Host "The backup can be found at $filePath."
}
Write-EventLog -EventId 0 -LogName Application -Source backup.ps1 -Message "script completed successfully"