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.

Sunday, December 21, 2008

Initial Release of My SharePoint PowerShell Cmdlets

Update 4/25/2009: I’ve removed the “-gl” suffix from all my cmdlets - any examples using the -gl in the cmdlet name should be updated.

If you’ve been following my blog you’ll remember that I recently pushed out a “beta” build of some SharePoint PowerShell Cmdlets for some initial feedback and reviews.  We’ll I’ve gone ahead and incorporated the feedback that I received and I am now officially releasing the first version of my cmdlets.  The number of cmdlets has not changed from the beta build – they’ve just been cleaned up and enhanced.  I will slowly start documenting each of the existing cmdlets (there are currently 11) and hopefully be adding new ones over time.

I’ve added links to the top of my blog for quick download of either the source code or the MOSS or WSS builds of the setup packages.  At present there are no differences between the MOSS and WSS builds with the exception of my STSADM extensions which are included in the package and are a required dependency.  I’ve also updated my main index page so that it now also includes the available PowerShell commands – just select what you would like to look at via the dropdown box:

image

To install the cmdlets download the MOSS or WSS installer from the links at the top of this page (or in the right-hand column).  Once downloaded run the installer from your MOSS server using your MOSS admin account.  You will see the following screens:

  1. The initial welcome screen:
    image
  2. The EULA screen – you must accept to continue (you can find a copy for future reference in the install directory):
    image
  3. The install location – by default the files will be put at “C:\Program Files\Gary Lapointe\PowerShell Commands for SharePoint\”:
    image
  4. Optionally install my custom STSADM extensions – the extensions are a required pre-requisite but I make their install conditional so that if you have already installed the extensions you can avoid having to re-install them.  This is particularly beneficial if you are installing the cmdlets on more than one machine in the farm – you only have to install the extensions in the farm once as they will be pushed out to all of the servers by SharePoint:
    image
  5. Confirm that you are ready to install:
    image
  6. The files are then installed:
    image

Once the installation has completed you will be presented with the contents of the ReadMe.rtf file (which can be found in the install directory).  I’ve included the contents of that file below for reference:

To automatically load the snapin every time you start PowerShell create a shortcut to PowerShell passing in the -psconsolefile parameter like so:

%SystemRoot%\system32\WindowsPowerShell\v1.0\Powershell.exe –psconsolefile "C:\Program Files\Gary Lapointe\PowerShell Commands for SharePoint\Console.psc1"

The contents of the Console.psc1 file can be seen below.

<?xml version="1.0" encoding="utf-8"?>
<PSConsoleFile ConsoleSchemaVersion="1.0">
  <PSVersion>1.0</PSVersion>
  <PSSnapIns>
    <PSSnapIn Name="Lapointe.SharePoint.PowerShell.Commands" />
  </PSSnapIns>
</PSConsoleFile>

Or run the following command or add the following command to your profile script:

    add-pssnapin -name "Lapointe.SharePoint.PowerShell.Commands"

To see the help file for any of the commands type the following (where -detailed and -full are optional):

    help <command name> [<-detailed | -full>]

For example, the following command will return the full help for the get-spsite command:

    help get-spsite -full

Here’s a quick demonstration showing some of the power of one of these cmdlets, the Get-SPSite cmdlet:

image

Looking at the example above you can see I was able to quickly get a list of all Site Collections using “$sites = get-spsite –url *”.  I then output the results to the display to see what got returned.  To get some different columns I then passed in the $sites variable to the Select-Object (select) cmdlet and had it return back the Url and Usage.Storage properties so that I can see the size of all the size collections in the farm.  I could take this further and do some filtering if necessary but I’ll leave that exercise to you.

Keep an eye on my blog for more online documentation about each of the cmdlets along with lots of useful examples (hopefully :)).

Friday, December 19, 2008

Custom Field Types and WSS 4.0’s XSLT-based Field Type

I just posted an article related to the List View Web Part and WSS 4.0’s XSLT-based List View Web Part – I had known about this change for quite some time but this other change was new to me.  It appears that there will now be a new XSLT-based field type.  The following article discusses the upgrade issues for custom field types: The CustomFieldType rule in Pre-Upgrade Checker in Windows SharePoint Services 3.0 Service Pack 2 can warn that customized field types will not be upgraded.  Here’s a snippet of the relevant information:

A field type that uses custom Collaborative Application Markup Language (CAML) in its RenderPattern element will not be upgraded as an XSLT-based field type. Fields based on this custom field type will be rendered without any custom formatting in the next release of Windows SharePoint Services.

As in my previous post about the LVWP there are two takeaways here – the first is that there will be a new XSLT-based field type in the next version and the second, and more important point, is that if you are creating custom field types and using custom CAML in the RenderPattern element you will have to reset that element to use XSLT after the upgrade completes.  Also, you might notice a bit of a trend with these two articles – it would appear that Microsoft is moving certain aspects of the product away from CAML – all I can say to that is, YIPPEE!!!

Custom List Views and WSS 4.0’s XSLT-based List View

Some of us have known about this for a while but we’ve been unable to talk about it until now – Microsoft released the following article two days ago: The CustomListView rule in Pre-Upgrade Checker can warn that customized list views that will not be upgraded.  Read this article closely because for those of you that hate the List View Web Part as much as I do you’ll be extremely pleased to hear about the future direction of it.  Here’s a snippet from that article:

The following will not be upgraded to the new XSLT-based list view:

  • A list view that uses custom Collaborative Application Markup Language (CAML)
  • A list view that is not associated with a feature
  • A list view that is associated with a custom feature

A list view that is not upgraded will still render properly in Windows SharePoint Services 4.0. However, it will not inherit any benefits of the new XSLT-based list view, such as SharePoint Designer customization support, conditional formatting, and improved developer experience with XSLT standard-based language support.

The new XSLT-based list view is the default view that will be used in the next version release of Windows SharePoint Services. It will replace the existing list view in Windows SharePoint Services 3.0.

So there’s a couple of significant things with this article – the first is that we can now officially say that the List View Web Part, as a CAML based web part, is dead in the next version and will be replaced with a much better XSLT-based List View Web Part.  The second is that you now have some valuable information to keep in mind when doing custom development – avoid creating custom list views if you plan to upgrade to the next version.  To clarify the bullets above – based on my understanding (which could be wrong or could change) if you’ve customized a view via the browser you’re safe – but if you’ve customized the CAML directly using a tool or the API (within a Feature for example) then you will have to manually upgrade those views.

Ensuring a Valid SPContext via Feature Activation

I’ve been meaning to blog about this for a while but just haven’t gotten around to it.  Have you ever needed to add a web part to a page during Feature activation?  Of course you can do this declaratively using CAML but I usually prefer to do this stuff via code.  The challenge is that occasionally you will need to activate the Feature outside the context of a web request – such as via STSADM – this becomes critical for certain web parts, such as earlier versions of the KPI List Web Part, which required a valid SPContext in order to be added to a page (this web part was fixed in the August 2008 Cumulative Update (or thereabouts) so that it no longer requires a valid SPContext object).

If you’re faced with adding a web part (or any other artifact) which requires a valid SPContext object outside of a web request than you can create your own context with the following three lines of code:

   1: HttpRequest httpRequest = new HttpRequest("", web.Url, "");
   2: HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new StringWriter()));
   3: SPControl.SetContextWeb(HttpContext.Current, web);
I actually can’t take the credit for this – I was talking with Dan Attis during the summer about an issue and he pointed out this simple little fix for me.  Using this I created a simple helper function that allows me to easily add a web part to a page within my Feature activation event.  The code is below – just pass in the SPWeb object, the URL to a page, and the path to the web part file.  I put this in a shared library which I use for all of my Features thus making it super easy to add a web part to a page:
public static void AddWebPart(SPWeb web, string page, string webPartXmlFile, string zone, int zoneId, bool deleteExistingIfFound)
{
    bool cleanupContext = false;
    try
    {
        if (HttpContext.Current == null)
        {
            cleanupContext = true;
            HttpRequest httpRequest = new HttpRequest("", web.Url, "");
            HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new StringWriter()));
            SPControl.SetContextWeb(HttpContext.Current, web);
        }

        using (SPLimitedWebPartManager manager = web.GetLimitedWebPartManager(page, PersonalizationScope.Shared))
        {
            string err;

            XmlTextReader reader = null;
            System.Web.UI.WebControls.WebParts.WebPart wp;
            try
            {
                string webPartXml = File.ReadAllText(webPartXmlFile);
                webPartXml = webPartXml.Replace("${siteCollection}", web.Site.Url);
                webPartXml = webPartXml.Replace("${site}", web.Url);
                webPartXml = webPartXml.Replace("${webTitle}", HttpUtility.HtmlEncode(web.Title));
                reader = new XmlTextReader(new StringReader(webPartXml));
                
                wp = manager.ImportWebPart(reader, out err);
                if (!string.IsNullOrEmpty(err))
                    throw new Exception(err);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
            }

            // Delete existing web part with same title so that we only have the latest version on the page
            foreach (System.Web.UI.WebControls.WebParts.WebPart wpTemp in manager.WebParts)
            {
                if (wpTemp.Title == wp.Title)
                {
                    if (deleteExistingIfFound)
                        manager.DeleteWebPart(wpTemp);
                    else
                    {
                        wpTemp.Dispose();
                        return;
                    }
                    break;
                }
                wpTemp.Dispose();
            }

            manager.AddWebPart(wp, zone, zoneId);
        }
    }
    finally
    {
        if (HttpContext.Current != null && cleanupContext)
        {
            HttpContext.Current = null;
        }
    }
}

gl-fixpagecontact Deprecated!!!

Woohoo! – I finally get to deprecate one of my commands – after creating and publishing 135 commands I discovered today that the August Cumulative Update fixes the issue that my gl-fixpagecontact command sought to address.  If you look back at the post for that command you can see that there was a bug with the product which resulted in a user not found exception being thrown when looking at the settings of a publishing page.  This happened in couple of different situations but the easiest way to trigger it was to simply delete the user that created the page (or that was assigned as the page contact or that last modified the page) from the site collection.  When you did this and then visited the settings page you would get an error similar to the following:

image

The error would vary slightly depending on whether or not the field was the “Contact”, “CreatedBy”, or “LastModifiedBy” field.  I decided to revisit this command due to a comment that was posted on the post related to it which asked if the command could be modified to handle the CreatedBy and LastModifiedBy fields (I was only handling the Contact field).  I did some digging and have not yet discovered a way to update these two fields for a document library (if anyone has a way to do this please let me know) so I decided to send an email out to Paul Andrew to see if the bug had already been addressed - I usually pay attention to what fixes went into each update but I guess I missed this because within just a few minutes I got a response from Paul stating that this was indeed fixed with the August update (http://support.microsoft.com/kb/956056 and http://support.microsoft.com/kb/956057).  So I decided to go ahead and update my development machine to confirm this and Merry Christmas it worked!  After the updates got installed the settings page loaded fine and the invalid fields were set to my system account – now I’m not sure what logic is used here to determine what user is used – I was logged in with my system account so I don’t know if it’s using the logged in user or the system account but regardless, the page loads and that’s the important part.

So I am now officially deprecating this command – I’ll keep it in with the package but I won’t be supporting it further now that I can finally tell people to just install the update!  Thank you Paul for your help and quick responses!!!

Sunday, December 7, 2008

I'll be Speaking at the SharePoint Best Practices Conference

Catch me at the SharePoint Best Practices Conference in San Diego, California.  The conference will be held February 2-4, 2009.  I'll be presenting two topics, both currently scheduled for the last day, Wednesday:

IA260, Using Content Types to Improve Discoverability

Content Types are one of the great new features included with SharePoint 2007 and they can be used to serve many different needs.  In this session we will discuss some best practices and lessons learned when trying to use Content Types to make information more discoverable to users with different navigational needs.  We will discuss some simple approaches to help determine which Content Types are needed and how to utilize those Content Types to address the specific goal of helping users find information more easily.  We will also discuss various page design, taxonomy, and search capabilities that can be utilized as well as the lessons learned from real-world implementations.

IW265, Sub-site or Site Collection ? Best Practice Approaches, Considerations, and Lessons Learned

One of the more difficult tasks planners face when designing a WSS or MOSS environment is whether to use sub-sites or site collections and in what combination.  This is a critical process to get right from the beginning as it could have extreme ramifications on the overall success of the implementation.  This session will cover the pros and cons of using site collections and the best practices that affect the decisions to use them.  We will look at the various ways in which a logical, hierarchical, taxonomy can be met using site collections and how to keep various assets synchronized between related site collections.  Also, because sometimes even the best laid plans can’t account for the unforeseen we will delve into the various approaches available to change the site collection architecture post implementation (how and why you might need to convert sub-sites to site collections and site collections to sub-sites).

This will be my first conference talk so I'm real excited (and admittedly a little nervous) so please stop by and give me your support!  If you're not currently registered you can do so from here: http://www.sharepointbestpractices.com/ - it's sure to be a great conference!

SharePoint Best Practices Conference