Friday, July 11, 2008

Returning objects from PowerShell functions

This can be very confusing and I am sure that I will need to describe it to some people in future, so I will rather write small post about it now and just send them link in future ;)

Difference between subroutines and functions is that functions returns some data...

So for example Get-Date that RETURNS date is function. Get-Date that will ONLY display date on screen is subroutine.

If you are used to programming, usually you do something within body function and then you return some object.

Lets have a look at below example. You just run function and it should return "Test" string:

Function Test {
Write-Host 'I want to return object of [String] type with value "Test"'
Return "Test"
}

Makes sense, right? If we run it, we can see following:

PS C:\Links\HDDs\DevHDD\WorkingProjects\S4Maintenance> Test
I want to return object of [String] type with value "Test"
Test

Looks fine so far. Now lets try to assign output from that function to some variable:

PS C:\Links\HDDs\DevHDD\WorkingProjects\S4Maintenance> $Output = Test
I want to return object of [String] type with value "Test"
PS C:\Links\HDDs\DevHDD\WorkingProjects\S4Maintenance> $Output
Test

Still completely normal. But I want to make that function reaaaally really short, so I will remove Write-Host, it's now really needed:

Function Test {
'I want to return object of [String] type with value "Test"'
Return "Test"
}

Still makes perfect sense, right? But it won't work:

PS C:\Links\HDDs\DevHDD\WorkingProjects\S4Maintenance> $Output = Test
PS C:\Links\HDDs\DevHDD\WorkingProjects\S4Maintenance> $Output
I want to return object of [String] type with value "Test"
Test

As you can see both lines are returned... Reason for this is simple:

If you assign output from function to variable, it is NOT object specified after Return command that is returned, but whole output from function.

Only exception (as far as I know) is Write-Host, that is ignored. This behavior can be VERY confusing, because your function can work perfectly, but then suddenly (once you improve it or add more code), it will return System.Object instead of Xml.XmlElement etc.

For workaround, I am passing Output variable name as parameter also:

Function TestOutput ([string]$OutputVariable) {
    Write-Host $OutputVariable
    Set-Variable -Value 0 -Name $OutputVariable -Scope 1
}

$MyVar = 1
Test "MyVar"

As you can see, output is assigned to variable provided as argument. I don't really like this, however I still think it can make your functions more robust. This is specially case with processing XML - some methods will automatically display output from operation to screen and then your output is immediately corrupted.

 

How do you solve this, any ideas???

1 comment:

Bhavna said...

Thank you for this life-saving post.

I found another method that works. You can also pipe every command's output within the function to out-null.