Sometimes you think you understand something just fine – until it stops working, and then you realise you didn’t have a clue. So it was with me and the “Return” statement in PowerShell functions
I’ve been doing a lot of documentation scripts that pull out FIM configurations and put them into nice Word documents. I’d already started putting reusable chunks of script into functions, and all was going swimmingly, until suddenly it wasn’t.
I had improved my “StartDoc” function so it would take a Word template file as input. Here’s how it looked:
Function StartDoc { PARAM([string]$Orientation = "Portrait", [string]$TemplateFile) END { if ($Orientation.ToLower() -eq "landscape") {$o = 1} else {$o = 0} $word=new-object -ComObject "Word.Application" if ($TemplateFile -ne "") { if (-not (Test-Path $TemplateFile)) {Throw "Template not found $TemplateFile"} $document=$word.documents.Add($TemplateFile) } else { $document=$word.documents.Add() } $word.Visible=$True $document.PageSetup.Orientation = $o $selection=$word.Selection #Move to end of document $selection.EndOf(6) Return $selection } }
The function worked perfectly and did what I wanted – but something weird was happening to that $selection object. Inside the function it correctly represented the document and my location in it – once returned back to the main script it became a string array and I lost all my properties and methods!
Of course lots of googling followed. One thread I found said “that’s the way it’s supposed to work, deal with it” but I knew it had been working before I added the template support!
Eventually the culprit turned out to be the line “$selection.EndOf(6)” which makes your cursor skip to the end of the document, something I hadn’t needed before when I was just loading a blank document without any template. And it’s not anything particular about that command – it’s just that it returns a value – in this case, the line number you’re skipping to.
It turns out that “Return” command is a bit misleading. Yes the function returns that value, but it also returns anything else in the function that produces output. If more than one thing needs to be returned you get an array.
So the secret is to make sure that no function line produces any output except things you actually do want returned to the calling script. I could do this is a couple of ways:
$linenumber = $selection.EndOf(6) or $selection.EndOf(6) | Out-Null