Private/Save-R1Download.ps1

function Save-R1Download {
    <#
    .SYNOPSIS
    Downloads a file from the RadiantOne API and saves it locally.

    .DESCRIPTION
    The response is written straight to disk, so a binary download arrives intact.

    A path naming an existing directory is where the file is saved, under the name given in the
    Content-Disposition header of the response. Any other path is the full path of the file, and the
    name it ends in is used whatever the response gives. Without a path, the file is saved to the
    current user's Downloads directory.

    The name the response gives cannot be known until the response arrives, so the download is
    written to a temporary file in the destination directory first, then renamed.

    .PARAMETER Uri
    The address of the download.

    .PARAMETER Method
    The method of the request.

    .PARAMETER Body
    The body of the request, where the download requires one.

    .PARAMETER Path
    The directory to save the file into, or the full path of the file.

    .PARAMETER DefaultName
    The name to save the file under when neither the path nor the response gives one.

    .EXAMPLE
    Save-R1Download -Uri $URI -Method GET -Path 'C:\Exports' -DefaultName 'datasources.zip'

    Saves the download into C:\Exports, named as the response names it.

    .OUTPUTS
    System.IO.FileInfo
    #>

    [CmdletBinding()]
    [OutputType([System.IO.FileInfo])]
    param(
        [parameter(Mandatory = $true)]
        [string]$Uri,

        [parameter(Mandatory = $true)]
        [ValidateSet('GET', 'POST')]
        [string]$Method,

        [parameter(Mandatory = $false)]
        [object]$Body,

        [parameter(Mandatory = $false)]
        [string]$Path,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$DefaultName
    )

    $FileName = $null

    if (-not ($PSBoundParameters.ContainsKey('Path'))) {

        $Directory = Get-R1DownloadPath

    } elseif (Test-Path -LiteralPath $Path -PathType Container) {

        $Directory = $Path

    } else {

        $Directory = Split-Path -Path $Path -Parent
        $FileName = Split-Path -Path $Path -Leaf

        #A bare file name is saved to the current location
        if ([string]::IsNullOrEmpty($Directory)) {

            $Directory = '.'

        }

    }

    if (-not (Test-Path -LiteralPath $Directory -PathType Container)) {

        $PSCmdlet.ThrowTerminatingError(

            [System.Management.Automation.ErrorRecord]::new(

                [System.IO.DirectoryNotFoundException]::new("Directory not found: $Directory"),
                'psRadiantOne.DirectoryNotFound',
                [System.Management.Automation.ErrorCategory]::ObjectNotFound,
                $Directory

            )

        )

    }

    $Directory = (Resolve-Path -LiteralPath $Directory).ProviderPath

    $TempFile = Join-Path -Path $Directory -ChildPath ([System.IO.Path]::GetRandomFileName())

    $Request = @{
        Uri     = $Uri
        Method  = $Method
        OutFile = $TempFile
    }

    if ($PSBoundParameters.ContainsKey('Body')) {

        $Request['Body'] = $Body

    }

    try {

        $Response = Invoke-R1RestMethod @Request

        if ([string]::IsNullOrEmpty($FileName)) {

            $FileName = Get-R1DownloadFileName -Response $Response

        }

        if ([string]::IsNullOrEmpty($FileName)) {

            $FileName = $DefaultName

        }

        $OutputFile = Join-Path -Path $Directory -ChildPath $FileName

        Move-Item -LiteralPath $TempFile -Destination $OutputFile -Force

        Get-Item -LiteralPath $OutputFile

    } finally {

        #Left behind only when the download or the rename failed
        if (Test-Path -LiteralPath $TempFile) {

            Remove-Item -LiteralPath $TempFile -Force

        }

    }

}