4

I've got a build script (PowerShell 4 on Windows 2012 R2) that runs NUnit in a background job and returns NUnit's output. This output is collected in a Collections.Generic.List[string].

$nunitJob = Start-Job -ScriptBlock { 
                                    param(
                                        [string]
                                        $BinRoot,

                                        [string]
                                        $NUnitConsolePath,

                                        [string[]]
                                        $NUnitParams,

                                        [string]
                                        $Verbose
                                    )

                                    Set-Location -Path $BinRoot
                                    $VerbosePreference = $Verbose

                                    Write-Verbose -Message ('{0} {1}' -f $NUnitConsolePath,($NUnitParams -join ' '))
                                    & $NUnitConsolePath $NUnitParams 2>&1 
                                    $LASTEXITCODE
                                 } -ArgumentList $binRoot,$nunitConsolePath,$nunitParams,$VerbosePreference

$nunitJob | Wait-Job -Timeout ($timeoutMinutes * 60) | Out-Null
$jobKilled = $false
if( $nunitJob.JobStateInfo.State -eq [Management.Automation.JobState]::Running )
{
    $jobKilled = $true
    $errMsg = 'Killing {0} tests: exceeded {1} minute timeout.' -f $assembly.Name,$timeoutMinutes
    Write-Error -Message $errMsg
}

$output = New-Object 'Collections.Generic.List[string]'

$nunitJob | 
    Stop-Job -PassThru | 
    Receive-Job |
    ForEach-Object  { 
        if( -not $_ )
        {
            [void]$output.Add( '' )
            return
        }

        switch -Regex ( $_ )
        {
            '^Tests run: (\d+), Errors: (\d+), Failures: (\d+), Inconclusive: (\d+), Time: ([\d\.]+) seconds$'
            {
                $testsRun = $Matches[1]
                $errors = $Matches[2]
                $failures = $Matches[3]
                $inconclusive = $Matches[4]
                $duration = New-Object 'TimeSpan' 0,0,$Matches[5]
                break
            }
            '^  Not run: (\d+), Invalid: (\d+), Ignored: (\d+), Skipped: (\d+)$'
            {
                $notRun = $Matches[1]
                $invalid = $Matches[2]
                $ignored = $Matches[3]
                $skipped = $Matches[4]
                break
            }
        }

        # Error happens here:
        [void] $output.Add( $_ )
    }

Intermittently, our build will fail with this error:

Cannot find an overload for "Add" and the argument count: "1".
At line:XXXXX char:XXXXX
+ [void] $output.Add( $_ )
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest

Any idea why PowerShell would not be able to find List[string]'s Add method?

I've opened a console Window and played around with passing different typed objects to Add without getting an error.

> $o = New-Object 'Collections.Generic.List[string]'
> $o.Add( '' )
> $o.Add( $null )
> $o.Add( 1 )
> $o


1
9
  • 1
    Problem is most likely that it cannot implicitly convert $_ to a string. Like $o.Add($(New-Object psobject)) Commented Aug 27, 2015 at 23:34
  • @zespri I did remove some lines, but none that involved $output. Commented Aug 27, 2015 at 23:35
  • 1
    @MathiasR.Jessen That may be it. I tried $output.Add( [pscustomobject]@{ } ) and am able to reproduce the error. Now I have to figure out why PowerShell isn't treating console output as strings. Commented Aug 27, 2015 at 23:38
  • "treating console output as strings"? Do you attempt to modify $_ in any way during foreach-object? Again, the entire code block might be useful/meaningful here. Commented Aug 27, 2015 at 23:43
  • 3
    It might be worth adding a Write-Verbose $_.GetType().Fullname -Verbose just to see what kind of object you are dealing with. Commented Aug 28, 2015 at 2:21

1 Answer 1

1

When you redirect stderr to stdout, you can get System.Management.Automation.ErrorRecords interspersed with strings. Stderr is automatically converted to ErrorRecords while stdout is strings.

So you'll probably want to look to see if the output contains ErrorRecords of interest and if not then filter them out.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.