Trying to download a file from an Azure DevOps Git repo using Powershell

Viewed 2813

So I have a Git repo in Azure DevOps, with a URL like

https://[$server]/tfs/[$company]/[$project]/_git/[$repoName]

And I can get to individual files in that repo by appending to that something like this:

?path=/[$folder]/[$fileName]

I am trying to use Powershell to download a specific file from this repo to the corresponding location and filename on my computer, like this:

$sourcePath = "https://[$server]/tfs/[$company]/[$project]/_git/[$repoName]?path=/[$folder]/[$fileName]&download=true"
$filePath = "C:\Documents\[$folder]\[$fileName]"
Invoke-RestMethod -Uri $sourcePath -Method Get -Headers @{Authorization=("Basic {0}" -f [$AuthInfo])} -OutFile $filePath

What this is doing is instead of replacing the local file with the file from the repo, it is replacing the contents of the local file with the contents of the response body. I find it odd that all the googling I've been doing says to do it this way, even though the Microsoft article on Invoke-RestMethod actually explains that this is what -OutFile does.

Note I've also tried Invoke-WebRequest....same thing.

So how do I download the actual file from the repo to the local destination I want (or replace the contents of the local destination file with the contents of the repo file)?

In addition, is there a way to specify which branch to get the file from? Maybe I should be using Git powershell commands with this as well somehow? All the other googling I've done about downloading from a git repo comes up with results about GitHub.

Thank you!

2 Answers

Use the rest api with the following template:

GET https://{tfs_url}/{collection_name}/{project}/_apis/git/repositories/{repositoryId}/items?path={path}

Check the documentation: Items - Get, Example - Download

I use the following code to copy files (with System.Net.WebClient) in build pipelines:

$user = ""
$token = $env:SYSTEM_ACCESSTOKEN
$teamProject = $env:SYSTEM_TEAMPROJECT
$orgUrl = $env:SYSTEM_COLLECTIONURI
$repoName = "REPO_NAME"

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

    function InvokeGetFileRequest ($GitFilePath, $OutFilePath)
    {
        Write-Host "Download file" $GitFilePath "to" $OutFilePath
     
        $uriGetFile = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/items?scopePath=$GitFilePath&download=true&api-version=6.1-preview.1"
    
       Write-Host "Url:" $uriGetFile
    
        $wc = New-Object System.Net.WebClient
        $wc.Headers["Authorization"] = "Basic {0}" -f $base64AuthInfo
        $wc.Headers["Content-Type"] = "application/json";
        $wc.DownloadFile($uriGetFile, $OutFilePath)
    }

I needed to do this and what I saw here didn't work so I wrote my own:

param( 
    [Parameter(Mandatory=$true)] 
    [string] $GitFilePath,
    [Parameter(Mandatory=$true)] 
    [string] $OutFilePath,
    [Parameter(Mandatory=$true)] 
    [string] $RepoName,
    [string] $token,
    [string] $orgUrl,
    [string] $teamProject
)

if([String]::IsNullOrEmpty($token))
{
    if($env:SYSTEM_ACCESSTOKEN -eq $null)
    {
        Write-Error "you must either pass the -token parameter or use the BUILD_TOKEN environment variable"
        exit 1;
    }
    else
    {
        $token = $env:SYSTEM_ACCESSTOKEN;
    }
}


if([string]::IsNullOrEmpty($teamProject)){
    if($env:SYSTEM_TEAMPROJECT -eq $null)
    {
        Write-Error "you must either pass the -teampProject parameter or use the SYSTEM_TEAMPROJECT environment variable"
        exit 1;
    }
    else
    {
        $teamProject = $env:SYSTEM_TEAMPROJECT
    }
}

if([string]::IsNullOrEmpty($orgUrl)){
    if($env:SYSTEM_COLLECTIONURI -eq $null)
    {
        Write-Error "you must either pass the -orgUrl parameter or use the SYSTEM_COLLECTIONURI environment variable"
        exit 1;
    }
    else
    {
        $teamProject = $env:SYSTEM_COLLECTIONURI
    }
}

# Base64-encodes the Personal Access Token (PAT) appropriately  
$User='' 
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User,$token)));  
$header = @{Authorization=("Basic {0}" -f $base64AuthInfo)};  
#---------------------------------------------------------------------- 

Write-Host "Download file" $GitFilePath "to" $OutFilePath
     
$uriGetFile = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/items?scopePath=$GitFilePath&download=true&api-version=6.1-preview.1"
    
Write-Host "Url:" $uriGetFile
    
$filecontent = Invoke-RestMethod -ContentType "application/json" -UseBasicParsing -Headers $header -Uri $uriGetFile
$filecontent | Out-File -Encoding utf8 $OutFilePath
Related