So recently I had the requirement of getting a list of files that changed between two different releases. We wanted to use this list to act as a verification to ensure that all artifacts were included in a release package.
I modified the code posted here in order to quickly write a console application to do the task. With the immediate problem solved, my colleges and I bounced the idea about porting the code into a PowerShell script which would allow us to enhance it better in the long run.
The solution would be built around the Visual Studio Online(VSO) REST service. This reduces any dependency on Team Foundation Server(TFS) specific client side assemblies or tools. The limitation is that, at the moment, it is only supported in Visual Studio Online and not all features are supported.
The credentials will be collected using the
I ran into strange issue when attempting to authenticate the request. The
The next steps would make this to its own cmdlet in order to make it more reusable in other scripts. Also check out the Curah! page that I created while working on this.
I modified the code posted here in order to quickly write a console application to do the task. With the immediate problem solved, my colleges and I bounced the idea about porting the code into a PowerShell script which would allow us to enhance it better in the long run.
The solution would be built around the Visual Studio Online(VSO) REST service. This reduces any dependency on Team Foundation Server(TFS) specific client side assemblies or tools. The limitation is that, at the moment, it is only supported in Visual Studio Online and not all features are supported.
Pre-Requisites
Security and Credentials
In order make things simple, let's enable Alternate Authentication for access the account. This enables the script to use Basic Authentication when making request to the VSO REST service. This can be done by navigating to the profile page, selectingCredentials > Enable alternate credentials
and providing new credential information. More instructions available here.The credentials will be collected using the
Get-Credentials
cmdlet. This provides the standard windows credentials dialog for the user to enter information. Since this makes the script interactive, I debated about having the username and password as a parameter for the script, but in the end decided against it. Maybe the next improvement would be to include a silent version of the script.The REST call
Invoke-RestMethod
cmdlet will be used to make the actual call to the REST service. So what's the difference between Invoke-WebRequest
and Invoke-RestMethod
you may ask? While similar, the Invoke-RestMethod
attempts to parse the returned JSON so that we do not have to do it manually within our script. Think of it as a super set of Invoke-WebRequest
just like Invoke-WebRequest
is a superset of System.Net.WebClient
. Read more about it here and here.I ran into strange issue when attempting to authenticate the request. The
Get-Credentials
cmdlet would return a System.Management.Automation.PSCredential
object as expected, but when passed into into the Invoke-RestMethod
cmdlet, it was not generating the the basic authentication header token within the request. I still haven't figured out why this happens, but the workaround was to add the authentication header explicitly as shown here. $basicAuth = ("{0}:{1}" -f $username,$password)
$basicAuth = [System.Text.Encoding]::UTF8.GetBytes($basicAuth)
$basicAuth = [System.Convert]::ToBase64String($basicAuth)
$headers = @{Authorization=("Basic {0}" -f $basicAuth)}
Making the call to the service
-
First get a list of changesets related to the project within the timeframe that we're interested in.
It took me a while to figure it out but you should notice this call is only allowed to be made against the entire Team Project Collection. So in order to filter out the project, provide the project path via thehttps://{account}.visualstudio.com/defaultcollection/_apis/tfvc/changesets?api-version=1.0&searchCriteria.fromId=100&searchCriteria.toId=200&searchCriteria.itemPath=$/{project}
searchCriteria.itemPath
filter. That issearchCriteria.itemPath=$/{projectname}
where{projectname}
is the one that you are interested in.
-
Next iterate through each of the results to retrieve the detailed information on of each of the changesets. This result would include a collection of all the files that were affected.
https://{account}.visualstudio.com/defaultcollection/_apis/tfvc/changesets/{changesetId}/changes?api-version=1.0
-
Again, iterate through each of the changes and extract the
path
property of the json result set. This is the path and name of the file.
- Remove duplicates entries and folder creation entries as necessary.
Final Thoughts
You can download my implementation here.The next steps would make this to its own cmdlet in order to make it more reusable in other scripts. Also check out the Curah! page that I created while working on this.
References
- Identifying all .vb files changed between two changesets
- Microsoft Technet - Get-Credential
- Screen scraping for pleasure or profit (with PowerShell’s Invoke-RestMethod)
- Hey, Scripting Guy! - InvokeRestMethod for the Rest of Us
- Microsoft Technet - Invoke-RestMethod
- Accessing Visual Studio Online REST API using Powershell 4.0, Invoke-RestMethod and Alternate Credentials