Why does this code behave this way?

Please see the example code below. I was seeing an odd error in one of my scripts, after a couple hours, I found the source, but still don’t fully understand the behavior.

The example code below works properly as shown. But if I Comment out the $UserReportObj = Set-CommonValues -UserReportObj $UserReportObj line in the Process-UserObject function, and uncomment the line above it, I get 4 objects in the ‘$Report’ variable at the end of the script instead of only two. I understand why the code works when I’m explicitly assigning the return value from the Set-CommonValues function to the $UserReportObj variable, what I can’t quite figure out is why I get 2 additional objects in the ‘$report Variable’ when the $UserReportObj is NOT explicitly assigned to grab the return of the function.

My expectation would be that the return value from the Set-CommonValues function would just be lost since I’m not assigning the value to something in the calling function, OR, if powershell handles objects as a reference, I wouldn’t even NEED to return a value from the Set-CommonValues function (The Add-Member command would update the referred object). Instead I get two separate entries in the $Report Variable.

Can someone explain to me what’s going on behind the scenes here?

Example Code

Function Set-CommonValues
{
	param
	(
		[Parameter(Mandatory)]
		[object] $UserReportObj
	)
	
	$UserReportObj | Add-Member -Type NoteProperty -Name "Set Value 1" -Value $True -Force
	$UserReportObj | Add-Member -Type NoteProperty -Name "Set Value 2" -Value $True -Force
	
	Return $UserReportObj
}

Function Process-UserObject
{
	
	param
	(
		[Parameter(Mandatory)]
		[object] $UserReportObj
	)
	
	$UserReportObj | Add-Member -Type NoteProperty -Name "Ad Domain" -Value "contoso.com" -Force
	
#	Set-CommonValues -UserReportObj $UserReportObj
	$UserReportObj = Set-CommonValues -UserReportObj $UserReportObj
	
	return $UserReportObj	
}

$Names = ("John Doe", "Jane Doe")
$Report = @()

foreach($Name in $Names)
{
	$UserObj = New-Object -TypeName PSObject
	$UserObj | Add-Member -Type NoteProperty -Name "Name" -Value $Name -Force
	
	$UserObj = Process-UserObject -UserReportObj $UserObj
	
	$Report+= $UserObj
}

return $report

Everything that’s unassigned gets sent to the output stream.

Your function Process-UserObject is outputting the results of Set-CommonValues and $UserReportObj.

function getFoo {
    'foo'
}

function test {
    getFoo
    $bar = 'bar'
    return $bar
}

test

Will output:

foo
bar

Assigning the result to NULL is one way to suppress the output:

$null = Set-CommonValues -UserReportObj $UserReportObj
1 Like

OK, Thank you! That makes sense now. Looks like I need to read up a bit on powershell piping and the output stream. Coming from a C background, I couldn’t figure out how the heck this was happening.