Uploading build/release tasks to VSTS

Let’s start with why? Why would someone upload a task directly to TFS/VSTS? You can just install or update the extension that added those tasks, no?!?! So why?
Obviously there are many reasons, and aside the development of the tasks themselves, often is a case when you find and fix a bug in a task that you need to get in production ASAP. Notifying third party and waiting for a new version of the extension is often not acceptable.
But there is already a tool that Microsoft made for handling tasks! Does TFS-CLI tells you nothing? Sure, tool that works very well and which I mentioned already in several occasions on my blog. Still, getting it requires Java Runtime Environment, NodeJs, tool itself, configuration. These are often not available out of the box and if you are doing this things occasionally, a better way may be a simple script.

Following is a script I do use:

param(
   [Parameter(Mandatory=$true)][string]$TaskPath,
   [Parameter(Mandatory=$true)][string]$VstsUrl,
   [Parameter(Mandatory=$true)][string]$Pat
)

# Load task definition from the JSON file
$taskDefinition = (Get-Content $taskPath\task.json) -join "`n" | ConvertFrom-Json
$taskFolder = Get-Item $TaskPath

# Zip the task content
Write-Output "Zipping task content"
$taskZip = ("{0}\..\{1}.zip" -f $taskFolder, $taskDefinition.id)
if (Test-Path $taskZip) { Remove-Item $taskZip }

Add-Type -AssemblyName "System.IO.Compression.FileSystem"
[IO.Compression.ZipFile]::CreateFromDirectory($taskFolder, $taskZip)

# Prepare to upload the task
Write-Output "Uploading task content to $VstsUrl"

$taskZipItem = Get-Item $taskZip
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$Pat"))

$headers = @{ Authorization = "Basic $encodedCredentials"; "Content-Range" = "bytes 0-$($taskZipItem.Length - 1)/$($taskZipItem.Length)"}

$url = "{0}/_apis/distributedtask/tasks/{1}?api-version=2.0-preview" -f $VstsUrl, $taskDefinition.id

try
{
	Invoke-RestMethod -Uri $url -Headers $headers -ContentType application/octet-stream -Method Put -InFile $taskZipItem
	Write-Host "Task uploaded successfully" -ForegroundColor Green
}
finally
{
    Remove-Item -LiteralPath $taskZip -Force
}

To invoke this, it is sufficient to provide the path to the folder containing the task, url towards your VSTS account (in case of TFS, path to the collection) and your personal access token. E.g.

.\TaskUploader.ps1 .\task\ https://myaccount.visualstudio.com jx3sa4h3cb56ehftgrjitj6kctei3pp7usuyxkoim5vpeqcgn7eq

That’s all.