MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Wednesday, November 26, 2008

My New PowerShell Cmdlets for SharePoint 2007: Feedback Requested!

Okay all you PowerShell superstars out there that have been using my STSADM commands - I need your help!  I've decided to teach myself PowerShell and see if I can't leverage some of my STSADM experiences/code to expose some SharePoint functionality and I need some people who really know this PowerShell stuff to please take a look at what I've got so far and let me know if I'm way off base or not.

My initial stab includes 11 new cmdlets (10 Get and 1 Add):

  • Get-SPContentType-gl
  • Get-SPContentTypeUsages-gl
  • Get-SPFarm-gl
  • Get-SPField-gl
  • Add-SPList-gl
  • Get-SPList-gl
  • Get-SPSite-gl
  • Get-SPUserProfileManager-gl
  • Get-SPPrivacyPolicyManager-gl
  • Get-SPWeb-gl
  • Get-SPWebApplication-gl

The first thing you'll hopefully notice is that I've adopted a naming convention similar to what I did with my STSADM commands - I looked everywhere for best practices on naming custom cmdlets to avoid name clashes but couldn't find a darn thing (documentation for creating cmdlets is absolutely horrible!).  What does everyone think of this approach?  I tried to at least keep the verb-product+noun nomenclature so that you'd still be able to easily see all the get commands without having to also search -gl (so rather than gl-get-spfarm which would break a search for get-*).

I don't currently have help completed for all the commands, only a couple of them as I wanted to wait until I got some feedback before investing too much time in this.  I guess I should first ask if people see the need for this?  Am I wasting my time?  I want to learn PowerShell either way so I'll create stuff regardless but I'd like to be able to share with the community for some mutual benefits.

So, if you know PowerShell and have time to play with what I've created thus far (take a look at the code too and see if I'm doing anything stupid) please feel free to download the source and installer:

  • Setup Package: Lapointe.SharePoint.PowerShell.Commands.Setup.msi
    • I'm currently NOT including my custom STSADM extensions in the install package so you'll need to download and install those separately as they are a required dependency (see the links at the top of the page) - I may change this later so that the installer installs the STSADM extensions but I just don't want to have to worry about that at the moment (for now I'm just pushing out builds for both products at the same time).
  • Source Code: SPPoSH.zip
    • Crack it open, be honest, be brutal, but please, be constructive :)

Keep in mind that this is just an initial "Alpha" release to see what people think - if you've followed my blog any or used my STSADM extensions then you can probably guess that there'll be a lot more of these cmdlets in the future so I want to make sure that I'm taking the right approach.  Also - if you have any ideas for cmdlets that would be really helpful please let me know and I'll see if I can put something together as part of my learning exercise.

Thanks again to anyone who is able to help me out with this!

Update 12/14/2008: Based on feedback received (thanks Harley!) I've made one significant modification - the Get-SPSite-gl and Get-SPWeb-gl cmdlets now return back wrapper objects: SPSiteInfo and SPWebInfo, respectively.  These wrapper objects allow the caller to not have to worry about calling Dispose() which is particularly useful when the results have been filtered.  The Info objects contain virtually all the properties that their equivalent SP classes contain.  You can still get to the actual object by calling the SPBase property or the GetSPObject().

10 comments:

Jamie McAllister said...

Nice one Gary! You do seem to have the magic ability of posting tools on your blog right about when I need them! I'm in the process of expanding my Powershell knowledge too. Good work! :)

Harley Green said...

Hey Gary

This rocks.

Here's my intial feedback - I haven't gone through it in detail yet. I would try to stay away from returning anything that returns an IDisposable object. Powershell doesn't yet have an elegant way of dealing with this in an automated fashion, and many PS users don't call Dispose on their objects as they should. In addition, if you pass IDisposables down the pipeline, and they get filtered out, then you lose the reference to them.

I'd suggest creating a set of *Info classes ( similar in concept to System.IO.FileInfo / System.IO.DirectoryInfo ) and build the cmdlets to use these. This way you can dispose of the sharepoint objects safely within the cmdlet, and return the info object that has most of the properties populated, or can lazy load if it makes more sense.

I'll add to this once I've had a chance to play with them further.

Harley

WebApe said...

I am not sure if you can do this using Powershell, but we are a K-12 school district and we often change the AD account name for students, and unfortunately while we can update the AD account name in Sharepoint 2007 we can't seem to find a way to sync the Sharepont Display Name. A script to resync would be great and reusable for any educational customers you may have in the future.
Keep up the good work...

Gary Lapointe said...

Harley - for the IDisposable issue do you not think that would diminish the value of the Get operations if you can't work with the real SP* objects? Or do you think people would be okay with somthing that exposes most of the more common properties and then has like an SPBase property (similar to the PSBase that the PSObject has) to get to the real object? Wondering how that would work when trying to pass in a collection of these to one of the other commands (so how could I make the cmdlet flexible enough to handle a collection of these or a collection of the real objects (I suppose ParameterSets?))? On the name clashes - would typing in the full snapin name be better/worse than just using the -gl? Maybe I should just remove the -gl entirely and let people add or remove the snapin as needed? I do sort of like having the -gl in the name - it's a nice reminder of where it came from (which of course might be a bad thing if people hate them - but I guess then can always uninstall:) )

Thanks for your feedback! It's most appreciated!

Gary Lapointe said...

WebApe - you should be able to use "stsadm -o sync" to synchronize the display name - unfortunately this will only sync users who have in some way contributed to a site. I'd have to do some digging to find a way around this but it stands to reason that it should be possible.

WebApe said...

I have since found a codeplex stsadm extenstion that addresses this problem but it is not practical as we have some 30,000 students that may have a change in their name when then move to a different level or school in our district: 124-AStudent to 134-AStudent where the number is a school's site number. Anyway, this may help if you want to have a look.
http://www.codeplex.com/hwamigrateuser

Gary Lapointe said...

Yeah - that code has a lot of issues (probably the most obvious is the memory leak - he's looping through all site collections from the web app and for each one creating a new site collection (not sure why) but not disposing of the original site collection.

Harley Green said...

Gary

I don't think the IDisposable issue will diminish the value. On the contrary, I think that that is where the value is. After all, it is fairly trivial to instantiate an SPSite or SPWeb object using a script, or function:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Sharepoint")
$spSite = new-object Microsoft.Sharepoint.SPSite($siteUrl)
$spWeb = $spSite.AllWebs["SomeWeb"]

The problem is the lack of support for disposable objects - if I pass all the webs down the pipeline, and filter them looking for webs that meet a certain criteria, then all the objects that are filtered out are lost, and won't be disposed unless I call the garbage collector explicitly.

If your intention is to provide a fairly comprehensive set of cmdlets to simplify scripting against the Sharepoint Object Model, and if they all accept / use the *Info objects that you provide, then I think you're pretty much all the way there. I would agree with having something like a GetSPObject() method - so as not to limit the user if they need to do stuff that you don't have covered with a cmdlet. And yeah - parameter sets would be the way to go - I think you'd want to use them so that you could pass either *Info objects, Microsoft.Sharepoint.* objects, or strings (urls) directly to a cmdlet, for maximum flexibility.

One other comment - in your GetWeb/ GetSite cmdlets - you retrieve the entire list before writing them to the pipeline - I'd suggest that a more PS-centric approach would be to write them as you retrieve them.

I've been toying with doing something very similar, so if you're inclined to open source these, I'd be interested in contributing.

Later
Harley

Gary Lapointe said...

I've uploaded an updated version of the powershell cmdlets - feel free to download and let me know what you think of the changes - thanks!

decatec said...

Excellent addins to STSADM, I hope the MS team will consider them for Sharepoint 2009