Search code examples
powershelltfs-sdkazure-pipelines

Unable to call correct .NET overload when passing string[]


I have a method I'm trying to call from powershell, it's

 Workspace.GetPendingChanges(string[] items)

Of this method there are multiple overloads, but the ones making my life hard are:

 Workspace.GetPendingChanges(string items)
 Workspace.GetPendingChanges(string[] items)
 Workspace.GetPendingChanges(ItemSpec[] itemspecs)

I'm grabbing a list of files using the Find-Files cmdlet from TFS 2015's new build tasks:

if ($ItemSpec.Contains("*") -Or $ItemSpec.Contains("?"))
{
    Write-Verbose "Pattern found in solution parameter. Calling Find-Files."
    Write-Verbose "Calling Find-Files with pattern: $ItemSpec"    
    [string[]] $FilesToCheckin = @(Find-Files -SearchPattern $ItemSpec -RootFolder $env:BUILD_SOURCESDIRECTORY)
    Write-Verbose "Found files: $FilesToCheckin"
}
else
{
    Write-Verbose "No Pattern found in solution parameter."
    [string[]] $FilesToCheckin = @($ItemSpec)
}

And then I call:

$pendingChanges = $provider.Workspace.GetPendingChanges( @($FilesToCheckin))

I've tried about any version of casts [string[]] forced array notation @() I know, but the result from find-files is always converted to a single long string, before being passed into the correct overload:

System.Management.Automation.MethodInvocationException: Exception calling "GetPendingChanges" with "1" argument(s): "TF400889: The following path contains more than the allowed 259 characters: 

This is the "long string" that's generated

C:\TfsData\Build\_work\1\s\BuildProcessTemplates\AzureContinuousDeployment.11.xaml C:\TfsData\Build\_work\1\s\BuildProcessTemplates\DefaultTemplate.11.1.xaml C:\TfsData\Build\_work\1\s\BuildProcessTemplates\LabDefaultTemplate.11.xaml C:\TfsData\Build\_work\1\s\BuildProcessTemplates\UpgradeTemplate.xaml C:\TfsData\Build\_work\1\s\checkin-changes.ps1 C:\TfsData\Build\_work\1\s\update.txt C:\TfsData\Build\_work\1\s\updatefile.ps1. 

 

Specify a shorter path." ---> Microsoft.TeamFoundation.InvalidPathException: TF400889: The following path contains more than the allowed 259 characters: C:\TfsData\Build\_work\1\s\BuildProcessTemplates\AzureContinuousDeployment.11.xaml C:\TfsData\Build\_work\1\s\BuildProcessTemplates\DefaultTemplate.11.1.xaml C:\TfsData\Build\_work\1\s\BuildProcessTemplates\LabDefaultTemplate.11.xaml ...
    at System.IO.PathHelper.GetFullPathName()
    at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
    at System.IO.Path.GetFullPathInternal(String path)
    at Microsoft.TeamFoundation.Common.FileSpec.GetFullPathWrapper(String path)
    --- End of inner exception stack trace ---
    at Microsoft.TeamFoundation.Common.FileSpec.GetFullPathWrapper(String path)
    at Microsoft.TeamFoundation.Common.FileSpec.GetFullPath(String path, Boolean checkForIllegalDollar)
    at Microsoft.TeamFoundation.VersionControl.Common.VersionControlUtil.GetFullPath(String item, PathLength maxServerPathLength)
    at Microsoft.TeamFoundation.VersionControl.Client.ItemSpec..ctor(String item, RecursionType recursionType, Int32 deletionId)
    at Microsoft.TeamFoundation.VersionControl.Client.ItemSpec.FromStrings(String[] paths, RecursionType recursion)
    at 

This indicates it's calling the correct overload

Microsoft.TeamFoundation.VersionControl.Client.Workspace.GetPendingChanges(String[] items, RecursionType recursion, Boolean includeDownloadInfo)

The cmdlet returns a List<string> following:

protected override void ProcessRecord()
{
    base.ProcessRecord();
    if (!this.IncludeFiles && !this.IncludeFolders)
    {
        this.IncludeFiles = true;
    }
    List<string> sendToPipeline = FindFiles.FindMatchingFiles(this.RootFolder, this.SearchPattern, this.IncludeFiles, this.IncludeFolders);
    base.WriteObject(sendToPipeline, true);
}

To ensure I got a list from the call to Find-Files I added:

Write-Verbose "Found files: " -Verbose
Write-Verbose $FilesToCheckin.Count -Verbose

Which returns: 7, as expected.

My Question

How do I prevent Powershell from converting the result from find-files into one long string before passing it to GetPendingChanges?

Project available at, broken code commented out at the bottom:


Solution

  • I don't know why this works, but after adding @() and casts to [string[]] everywhere and removing the Write-Verbose $FilesToCheckin it works:

    if ($ItemSpec.Contains("*") -Or $ItemSpec.Contains("?"))
    {
        Write-Verbose "Pattern found in solution parameter. Calling Find-Files."
        Write-Verbose "Calling Find-Files with pattern: $ItemSpec"    
        [string[]] $FilesToCheckin = @(Find-Files -SearchPattern $ItemSpec -RootFolder $env:BUILD_SOURCESDIRECTORY)
    }
    else
    {
        Write-Verbose "No Pattern found in solution parameter."
        [string[]] $FilesToCheckin = @($ItemSpec)
    }
    
    $pendingChanges = $provider.Workspace.GetPendingChanges( [string[]] @($FilesToCheckin) )