public/Copy-Attachment.ps1

function Copy-Attachment {
    <#
    .DESCRIPTION
    Utilized for copying binary type file byte streams via REST POST method to a Visual Studio Team Services attachment store.
     
    .PARAMETER InstanceName
    The specific name of the VSTS instance to the attachment will be sent to.
    Example value would be CONTOSO where VSTS URL is https://contoso.visualstudio.com
     
    .PARAMETER SourceFileURL
    Full URL to the attachment that will be copied to the destination VSTS work item.
     
    .PARAMETER DestinationFileName
    File name of the destination file, can be the exact same name as the source file name.
     
    .PARAMETER APIKey
    The PAT (Personal Access Token) API Key with work item rights.
     
    .PARAMETER APIVersion
    The specific REST API version to utilize.
     
    .EXAMPLE
    Copy-Attachment -InstanceName 'contoso' -SourceFileURL 'https://contoso.zendesk.com/attachments/token/ENzrH7xesvZUUwocJbJJr8v2c/?name=File.pdf' -DestinationFileName 'File.pdf' -APIKey 'odzhygw6smyztbvqwkv7cqcnl6tddqakvdojjdjo7yz4f6a3cf8a' -APIVersion '1.0'
    #>

    [CmdletBinding()]
    param (
        # VSTS Instance Name
        [Parameter(Mandatory=$true)]
        [string]
        $InstanceName,
        # Source File URL
        [Parameter(Mandatory=$true)]
        [string]
        $SourceFileURL,
        # Destination File Name
        [Parameter(Mandatory=$true)]
        [string]
        $DestinationFileName,
        # VSTS API Key
        [Parameter(Mandatory=$true)]
        [string]
        $APIKey,
        # API Version
        [Parameter(Mandatory=$true)]
        [string]
        $APIVersion
    )
    process {
        $authHeader = @{Authorization = ("Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($apiKey)")))}

        $uri = "https://$($instanceName).visualstudio.com/DefaultCollection/_apis/wit/attachments?api-version=$($apiVersion)&filename=$($destinationFileName)"
        try {
            $sourceContent = (Invoke-WebRequest -Uri $sourceFileURL).Content
        }
        catch {
            throw "Failed to read $($sourceFilePath) due to the following exception.`r`n$($_.Exception.Message)"
        }
        try {
            $result = Invoke-RestMethod -Uri $uri -Method Post -Headers $authHeader -ContentType "application/octet-stream" -Body $sourceContent -ErrorAction Stop
            if ($result.url -eq $null) {
                throw $result
            }
            else {
                return $result
            }
        }
        catch {
            throw "Failed to copy attachment $($sourceFilePath) to $($uri) due to the following exception.`r`n$($_)"
        }
    }
}