Getting the contents of a file from an ADO repository

Thomas Watson
Version 1
Published in
5 min readAug 12, 2024
Photo by Crew on Unsplash

I have to confess I often have blog ideas and start a new story here on Medium, but as soon as I have completed the task that inspired the story, I have a tendency to be distracted by the next big thing I’m working on and leave a half-finished blog in the ‘draft stage’. (That’s the ADHD way!) But as with swings and roundabouts, sometimes things come around again and smack you in the face. For example, having to once again find out how to get the contents of a file from an Azure DevOps git repository.

Just to clarify, the task is to get the ‘contents’ of a file, not the file itself. There are other ways and methods to get the file itself. In my particular case, however, I wanted the contents of a file, which would be used to create an Azure DevOps pipeline.

As with some blogs, the push to complete this one was to make this information easier to find and maybe even as a memory aid for myself. So I’m dusting this off as it was something I had started a year ago and suddenly find myself needing again!

As with most (all?) of my topics, I will be focusing on doing things in Azure and /or via Powershell as that was the original point of the blog post but the key features of the script should be an example of how to use the request URI in any required situation — for example, currently, I need to pull the contents of a configuration file from an ADO git repository for use with an Azure Logic app and the rediscovery of this work has allowed me to skip some quality time with Duck Duck Go!

TL;DR: The key is using the REST API and, specifically creating the URI.

There can be numerous reasons that you may want to do this, but I suspect that most will include the fact that we want to version control a file and consume those contents elsewhere. In my case, I want to make sure a configuration file is held in version control whilst being used in a logic app. Any changes to that configuration must go through the PR approval process.

When I first looked at this topic, all that I could find were some stack overflow topics that seemed to be quite long in the tooth and I thought that the Azure DevOps API must have changed since then. (In fairness, I know there are many versions of the API, but I haven’t researched the differences in each.)

To whet your whistle, here is a PowerShell script that I created to get the contents of a YAML file from ADO that I was going to use to create an ADO pipeline, also via the REST API. I have moved on from that end goal but find myself needing to pull the contents of a file from Azure DevOps again. Anyway, the code:

Computer code: powershell code that gets the contents of an Azure DevOps git repository file
A Powershell script to get the contents of a file from an ADO git repository

This PowerShell script is designed to download a YAML file from an Azure DevOps Git repository using the Azure DevOps REST API. The script requires a Personal Access Token (PAT) for authentication and allows the user to specify various parameters such as the organization, project, repository, and file path. Additionally, it provides options to set the local download path and the output file name.

To make the script more useful to yourself, don’t be afraid to remove the ‘YAML’ from everything!

The script begins with a comment block that includes metadata about the script, such as its synopsis, description, parameters, and an example of how to use it. This metadata helps users understand the purpose of the script and how to configure it for their needs.

The script then initializes several variables, including the PAT, organization name, project name, repository name, YAML file path, download path, and output file name. If the download path or output file name is not specified, the script sets default values. The download path defaults to the current script folder, and the output file name defaults to “YamlDownload.yaml”.

Next, the script constructs the output path by concatenating the YAML file path and the output file name. It then creates a base64-encoded token for authentication using the PAT. The script constructs the URI for the Azure DevOps REST API request, which includes the organization, project, repository, and file path.

A cautionary note about P.A.T.s — I know everyone knows this, but worth a reminder! Never upload your P.A. Tokens to a public ADO, Github, Gitlab etc. This is a security issue and may lead to a rap on the knuckles, or much worse!!!

The script checks if the URI contains spaces and escapes them if necessary. It then attempts to download the YAML file using the Invoke-RestMethod cmdlet, passing the URI and authentication headers. If the download is successful and the outputYaml flag is set to true, the script writes the content of the YAML file to the specified output path.

If the request fails or the YAML file content is null, the script outputs an error message and exits with a non-zero status code. If the script encounters any exceptions during execution, it catches them and outputs an error message indicating that it could not reach the Azure DevOps endpoint.

Now, that file is a year old at this point and I’m fairly certain I would write it slightly differently now (especially the error handling) but it is provided here for entertainment and education purposes only! Github link.

The star of the show — The URI!

Ultimately, the usefulness of the script comes down to the URI used to request the resource. The URI from the code above is:

powershell code: a URI to get the contents of a file from an Azure DevOps Repository
The URI that will get the contents of a file.
"https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryName/items?path=$yamlFilePath&api-version=7.0"

This URI should be straightforward, and if you have looked at the Stack Overflow answers you will see that the API has evolved somewhat.

There was no direct ‘this is how you download the contents of a file’ in the ADO REST API documentation, so it was definitely a happy moment when I found it worked.

Everything should be self-explanatory with the exception of the ‘path’ value. In this case, if you are requesting a file that is at the top level of the repository, you would use ‘/filename’ and if in a sub-folder you would use ‘/sub-folder/filename’. Pretty much the same as most file paths, but worth mentioning.

I have used this with YAML and JSON files — and I expect it to work with plain text files as well, but your mileage may vary — as stated above, this information is for non-production / test purposes only!

Hopefully, someone finds this of use. I suspect I will find myself back here in another year trying to remember how I did my Logic App configuration files!

About the author

Thomas Watson is an Azure DevOps Engineer here at Version 1.

--

--

Thomas Watson
Version 1

Late changer to IT. Working / learning as a DevOps engineer