PowerShell V3: A Few of My Favorite Things

Posted on Posted in PowerShell Scripting, SharePoint 2013

Now that SharePoint 2013 has been released to manufacturing and will be available for download soon I figured I’d go ahead and put together a quick post pointing out some of my favorite PowerShell V3 enhancements that you can use to improve your command-line usage of PowerShell as well as your automation scripts.

PowerShell V3 + SharePoint 2010

The first thing I wanted to do before I get into some of the new stuff was to answer a question I’ve seen a lot lately via twitter and forum posts – can I use PowerShell V3 with SharePoint 2010? The simple answer is no, you cannot. PowerShell V3 requires the .NET 4 runtime which is not compatible or supported with SharePoint 2010. This is due to an unmanaged COM component that most of the SharePoint APIs wrap. However, if you have installed PowerShell V3 on your SharePoint 2010 servers you need not fret for you can still use PowerShell, just not any of the new stuff. This is because PowerShell V3 is installed in side-by-side mode which means that you can still load PowerShell V2: simply add the “-version 2” command-line switch to the powershell.exe executable: powershell.exe -version 2.

When you need to work with SharePoint you won’t be able to use the Windows PowerShell ISE or any of the new PowerShell language enhancements but at least you’ll still be able to work, and you’ll be able to leverage the new features for any non-SharePoint work, something that your more savvy IT administrators might be very appreciative of. Also, if you install a third party application like PowerGUI (at least the current version 3.2) it will run using the PowerShell V2 runspace so you still get a nice visual editor for your SharePoint 2010 work and you can use the ISE V3  for non-SharePoint work.

Show-Command

Not too long ago Microsoft released an online tool called the Windows PowerShell Command Builder. This tool allowed users to visually construct a command by dragging and dropping tiles representing nouns and verbs and then filling in the various fields provided by the tool. This proved a great way for folks who have never really worked with PowerShell before to start creating commands that performed useful tasks. The problem is that the tool is limited to the set of cmdlets made available within. So the PowerShell team created what I view as the evolution of this tool: Show-Command (I’ve no idea whether or not they used the online tool as the catalyst for this feature but the timing and similarities are such that it’s easy to assume as much).

Show-Command is a new cmdlet which has a visual interface associated with it. The cmdlet allows you to easily see all the parameter sets associated with a cmdlet via a simple form which you can fill out to construct a cmdlet call. Like the online tool, users who aren’t as familiar with using the command-line can now use a nice and familiar form to construct a call – this can then be copied to the clipboard for pasting into an editor or immediately executed.

If you’re proficient with PowerShell then this is a new feature that you can easily gloss over (I personally don’t see myself using it for anything other than demos) but if you’re among the many who are just getting into it then this can really help you – not just in the usage of cmdlets but also in the discovery of them as one of the additional features is a cmdlet search (simply call Show-Command without any parameters). So you might ask, “if you don’t plan on using it then why is it on your favorites list?” Well, it’s on my favorites list because I spend a lot of time helping first timers find and use cmdlets (often over the phone with no way for me to see what’s actually being typed) and a cmdlet like this will make this much easier for me and those I’m helping.

SNAGHTMLb316d1e SNAGHTMLb325b43

Windows PowerShell ISE

Yeah! The ISE now has full intellisense!!! I personally have a horrible memory and I live by intellisense so one of the first things I usually install in any environment is PowerGUI – for one reason only, intellisense. But sometimes I get resistance from administrators when it comes to installing third party products like this; but now that I can get intellisense with the ISE I can avoid the need for PowerGUI entirely (only thing it appears to be missing is the ability to copy with syntax highlighting – very useful for blogging – copying as RTF works great but there’s nothing out of the box for copying as HTML).

image

UPDATE 10/23/2012: I’ve created an add-on for the ISE that allows you to copy as HTML thus addressing my concern raised above.

Member Enumeration

So we’ve gotten the more obvious changes out of the way, now let’s look at some things that aren’t quite as obvious: member enumeration changes. These changes are subtle but fantastic and make working on the command-line with PowerShell so much nicer (they also make scripts a lot easier to read).

Let’s start with a simple example, suppose you want to output the title of all the SharePoint lists within a Site; using PowerShell V2 you’d write something like this (both lines do the same thing and just demonstrate two different approaches – note that the output, though it looks the same, is not the same because the Select-Object cmdlet creates a custom object with a NoteProperty type):

(Get-SPWeb http://demo).Lists | select Title
(Get-SPWeb http://demo).Lists | ForEach-Object {$_.Title}

With PowerShell V3 we can do the same thing but we don’t need to use the pipeline. PowerShell V3 is smart enough to realize that if we have a collection of objects and want to see a property value we can simply wrap the collection in parenthesis and then just add the property that we want to output:

((Get-SPWeb http://demo).Lists).Title

You’re not limited to just the immediate child property either:

((Get-SPWeb http://demo).Lists).RootFolder.Url

The cool thing about this is that you’re not limited to outputting property values; you can call methods as well. This is probably not quite as useful but it’s still kind of cool. In this example suppose you have an event receiver that runs when items are updated and you need to trigger that event receiver for all items in a list (I have to do this a lot when testing event receivers or when deploying a new event receiver to a list with existing data):

(((Get-SPWeb http://demo).Lists["Documents"]).Items).Update()

Every Object Has a Count Property

Sometimes when you call a cmdlet you don’t know whether you’ll get back one item or multiple items. In PowerShell V2 if you got back a collection you could use the Count property determine how many came back and use this to perform some action (perhaps as a stop index for a for loop); however, if you only got back one object the Count property wasn’t available which could result in your script breaking as calling the Count property would just return $null. With PowerShell V3, however, every object now has a Count property which means that we can do something like the following examples which all return a valid count value:

(Get-SPSite -Limit All).Count
(Get-SPSite http://demo/*).Count
(Get-SPSite http://demo).Count

Again, it’s subtle but when you’re writing scripts that operate on an indeterminate number of objects you don’t want to have to think about the fact that the Count property could be $null. This simple enhancement means that I don’t have to waste time adding lame $null check could in my scripts (something I often forget about until it bites me in the a$$). Also, when I say every object has the Count property I really do mean every object – that includes the $null object; so in the examples above if any of the Get-SPSite calls return no sites (or $null) then I’ll get a value of zero (0) for the Count property.

Almost Every Object Has an Object Indexer

This enhancement goes hand-in-hand with the previous feature and I don’t think you can mention the one without mentioning the other. Just like with the Count property if you had a command such as “Get-SPSite http://demo/*” which could return back zero or more objects you can use the object indexer to access any of those objects. There is one exception though: you cannot index into $null so if the command returned back zero objects (or $null) then the attempt to index into it would fail so our only real benefit here is that single objects do support the indexer.

(Get-SPSite -Limit All)[0]
(Get-SPSite http://demo/*)[0]
(Get-SPSite http://demo)[0]
#This next one will fail:
(Get-SPSite http://doesnotexist)[0]

ForEach Statement Does Not Iterate Over $null

Consider the following example:

function Process-SPSite($sites) {
    foreach ($site in $sites) {
        Write-Host "Processing $site"
    }
}
Process-SPSite (Get-SPSite http://demo/*)

What would you expect to happen if the call to Get-SPSite didn’t actually return any SPSite objects? Most people would think that the Write-Host statement would never be reached; if you’re using PowerShell V2, you’d be wrong. This means that in PowerShell V2 you have to add a check for a $null object condition:

function Process-SPSite($sites) {
    foreach ($site in $sites) {
        if ($site -eq $null) { continue }
        Write-Host "Processing $site"
    }
}
Process-SPSite (Get-SPSite http://demo/*)

In PowerShell V3, however, they’ve fixed this issue and the initial example will work just as expected for the Write-Host statement will not be hit if the input is $null (to my great relief because I always forget about this and inevitably am reminded of it while trying to update a production system where I typically get greeted with a ton of red errors thanks to a $null object that should not be $null).

Workflow

The last new feature I wanted to highlight was the new workflow capabilities. That’s right, workflow! It’s now super easy to write a script which performs complex parallel or sequential operations and you can even turn a workflow into a job that can be run on a schedule. There’s a TON of stuff you can do with this new feature and I could easily write several posts about it but I’m not a PowerShell MVP, I’m a SharePoint MVP so I just want to show one simple example of how you can use this new feature to speed up your scripts a bit (for more about what you can do with it see TechNet: http://technet.microsoft.com/en-us/library/jj134242.aspx).

Often times when I deploy custom code to an environment I typically need to activate (or re-activate) a SharePoint Feature across all Sites or Site Collections; in a large environment this can take a considerable amount of time. What I’d like to be able to do is activate the Features in parallel as there is no dependency from one activation to the other so the only thing preventing me from doing it in parallel in the past was that I didn’t have an easy way to do it (the Enable-SPFeature cmdlet blocks until it’s complete). Thankfully, with PowerShell V3 there’s now a concept of parallel foreach statement. In the following example I’m using the –parallel parameter of the foreach keyword to indicate that I want the contents of the foreach block to run in parallel:

image

Note that I’m not using the function keyword and instead am using the workflow keyword to tell PowerShell that this is in fact a workflow. A key point is that that the commands that are executed within the workflow are actually workflow activities – NOT CMDLETS! This means that you cannot just slap any old cmdlet call in here – you’ll get a nice error stating that the cmdlet was not packaged as part of the workflow. To use a cmdlet that does not exist as an activity (such as all of the SharePoint cmdlets) we must wrap the calls to that cmdlet in an InlineScript activity (again, this isn’t a cmdlet, it’s a workflow activity). The code within the InlineScript activity actually runs outside of the workflow process, though it is possible to change that behavior (see “Running InlineScript in the Workflow Process” in the following TechNet article: http://technet.microsoft.com/en-us/library/jj574197.aspx).

Another interesting point is that you might notice that I did not pass in the SPSite object and instead passed in the URL of the SPSite. This is because whatever you pass into the workflow must be serializable and SPSite cannot be serialized. One final note, notice that in the call to Enable-SPFeature I’m prefacing the $feature and $url variables with the new $using scope indicator; this is new to PowerShell V3 and allows me to pass a variable from one process to another – I can use this to pass variables to workflow activities or to pass variables to jobs or remote sessions when using remoting.

Conclusion

There are a ton of new features with PowerShell V3 and I’ve only just scratched the surface with this article. You can find lots of great information on TechNet and the PowerShell TechNet Wiki. I’ll also be covering these new features and a few others that I like during my introductory PowerShell session at SPLive! so if you’re planning on going to that conference and would like to see more of this then definitely stop by my session. If you have any of your own favorite features please share them by leaving comment – I’m always interesting in learning what others have found to be useful.

-Gary

Leave a Reply

Your email address will not be published. Required fields are marked *

*