Access to the path is denied" when using Publish Artifact build step when Contents has additional items in new TFS 2015 vNext build

One of my customers reported the following bug in the build and has been accepted by product team also, so wanted to share this, just in case someone is facing this.

 Problem Description

==================

In summary customer is seeing issues during the build with access denied errors being thrown when working with artifacts (created as part of the Publish Build Artifacts build step). From what they have witnessed to date the key points seems to be as follows:

 Within the build definition we have clean specified under both Build and Repository

 

 

 

 

Within the Publish Build Artifacts public task we are outputting varied files, but to keep it simple we’ll say everything from the build folder (i.e. **)…

 

 

 

With the above settings they get errors such as…

 

15:57:06.152968 BaseLogger.LogConsoleMessage(scope.JobId = 464f2d0e-450a-4b67-b1e9-959187e37644, message = Deleting artifactsStagingFolder: D:\IISTempFiles\AgentWorking\Agent-IISDAV00B1-1\55124e4f\artifacts)

15:57:06.168596 ---------------------------------------------------------------------------

15:57:06.168596 System.UnauthorizedAccessException: Access to the path 'ClassLibrary1.sln' is denied.

15:57:06.168596    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive, Boolean throwOnTopLevelDirectoryNotFound)

15:57:06.168596    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive, Boolean checkHost)

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Plugin.Build.BuildJobExtension.OnPrepareEnvironment(IJobContext context, IDictionary`2 savedSettings, IJobRequest job, CancellationToken cancellationToken)

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Worker.JobExtensionManager.<>c__DisplayClass8.<OnPrepareEnvironment>b__7()

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Worker.JobExtensionManager.TryAction(String method, Action action, Boolean throwOnError)

15:57:06.168596    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive, Boolean throwOnTopLevelDirectoryNotFound)

15:57:06.168596    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive, Boolean checkHost)

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Plugin.Build.BuildJobExtension.OnPrepareEnvironment(IJobContext context, IDictionary`2 savedSettings, IJobRequest job, CancellationToken cancellationToken)

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Worker.JobExtensionManager.<>c__DisplayClass8.<OnPrepareEnvironment>b__7()

15:57:06.168596    at Microsoft.TeamFoundation.DistributedTask.Worker.JobExtensionManager.TryAction(String method, Action action, Boolean throwOnError)

15:57:06.168596 ---------------------------------------------------------------------------

 

Ultimately the issue appears to be down to the fact this it fails when trying to delete items from the artifacts folder that are readonly.

 

The issue has been described in following MSDN forums as well

 

https://social.msdn.microsoft.com/Forums/vstudio/en-US/4b0aa103-17ac-4563-9b69-0dbbae56c1cd/access-to-the-path-is-denied-when-using-publish-artifact-build-step-when-contents-has-additional?forum=tfsbuild

 

https://connect.microsoft.com/VisualStudio/feedback/details/1826751/on-premise-publish-build-artifacts-step-fails-when-content-filter-includes-read-only-files-from-version-control

 

Microsoft Product team has acknowledged it and they ’ll get a fix in this sprint (will ship to VSO in a few weeks).

 

A workaround for now is to add a Command Line task before the Publish Build Artifacts task. You would want to set the inputs on the task to something like the following:

Tool:     Powershell.exe

Arguments: -ExecutionPolicy Bypass -Command "dir '$(Build.SourcesDirectory)' -Recurse -Filter *.pdb | ForEach-Object { [System.IO.File]::SetAttributes($_.FullName, ([System.IO.File]::GetAttributes($_.FullName) -band (-bnot [System.IO.FileAttributes]::ReadOnly))) }"

 Or you could move the logic into a ps1 script and call that using a PowerShell task. You might be able to speed up the logic a little by checking if the file attributes contains the readonly flag before blindly updating it. Anyway, that’s the gist of the workaround

 

Written by: Nitish Nagpal

Support Escalation Engineer

Reviewed by: George Archer

Senior Escalation Engineer