示例备份脚本

作为从装置 UI 中使用设置 > 操作 > 创建备份的一种替代方法,您可以编写并运行一个脚本以自动创建和下载装置备份文件。

下面显示的示例 backup.ps1 脚本提供了一个示例 PowerShell 脚本,它使用 REST 调用创建和下载装置备份文件。将该示例脚本复制并粘贴到运行 PowerShell 3.0 版本的 Windows 系统上的文件中,并编辑该脚本以针对您的环境进行自定义。

您可以计划在交互或批处理模式下定期自动运行备份脚本(Hewlett Packard Enterprise 建议每天备份一次)。仅具有备份管理员或基础架构管理员权限的用户可以交互地运行脚本。

  • 要以交互方式运行该脚本,请不要包含任何参数。脚本将提示您输入装置主机名、装置用户名和密码,以及存储这些参数以在批处理模式下执行的文件的名称。输入具有备份管理员或基础架构管理员角色的用户的名称和密码。用户名和密码是以加密方式存储的。

    在首次运行时,Hewlett Packard Enterprise 建议您以交互方式运行该脚本。然后,可以使用在首次运行时创建的参数文件,计划在后台自动运行脚本。

  • 要在批处理模式下运行该脚本,请在命令行中指定包含参数的文件的名称。

Hewlett Packard Enterprise 建议您使用 SSL 选项安装 cURL 以提高性能。该示例脚本可以在无 cURL 的情况下使用,但可能需要几小时才能下载完较大的备份文件。要下载 cURL,请访问:

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

注意:

您还可能需要安装 Microsoft Visual C++ 可再发行组件 MSVCR100.dll 文件,可以从以下位置下载该组件:

请确保路径环境变量中包含 cURL 的路径。

示例脚本

示例脚本进行以下调用以创建和下载备份文件:

  1. 调用 queryfor-credentials(),通过提示用户输入值或从文件中读取值以获取装置主机名、用户名和密码。

  2. 调用 login-appliance() 发出 REST 请求以获取会话 ID,用于授权备份 REST 调用。

  3. 调用 backup-appliance() 发出 REST 请求以启动备份操作。

  4. 调用 waitFor-completion() 发出 REST 请求以轮询备份状况,直到备份完成。

  5. 调用 get-backupResource() 发出 REST 请求以获取下载 URI。

  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"