PowerShell is the Windows (and especially the Windows Server) answer to everything-automation: every which part of the OS and its services provides a way to control it from PowerShell. And the PowerShell scripts are The Way to automate everything.
But here is the unusual part: It's not a normal OS shell. I've tried it before as an OS shell and it didn't work well for me then because I didn't understand its purpose. Well, it can be used as an OS shell, and in some ways claimed to be an OS shell, but in my opinion that's not its strength. Instead, it's the shell for the .NET virtual machine. Exactly the thing that Java is missing, and the gap that it tries to plug with the crap like Ant and Maven, unsuccessfully. PowerShell lets you run all the .NET methods interactively from the command line, and build the pipelines of them. It has some very cool syntax that lets you automatically apply the pipeline input in the same way as the command-line input. It also has the remote execution functionality, so it serves as an analog of the rsh/ssh (more advanced in some ways, less advanced in the others) in the Microsoft ecosystem.
It's also not an enclosed language. Your typical language, such as a Unix shell, operates with the primitives that are a part of the language. For example, in a Bourne (and derived) shell there are commands (as either a binary executable, or an embedded command, or a shell function), variables, and the syntactic constructions. You mostly deal with them. If sometimes they're not enough and say you want to use some Perl statements or data structures, you'd call Perl as a command, pass some values as arguments and the program as an argument or file, and deal with the Perl data structures inside the Perl program. Not so with the PowerShell. PowerShell is symbiotic with .NET and especially with C#. Many things that you'd want to deal with in a PowerShell program don't exist as a PowerShell command. Instead they exist as a .NET object and PowerShell knows how to deal directly with the .NET objects. All of the .NET is available from PowerShell, and quite often when you need to deal with something and want to find how to do it, you need to look in the .NET manuals, not in the PowerShell manuals.
The .NET integration is quite powerful. You can even compile the C# code on the fly (it's called P/Invoke) and call it. And there are ways to call the native C functions from C#, so in result you can even call the native code from PowerShell.
But it's both a blessing and a curse. Let me illustrate it with an example of arrays. The PowerShell arrays are fixed. Once an array is created, it cannot be grown or shrunk. Which is quite different from say Perl or even from Unix shells with their shifts, and really annoyingly inconvenient. In my searches I've encountered a feature request on Technet asking for the pushable arrays like in Perl that got turned down. So, why did it get turned down? As it turns out, .NET has the classes that do that. You can create a System.Collections.ArrayList or System.Collections.Queue object from PowerShell, and get what you need:
$array = New-Object System.Collections.ArrayList
And then even all the operations that work on the PowerShell arrays happen to work on the ArrayList as well, for example ($array -join ","), I suppose because they use the general Collections interfaces.
So as you can see the blessing is that there is a great variety of stuff coming right out of the box. The curse though is that it's a pain to use and a pain to remember. Too much generality, not enough convenience.
Oh, and for the record, the idiom to shift a classis PowerShell array is:
$head, $array = $array
I haven't invented it myself, just found somewhere in some examples. It's not the cheapest thing to do in a deeply nested loop, since it creates a whole new array minus one element, but plenty good enough for the typical shell usages.