I have a PowerShell script that interacts with a TFVC repo in Azure DevOps. The code uses TF.exe for this interaction using an Azure DevOps username and PAT.
The PAT is valid and has the needed permissions. I am using the PAT as a password for a TF GET command (see example below). However, I noticed that every now and then, authentication will fail "Error TF30063: You are not authorized to access ...
" and I overcome this by opening the developer's command prompt and run any TF commands (such as trying to access to the workspace in question) which then prompts me to provide my Azure DevOps credentials (which I do). Then when I run the script again, it all works fine. I cleared all local Windows Credentials in Credential Manager, I also cleared these two directories trying to see how credential caching manifest itself for Visual Studio/TF.exe/Or Developer Command prompt (whichever applies):
An example from the script:
$tfCommand = "get '$($mapping)'"
$tfCommandOptions = "/recursive /login:$($userName),$($PAT)"
$fullCommand = "& `"$($tfPath)`" $($tfCommand) $($tfCommandOptions)"
Invoke-Expression $fullCommand
Where:
$mapping
is a Visual Studio workspace mapping (between the remote TFVC repo in Azure DevOps and a local folder). This workspace is private.$tfPath
is the path to TF.EXEHere is the login example:
$tfCommand = "workfold"
$tfCommandOptions = "/collection:$global:CollectionUrl /workspace:$global:Workspace /login:$global:Username,$global:PAT"
$fullCommand = "& `"$($TFPath)`" $($tfCommand) $($tfCommandOptions)"
$rawMappingResultAsString = Invoke-Expression $fullCommand
I am trying to understand the mechanics of this manual authentication and why is it required every now and then (almost every two weeks or so). If the TF commands have credentials when issued (in PowerShell script), why do I need that additional manual authentication sometimes?
To start, some credit to @alvin-zhao-msft as for what he put in his answer is correct (regarding OAuth, PAT authentication support in TF.EXE
, etc.) and helpful but wasn't the exact answer I was looking for.
The actual answer (or part of it) is found here How to logout of tf.exe and login through another account with 2FA enabled?
Essentially, TF.EXE
maintains its own source connections (independent from VS, at least by means of personal trial and error on my end). These connections also seem to contain the cached credentials (as I assume because once I removed them, I was asked to authenticate again when running commands like tf workspace myworkspace
)
Although that answer doesn't exactly specify how to remove such connections (to clear cached credentials), Copilot helped me in this regard:
tf settings connections /remove:serverURL
I couldn't find this specific command in Team Foundation version control commands and I believe the /remove
switch can take a list of serverURLs because when I cleared all connections and ran tf settings connections
again I get:
The collection must contain at least one element.
Parameter name: serverUrls
Which indicates that parameter takes a list of serverURLs. Since all lists in other tf
commands are semi-colon separated, I would assume this list is also semi-colon delimited. I haven't tried.
I hope this explains the mechanism by which TF.EXE
caches credentials to source control.
Additional information for people to research and investigate:
The interactive authentication screen you get from running a TF command in a Developer Command Prompt or Developer PowerShell for the first time seems to be dependent on the Visual Studio version you are using. Claude.ai suggested that TF does relay on Visual Studio to generate OAuth tokens using some internal libraries and logic when creating its (TF's) source connections as mentioned above. Following this path I found this article Enhancing your Visual Studio authentication experience which clarified more about my setup. I do use VS 2022 (a higher version than the on in the article) and inspect my settings I am suing Windows authentication broker as the default authentication mechanism. And although the Azure DevOps instance is not connected to Microsoft Entra ID, the organization is on Azure and the users are on Entra ID (which perhaps what Visual Studio is communicating to when obtaining an OAuth token on behave of my Azure DevOps username and password since I am using the same credential in both, DevOps and Azure Entra ID). Especially since AzureCloud is listed in the "Registered Azure Clouds" in Visual Studio > Tools > Environment > Accounts.
I didn't want to spend more time researching this issue but I hope this post adds more details that might be helpful in the future.