IT:AD:PowerShell:HowTo:Gotchas
Summary
No question about it – Powershell's idiosyncrasies are so infuriating that there are days that I want to take the creators of PowerShell out back and beat them to a pulp for the amount of time I've lost debugging.
Tips
Prefer Void Returns
Prefer void returns, unless the function's point is to return a variable.
Powershell is a pipe mechanism where any unused variable created in one module is put made available to the next Module. This can drive you nuts.
function Foo1(){
return "Foo";
}
# Invoke it, and you get back "Foo", as one would expect from any language:
c:>Foo1
Foo
Let's chain two processors together, and try again:
function Bar2(){
return "Bar";
}
function Foo2(){
$x = Bar2;
return "Foo";
}
# Invoke it, and you get back "Foo", as one would expect from any language:
c:>Foo2
Foo
This time, let's be totally flummoxed:
function Bar3(){
return "Bar";
}
function Foo3(){
Bar3;
return "Foo";
}
# Invoke it, and you get back "Foo", as one would expect from any language:
c:>Foo3
Foo
Bar
# say what?!? Two outputs?!?!!
That combined with the second fact that if the return value of an invoked method only has one item (eg: as string) the return value will be a single value, but if it finds more than one, the string will be wrapped in an array…and you quickly go nuts:
Write-Host Foo2 Write-Host Foo3 #shit, that's not right...maybe it's the second item I want Write-Host Foo3[1] # but that stinks...and is going to sooner or later trip up.
The reason is that Powershell is trying to be helpful (like a kick in the head!) and is packing the output with everything that was created, that you may need, further down the pipeline.
I'm sure it could be very useful. Except I haven't found a use for it.
Instead, just ensure that if your function is either an Action or a Function, and vigorously don't return a value if it is not going to be used. In other words:
void Ensure-Directory($path){
...check the directory...and make it if not...
#Do NOT do this.
#a) the value is already known by the invoker
#b) as invoker already has it, it's not guaranteed
# it will use it. And if the response is not used
# (ie, put into a variable)
# it will pack the pipeline uneccessariy, and turn
# the response of the invoker into an array...
#NO!!!! return $path
}
void Get-DirectoryPAth($args){
$result = ....calc something the invoker doesn't know...
# on the other hand this will always be used
# so go right ahead
return $result;
}