| I've recently written a couple thousand lines of PowerShell. It's a miserable language, full of unexpected behaviors and badly designed features. Oh, it's got some interesting stuff going on, but things like: - including the text of 'echo' (and stdout generated by invoked tools) in a function's result was a big surprise. You wind up piping stuff to "Out-Null" a lot in defense of this, since a lot of Windows tools are stupidly chatty ("The Blffgh command succeeded with status 0!") and that's awkward. - so was the "unwrapping" that happens when a function returns a list (return [a,b] you get the list you want, try to return [a] and it rips off the list and just returns the inner 'a', and I think an empty list results in null . . . just wow). The sole reason I use PowerShell is because it's good for mucking with OS-level objects in Windows, stuff that I would otherwise have to write native code to frob. And sometimes that is actually kind of attractive. |
Yes, the output from calling native commands within functions can be a little tricky, and something that annoyed me initially, but once you understand the concept of passing objects around, not strings, you quickly get used to either capturing the output into a variable ($BlahResult = .\blah.exe /foo bar /baz 2>&1), where you can then access the string output (stdout) and any ErrorRecord (stderr) lines, or as you suggested, piping to Out-Null if you don't actually need the output. If you're writing your own 'echo' type statements for debugging or information purposes, you learn to use Write-Verbose or Write-Debug instead of Write-Output (which is what happens by default).
The unwrapping example was something that got me initially, because I was used to defining a collection (array, List, whatever), populating it, and then returning that collection... and then having the calling code iterate over that collection. "The PowerShell way" is to not focus on the collection/array at all, but instead just let it take care of that and deal with the items themselves. If you pipe the output of a function to Foreach-Object, it will work correctly - if it's a single object returned, that's what will be $_ in the loop, if it's multiple, they will all be passed in one-by-one as $_... if you actually want to access the array itself (for example to count the number of items), then you can enforce the array type by wrapping it in an additional array (i.e. @($Users).Count).