On the most recent DotNetRocks TV episode, Carl and Scott demonstrate PowerShell: both its concepts and features, and a lot of how generally sweet it is. Unfortunately Scott ran out of time before he got to the good parts (he was just getting to object piping). Clearly there's room for more PowerShell.

One positive thing about the show is that after watching it, I was inspired to write this post.

Outline

I'm going to cover as many random useful things I've found inside PowerShell as humanly possible. Many of these things will be stupid simple; the common pattern you should notice is that, one way or the other, these scripts save me time, sanity, or time and sanity.

Let's begin!

ONE: Calling into DOS

One of the first things I tried to do in PowerShell was a recursive directory listing. In the CMD shell (the shell formerly known as DOS), the appropriate way to do this is dir /s.

It was quite a shock to find out PowerShell's dir command doesn't support a "/s" switch. Had I known back then what I know now, I would have felt better--you can run any DOS command (including those defined in the command shell itself) from PowerShell simply by prefixing the command with "cmd /c".

I'm not saying that you should be typing "cmd /c dir /s" to get a directory listing--you should be learning PowerShell's superior dir command. But I think it's also important to note that you can get the job done today, immediately, inside the PowerShell prompt, without learning any PowerShell. Just prefix your DOS command with "cmd /c".

I'll enumerate some useful things I've found, even after learning PowerShell:

cmd /c start .

(this opens the current directory in an Explorer window. The "start" command also opens documents and URLs)

cmd /c pause

(this runs the DOS pause command. This is a better solution than a "echo 'Press any key to continue...'; read-host;")

TWO: I'm too lazy to cut and paste--PowerShell is my laziness enabler

I can't say enough good things about the Set-Clipboard cmdlet, and how useful I find it. Here are some of the different things I've run:

(dir)[-1].Fullname | set-clipboard

(dir)[-2].Fullname | set-clipboard

(The above lines are just one act in a five-act play: "How do I copy the full path and name of this file?" 1. Run dir on the entire directory. 2. Eyeball the file you want. If it's close to the bottom, you can use PowerShell's "negative index" functionality to easily count backwards. 3. Get the FullName property of the file, 4. Run the command to copy this to the clipboard, 5. Paste full path and filename elsewhere. I'll note that this hasn't necessarily saved me time.)

(history)[-1] | foreach { $_.CommandLine } | out-string | set-clipboard
(First let me explain what this line does. This pulls the last command from PowerShell's command history, and copies it to the clipboard. in theory, I could have used some other way to get this command into the clipboard--but this is so much easier.)

history | foreach { $_.CommandLine } | out-string | set-clipboard

(This takes the entire history and pastes it to the clipboard. I intend to paste the PowerShell history directly into my Notepad equivalent for pruning into a real script.)

([Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")).FullName | set-clipboard

(This gets the 4-part .NET assembly name, which you'd otherwise have to manually transcribe from your Explorer window's representation of the GAC.  I have used this with SharePoint several times already.)

$a = (sn -T MySharePointWorkflow.dll)
$a[-1].Split(" ")[-1] | set-clipboard

(Assuming the above lines are errorr-free, this gets the PublicKeyToken from "MySharePointWorkflow.dll". If I'm wrong, well, let's all pretend I'm right anyway. Something looking vaguely like this has worked for me once or twice. You should be able to guess by now, but in case you haven't: yes, it's for SharePoint development.)

THREE: Automating SharePoint deployment and administration tasks

stsadm | find """feature"""

First, I'll note that the "stsadm" command is SharePoint's command-line administration tool. I'm running the "find" command to parse the text output and display any lines containing the word "feature". In other words: I'm doing a poor man's grep.

What you may notice above is the odd arrangement of double-quote marks. This gotcha is a side effect of PowerShell's pseudo-hands off approach to interpreting DOS commands. The triple-double quotes above (""") look awkward, but will evaluate down to a single set of quotes once the command is interpreted by DOS. The specifics aren't important. What's important is that once you understand how to escape characters properly like I've done above, you can easily run DOS commands from inside PowerShell. DO IT NATIVE!

SharePoint deployment scripts - I can't tell you how many times I've seen 7-line C# console utilities that are built to supplement missing SharePoint administration functionality. While a small C# console application gets the job done, PowerShell is built for this sort of one-time use console utility. If I could get away with it (and I might yet), I would love love love to abstract away all the SharePoint deployment/development/general ugliness that makes me angry, and replace it all with a post-deployment task/small script/everything script.

Another example I've seen recently: we needed to wire up a custom 404 handler and a custom 404 redirect page. "Deployment" of this solution required both updating a property on a SPWebApplication object and copying files in a very specific manner. I'm proud to say I was able to abstract away this ugliness with PowerShell!

FOUR: REPL in .NET!

EXAMPLE: I need to figure out how the System.Uri class works. Aside: if you're working on web apps and you're unaware of the Uri class, you will want to take a look at it. Moving on.

So in doing quick research on the Uri class (or any class really), there are a few options: MSDN (ha), Google (ok), in-process debug-time experimentation with the Visual Studio Immediate Window (ok), Lutz' Reflector (often excellent), or PowerShell (yessssss). I don't know if you've guessed by now, but we're going to inspect and try things out on the Uri class with PowerShell.

$u = [Uri]"http://test.site.com/testing?query=1&query2=a&query3isempty=&query4=something"
$u
$u | gm
$newUri = new-object "System.Uri" -arg $u, ([Uri]"http://some.other.site/letstry/relative/").PathAndQuery
$newUri

What's awesome about a read-eval-print loop (REPL) is that it reduces experimentation time from minutes (or hours!) to seconds. Actually, anyone who has used any scripting language will be able to tell you why REPL is awesome; feel free to read THEM instead of ME. I hear LISP has been around for a while; maybe you could ask your grandparents.