Get-ChildItem
Guess what it does by looking at its name.Correct, it lists the contents of a directory! What else could it be? Conversely, if you want to find out what "dir"/"ls" would be in PowerShell, where else would you be looking!
I like the idea of PowerShell a lot (object-oriented piping), but I hope it evolves into something with saner default aliases and better documentation, with easy things accomplished easily.
Not so hopeless (although if you ask for detailed docs it opens a browser for you,internet required):
PS C:\Users\xxx> help ls
NAME
Get-ChildItem
SYNTAX
Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [<CommonParameters>]
Get-ChildItem [[-Filter] <string>] [<CommonParameters>]
ALIASES
gci
ls
dirFilesystems, most of them anyway, are structured as trees of files and directories.
Therefore one would expect a command named "Get-ChildItem" executed against the current directory to do...?
(Aside from that, the Powershell default alias set translates both "dir" and "ls" to Get-ChildItem.)
It does so much more than that. It can display child items from any PSProvider (Get-PSProvider): defined aliases, environmental variables, defined variables, defined functions, registry nodes, X.509 certificate containers and even Active Directory paths. "FileSystem" is just one provider amongst many.
You can also `cd` to any of these providers to use them in a filesystem-like manner. e.g. `cd HKLM:\`, `cd AD:\` (if you have the ActiveDirectory module)
That's why the name is abstract. Many of the default cmdlets work on all kinds of stuff, not just bare filesystem stuff.
You say you run compare-object and you're surprised that it returns an object; Powershell is essentially an object-oriented pipeline, so a return object should always be the expected case. You say is that it's hard to coerce the object into a text-stream that you can munge, but again I suspect that your difficulties are again a misunderstanding of exactly how you should be operating in Powershell. Even me saying "coerce the object into a text-stream" is disingenuous, because what you'll end up with is almost always going to be `string[]`. Once you've thrown away all of the data contained in the object except for the one string property you want, you've thrown away all of the value of Powershell.
None of this difficulty is your fault. In bash you would "just" pipe the output of `diff` into `awk`, but that "just" is a cop-out: bash is nearly as complex as Powershell itself before you throw awk into the mix. You already know awk and bash, so it's natural to you and all of your preconceptions about how the shell should work are met.
Powershell is entirely capable of doing what you want to do with it, but it's a completely different world. If you persist with it, and you do get the hang of it, I promise you'll understand the value of the concepts behind it.
Maybe, but I still want to make the case that Powershell sucks:
- Function return values. WTF were they thinking when they decided it was useful when the result of a function is an array of every statement result within that function? And why isn't there a useful way (like, say, "return") that overrides that behaviour?
- Automatic unboxing and splatting of arrays. If I have a list of one element, I want to know that I have a list of one element. If I ask for the Length of that array, I do not want to know the length of that single element (which is not 1, in the case of a list of strings).
- Case sensitivity. Sorting in Powershell is always case-insensitive, except when it isn't (when you use a .Net sort algorithm instead of Sort-Object). Still, Get-Unique is always case sensitive, as is Select-Object -Unique. Of course, you can get case insensitive uniqueness by using Sort-Object -Unique.
- The -AsString weirdness. Multiple Powershell commands can process String lists, and know they're processing String lists, but they will still return their results as Strings wrapped in PSObject. This leads to very fun results when you're trying to use those results as HashTable keys. I've lost days debugging this madness, especially when coupled with the implicit autoboxing I mentioned above.
Because in a pipeline results are usually »whatever the element happens to have as its output«. Usually you know or notice if statements within your function have return values or not. I haven't found it problematic so far, either. You don't write PowerShell like C# anyway, so different patterns are idiomatic. You'll get the hang of it fairly quickly.
> And why isn't there a useful way (like, say, "return") that overrides that behaviour?
There is. It's called return:
return (expr)
is the same as (expr)
return
and return will immediately exit the function / script block.> Automatic unboxing and splatting of arrays.
Admittedly, this can be annoying, however this only ever applies to function or cmdlet output. When you're creating a one-element array (via @(1) or ,1) it stays that way unless used as the first part in a pipeline, where unwrapping is usually wanted.
You can also use Count instead of Length (unless your items have a Count property) since v3, as PowerShell implicitly understands reading the Count property on a scalar value that doesn't have it and returns 1.
The usual fix is to explicitly make the return value an array, though:
$foo = @(Get-Foo)
PowerShell cannot know that a call results in multiple values or just one, e.g. Get-Service yields an array, but Get-Service foo yields a single object. It's not unreasonable to expect something like (Get-Service foo).DisplayName to work instead of having to do either (Get-Service foo)[0].DisplayName or Get-Service foo | % DisplayName.So it's a trade-off between two ugly things. Trade-offs are always bound to annoy people who consider one thing worse than the other.
> Still, Get-Unique is always case sensitive, as is Select-Object -Unique. Of course, you can get case insensitive uniqueness by using Sort-Object -Unique.
Huh, learned something new there, thanks. I think the only instances where I needed unique strings was in golfing, so sort -u was the way to go anyway. At least it's documented in each of those cases.
As for sorting using the .NET method not adhering to the defaults used throughout PowerShell, I think that's hardly surprising. You're explicitly leaving PowerShell and using the BCL directly. Of course other rules apply. And there are even worse annoyances on that front, such as that PowerShell's current directory is not the process' current directory (so you can't really use relative paths with .NET APIs).
> -AsString
Never used, to be honest, so no opinion here.
I know. Just to be sure, my beef is that:
function test() {
1
return 2
}
still returns @(1,2), not just 2 [void](expr)
$null = (expr)
(expr) | Out-Null