Use PowerShell to destroy source code marked for deletion in TFS, is this possible? - rest

Example
If you look at the picture, I have marked some sample files/source in VS2017 source Control Explorer as deleted, but TFS doesn't delete it automatically, you have to destroy it manually with the tf destroy command.
I wanted to make PowerShell use the TFS REST API to get source that has been marked for deletion, but looking through their API reference, I haven't found a way to do this, it doesn't seem like the API exposes that kind of information, but somehow Visual Studio 2017 is able to get it, so surely I should be able to?
I'm using TFS2017 Update 2, so this is api version 3.2.
Why I want to do this: We're running low on space and we have lots of team project collections with source marked for deletion. It would be very tedious to destroy everything manually.

If you have TFS Power Tools you can use this PowerShell script to destory all the deleted items (with tf and not with rest api, but it does the work, you don't need to do it manually):
$tfsServer = Get-TfsServer -name http://YOURTFSSERVER:PORT
$destroyList = get-tfschilditem -item $/Root/ -server $tfsServer -Deleted -recurse | Where {$_.DeletionId -ne 0}
foreach($item in $destroyList)
{
$itemPath = '"' + $item.ServerItem + ";X" + $item.DeletionId + '"'
tf destroy $itemPath /i /startcleanup
}

There are no REST APIs for this. You will have to use tf.exe.

Related

How to destroy a branch in TFVC using the REST API?

I am looking to delete and then destroy a branch in TFVC (in Azure Devops) using the REST API and Powershell, but after checking the documentation I have to ask: is this possible using the API?
Using the GET documentation as a guide I could take a guess at it and run something similar to the following:
DELETE https://dev.azure.com/{organization}/{project}/_apis/tfvc/branches?path={path}&api-version=6.0
but given the destructive nature of these calls I am reluctant to guess. And there is no obvious way to invoke the destroy functionality.
Alternatively, is there a way to trace the API call that must (probably?) be executed if I was to run the command line tf vc destroy "$/MyBranch/Path"? Or am I going to have to resort to using a Powershell snapin for this?
Why not use tf vc destroy from powershell? Most of TFVC is handled by the old SOAP API and doesn't have a REST equivalent. The investment in more REST APIs for TFVC is unlikely. You can invoke tf vc from powershell assuming you have Team Explorer installed on the machine.
Alternatively, you can load the Client Object Model into PowerShell directly and invoke the destroy calls from it. The call is pretty straightforward. That way the Client Object Model will do all the API wrestling. You can get the assemblies from NuGet without installing Team Explorer to a machine.
To get an instance of the VersionControlServer class you can look at my TFVC tasks. The code below is untested, but should get you really close:
[System.Reflection.Assembly]::LoadFrom("Newtonsoft.Json.dll")
[System.Reflection.Assembly]::LoadFrom("Microsoft.TeamFoundation.Client")
[System.Reflection.Assembly]::LoadFrom("Microsoft.TeamFoundation.Common")
[System.Reflection.Assembly]::LoadFrom("Microsoft.TeamFoundation.VersionControl.Client")
[System.Reflection.Assembly]::LoadFrom("Microsoft.TeamFoundation.WorkItemTracking.Client")
[System.Reflection.Assembly]::LoadFrom("Microsoft.TeamFoundation.Diff")
$OnNonFatalError = [Microsoft.TeamFoundation.VersionControl.Client.ExceptionEventHandler] {
param($sender, $e)
if ($e.Exception -ne $null -and $e.Exception.Message -ne $null)
{
Write-Message -Type Warning $e.Exception.Message
}
if ($e.Failure -ne $null -and $e.Failure.Message -ne $null)
{
Write-Message -Type Warning $e.Failure.Message
if ($e.Failure.Warnings -ne $null -and $e.Failure.Warnings.Length -gt 0)
{
foreach ($warning in $e.Failure.Warnings)
{
Write-Message -Type Warning $warning.ParentOrChildTask
}
}
}
}
function Get-TfsVersionControlServer()
{
[cmdletbinding()]
param(
[string] $ProjectCollectionUri
)
$collection = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(
$ProjectCollectionUri)
$collection.EnsureAuthenticated()
$versionControlServer =
$provider.TfsTeamProjectCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$versionControlServer.add_NonFatalError($OnNonFatalError)
return $versionControlServer
}
Get-TfsVersionControlServer().Destroy(...)
Then call the destroy function from there.
I looked at the API documentation as well. In my experience, Azure keeps their API documents up to date pretty well. The absence of the DELETE operation in their documentation indicates that the DELETE operation is not yet supported. Even if it 'worked', I wouldn't use it until it was supported in their API - especially with something dealing with version control.

Determining Installed Visual Studio Path for 2017

I have a powershell script that looks at a list of VS installations, and determines the highest version installed. It then uses the InstallDir for that version, and uses it to access various commands.
It still uses the lower versions, however.
As of VS2017, it appears that the Registry keys are no longer saved in the same way. I need to update the script to be able to figure out the 2017 settings.
#Add New Versions to this list when new versions of VS are released
$VsVersionsToDisable = "10.0", "11.0", "12.0", "14.0"
[System.Collections.ArrayList]$VsVersions = $VsVersionsToDisable
#Find the Highest installed VS Version, and use it for the TFS.exe Command.
foreach ($version in $VsVersions | Sort-Object -Descending)
{
$keyPath = "HKCU:\Software\Microsoft\VisualStudio\$version`_Config"
If (Test-Path $keyPath)
{
$aliasPath = Get-ItemProperty -Path $keyPath | Select-Object `
-ExpandProperty InstallDir
$proxyPath = Join-Path $aliasPath "tf.exe"
set-alias proxyTF $proxyPath
}
}
To avoid an XY question: We use this script to configure the TFS Proxy settings for a user. It determines the highest installed version, uses it to find the proxy, then iterates through the lower versions configuring their proxy settings with the same value.
What is the best way to determine the installation directory (and also the tf.exe location) for VS2017?
From what I can see, use the SxS\VS7 option:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7
It should give you the root paths to Visual Studio:
That should get you going.
The tf.exe location is then stored using a symlink under:
.\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe
Since you're using PowerShell, check out https://github.com/microsoft/vssetup.powershell, which is a PS module for detecting installations of VS2017+.
Otherwise, you could need to rely on the Nuget package which is the supported means of detecting VS.
See also this answer on a related question, which predates the PS module I listed above but contains some unsupported methods for finding VS.
I did use this as a reference and came to a solution in another way.
I'm not sure how resilient it is with regards to other versions, but it did the trick for me. It get's the directory of devenv and then I add the extra on the end for TFS. Obviously if the structure is different, then we are screwed.
Hope it helps.
$regKey = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\devenv.exe"
$visualStudioDir = Get-ItemPropertyValue -Path $regKey -Name "(Default)"
$visualStudioDir = ($visualStudioDir.Replace("devenv.exe","")).replace("`"","")
$tfsPath = 'CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe'
Set-Alias tf $visualStudioDir$tfsPath
tf workspaces

Powershell get latest on a working folder?

I am trying to get latest on a specific folder and was wondering how I would do this. I have been reading the MSDN documentation about the Workspace class but unfortunately it doesn't seem to provide any information about how I would go about getting latest of a specific folder.
For example, I have a single workspace but with multiple working folders. My PowerShell script can get latest but only at workspace level. Is it possible to get it from a working directory level or at a particular folder level?
Thanks in advance, DS.
EDIT
I believe this is possible as power tools is able to do it via right clicking a folder and getting latest. Ideally, want to replicate this.
http://msdn.microsoft.com/en-us/library/Microsoft.TeamFoundation.VersionControl.Client.Workspace.aspx
The below shows my script in practice..
$tfs = .\tfs-get-instance.ps1 -uri $uri
$vcs = $tfs.TfsTeamProjectCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
[psobject]$workspace = $vcs.GetWorkspace([System.Environment]::MachineName, [System.Environment]::UserName)
$workspace.Map($sourceFolder, $localFolder)
$result = $workspace.GetLocalItemForServerItem($sourceFolder);
if ($result -ne "")
{
echo $result
}
You should be able to use the Workspace.Get Method (String[], VersionSpec, RecursionType, GetOptions) to get what you want.
On the other hand, if you don't necessarily want to do it using the .NET objects, you could let tf.exe do the actual work, like the following:
& $TfExePath workfold /map "$codePath" "$LocalFolderPath" /collection:"$tfCollection" /workspace:$workspaceName
& $TfExePath get "$codePath" /version:$ChangeSet /force /overwrite /all /recursive $workspaceName
On the other hand, if you have the TF PowerTools installed you should also have PowerShell cmdlets for working with TFS. I have never used them, but I'm guessing you should be able to use them instead of using tf.exe if you want to. I would probably go for the PowerShell cmdlets in the power tools if they fill your need.

Get Latest Version of Folder from TFS, using Powershell

I am trying to "Get Latest Version" of a particular folder from TFS, using Powershell.
I have installed the TFS Snappin, and have been using TFS Power Tools cmdlets in PowerShell (such as Get-TfsChildItem and Select-TfsItem etc) [How do I set up TFS PowerShell Snapin ], and have gone through their documentation (which I didn't find explanatory enough!).
Confused, on the exact cmdlet to use, when I am trying to get the latest version of an entire Folder structure from TFS, that is mapped to my local drive (and not just a changeset or ChildItem).
Example :
Tfs Path - $/APD-RepairSolutions/Main/Database
Mapped path - D:\TFS\APD-RepairSolutions/Main/Database.
I want a code, that would iteratively get the latest version of the entire folder Database,( that has number of tables,stored procedures etc.)
I am using ..
PS D:\Tfs\APD-RepairSolutions\Main\Database> $server=Get-TfsServer -Name http://tfs:8080/tfs
PS D:\Tfs\APD-RepairSolutions\Main\Database> Get-TfsChangeset -Recurse -Server $Server
Not helping my case - as it is only returning the latest changeset in the current directory.
To get latest (tf get) use Update-TfsWorkspace.
Get-TfsChangeset is the equivalent of tf changeset.
Gotcha! with Update-TFSWorskpace. Has some helpful parameters as well. -Items is used to specify the exact items you want to update.
PS D:\Tfs\APD-RepairSolutions\Main>Update-TFSWorkspace -All -Overwrite -Force -Recurse -Items .\Database
The Workspace is replaced with updated versions of items. Thanks #Kmoraz!
If you would like to use the TFS API instead, you can use the Workspace.Get Method:
# Load the TFS assemblies
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
$ws = $vcServer.QueryWorkspaces("<WORKSPACENAME>", $null, $null);
# Specify properties of intended workspace get
$recursionType = [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::Full
$latestVersion = [Microsoft.TeamFoundation.VersionControl.Client.VersionSpec]::Latest
$getOptions = [Microsoft.TeamFoundation.VersionControl.Client.GetOptions]::GetAll
# Get what I want!
$ws.Get("$/Remote/Folder", $latestVersion, $recursionType, $getOptions)
Would be a good idea to replace the nulls with your domain login and computer name when Querying Workspaces.

How do I get a list of all tfs alert subscriptions via powershell (get .Net assembly via PowerShell?)

I'm trying to move my tools to powershell, can this be done in PowerShell? the bit I'm really interested in is:
IEventService es = tfs.GetService(typeof(IEventService)) as IEventService;
List<Subscription> ls = es.GetAllEventSubscriptions().ToList();
Edit: what I really want to do might be using a .NET assembly from powershell and this might then be a duplicate of Using .NET library from PowerShell
Here is a TFS API in PowerShell function that I found on a blog long ago that will get you started. I've posted it to a GitHub Gist. Basically you ensure you've loaded up the TFS assemblies into the AppDomain and then you can add any TFS Service Interfaces you want to the object and just operate on them just as you would in any c# application, etc.
https://gist.github.com/3288447
Once you have the TFS object returned from the method in the Gist above, you can operate on the loaded services like so:
#use work item service
$tfs = get-tfs $env:TFSSERVERURL -silent
$project = $tfs.wit.Projects | ?{ $_.Name -eq $projectName}
#todo - replace with text for query or file read -- this is deprecated
$query = $project.StoredQueries | ?{ $_.Name -eq 'Active Bugs' }
$queryText = $query.QueryText.Replace("#project","'$projectName'")
$results = $tfs.wit.Query($queryText)
#do something with the results...
In your request above you can just alter the get-tfs method to add your service interface to the set loaded and then operate on the .NET methods much like I do in the example above.