Enumerate Page Web Parts

Posted on Posted in SharePoint 2007, STSADM Commands

As part of the upgrade I needed to be able to fix some web parts that did not migrate correctly (either during the upgrade itself or as a result of moving a web). Before I started messing around with the web parts though I wanted to be able to see what I was dealing with. So I decided to create this simple command called gl-enumpagewebparts that would enable me to list out in XML all the web parts that are on a given page (open or closed).

One thing that I found that was very interesting was that the web part manager export method treats V2 and V3 web parts very differently. But perhaps the biggest annoyance I found was that I couldn’t get the web part zone from the web part instance itself – I had to use the web part manager (SPLimitedWebPartManager) to get it (took me longer than I’d like to admit to figure that out). This command is really quite simple – it takes in an url to a web part page, loads up an SPLimitedWebPartManager (for both the shared and personal views) and then loops through the WebParts collection outputting the results as XML.

I created three separate methods to get the XML details – one is verbose and essentially just uses the built in Export() method to get the XML (you can get these results via the -verbose parameter), another is a bit simpler and is constructed by hand (this is the default) and a third is actually for use by another command that I created which I’ll be documenting soon. The core code is shown below:

   1: /// <summary>
   2: /// Runs the specified command.
   3: /// </summary>
   4: /// <param name="command">The command.</param>
   5: /// <param name="keyValues">The key values.</param>
   6: /// <param name="output">The output.</param>
   7: /// <returns></returns>
   8: public override int Run(string command, StringDictionary keyValues, out string output)
   9: {
  10:  output = string.Empty;
  11:  
  12:  InitParameters(keyValues);
  13:  
  14:  string url = Params["url"].Value;
  15:  
  16:  XmlDocument xmlDoc = new XmlDocument();
  17:  xmlDoc.AppendChild(xmlDoc.CreateElement("WebParts"));
  18:  xmlDoc.DocumentElement.SetAttribute("page", url);
  19:  
  20:  using (SPSite site = new SPSite(url))
  21:  using (SPWeb web = site.OpenWeb()) // The url contains a filename so AllWebs[] will not work unless we want to try and parse which we don't
  22:  {
  23:   XmlElement shared = xmlDoc.CreateElement("Shared");
  24:   xmlDoc.DocumentElement.AppendChild(shared);
  25:  
  26:   SPLimitedWebPartManager webPartMngr = web.GetLimitedWebPartManager(url, PersonalizationScope.Shared);
  27:   
  28:   string tempXml = string.Empty;
  29:   foreach (WebPart wp in webPartMngr.WebParts)
  30:   {
  31:    if (Params["verbose"].UserTypedIn)
  32:     tempXml += GetWebPartDetails(wp, webPartMngr);
  33:    else
  34:     tempXml += GetWebPartDetailsSimple(wp, webPartMngr);
  35:   }
  36:   shared.InnerXml = tempXml;
  37:  
  38:   XmlElement user = xmlDoc.CreateElement("User");
  39:   xmlDoc.DocumentElement.AppendChild(user);
  40:   
  41:   webPartMngr = web.GetLimitedWebPartManager(url, PersonalizationScope.User);
  42:   tempXml = string.Empty;
  43:   foreach (WebPart wp in webPartMngr.WebParts)
  44:   {
  45:    if (Params["verbose"].UserTypedIn)
  46:     tempXml += GetWebPartDetails(wp, webPartMngr);
  47:    else
  48:     tempXml += GetWebPartDetailsSimple(wp, webPartMngr);
  49:   }
  50:   user.InnerXml = tempXml;
  51:  
  52:  }
  53:  
  54:  output += Utilities.GetFormattedXml(xmlDoc);
  55:  
  56:  return 1;
  57: }
  58:  
  59: #endregion
  60:  
  61: /// <summary>
  62: /// Gets the web part details.
  63: /// </summary>
  64: /// <param name="wp">The web part.</param>
  65: /// <param name="manager">The web part manager.</param>
  66: /// <returns></returns>
  67: internal static string GetWebPartDetails(WebPart wp, SPLimitedWebPartManager manager)
  68: {
  69:  StringBuilder sb = new StringBuilder();
  70:  
  71:  XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(sb));
  72:  xmlWriter.Formatting = Formatting.Indented;
  73:  manager.ExportWebPart(wp, xmlWriter);
  74:  xmlWriter.Flush();
  75:  
  76:  XmlDocument xmlDoc = new XmlDocument();
  77:  xmlDoc.LoadXml(sb.ToString());
  78:  
  79:  XmlElement elem = xmlDoc.DocumentElement;
  80:  if (xmlDoc.DocumentElement.Name == "webParts")
  81:  {
  82:   elem = (XmlElement)xmlDoc.DocumentElement.ChildNodes[0];
  83:   
  84:   // We've found a v3 web part but the export method does not export what the zone ID is so we
  85:   // have to manually add that in.  Unfortunately the Zone property is always null because we are
  86:   // using a SPLimitedWebPartManager so we have to use the helper method GetZoneID to set the zone ID.
  87:   XmlElement property = xmlDoc.CreateElement("property");
  88:   property.SetAttribute("name", "ZoneID");
  89:   property.SetAttribute("type", "string");
  90:   property.InnerText = manager.GetZoneID(wp);
  91:   elem.ChildNodes[1].ChildNodes[0].AppendChild(property);
  92:  }
  93:  
  94:  return elem.OuterXml.Replace(" xmlns=\"\"", ""); // Just some minor cleanup to deal with erroneous namespace tags added due to the zoneID being added manually.
  95: }

The syntax of the command I created can be seen below.

C:\>stsadm -help gl-enumpagewebparts

stsadm -o gl-enumpagewebparts

Lists all the web parts that have been added to the specified page.

Parameters:
        -url <web part page URL>
        [-verbose]

Here’s an example of how to list all the web parts on a given page and dump to a text file:

stsadm -o gl-enumpagewebparts -url "http://intranet/hr/pages/default.aspx" -verbose > webparts.xml

7 thoughts on “Enumerate Page Web Parts

  1. Hi gary,
    your posts are great,and helped us in almost all the issues we faced during migration.
    For a quite few days we are fighting with an issue on migrating mysites.When we migrate mysites the webparts on private page of sps2003 goes to MySide(old) page after migration.But our client want them to be on MyHome after migration.For this our approach is to export webparts that are on sps2003 private page and import the same on MyHome page after migration.
    We were able to import webparts on MyHome using objectmodel.
    But we could not export webparts on the private page of sps2003 using code.can you please help us in this regard.After trying for all these days i found you are the only hope.

    Thanks
    srikanth

  2. Hi gary,
    your posts are great,and helped us in almost all the issues we faced during migration.
    For a quite few days we are fighting with an issue on migrating mysites.When we migrate mysites the webparts on private page of sps2003 goes to MySide(old) page after migration.But our client want them to be on MyHome after migration.For this our approach is to export webparts that are on sps2003 private page and import the same on MyHome page after migration.
    We were able to import webparts on MyHome using objectmodel.
    But we could not export webparts on the private page of sps2003 using code.can you please help us in this regard.After trying for all these days i found you are the only hope.

    Thanks
    srikanth

  3. Srikanth – take a look at the gl-exportlistitem2 and gl-addlistitem commands – I’ve built in a lot of stuff to handle migrating web part pages. You may also have some luck with the exportlistitem and importlistitem commands which use Microsoft’s deployment API (you may run into issues with these because you are reparenting the pages).

  4. I’m trying to get a list of webparts on a moss2007 page via powershell –
    My script *mostly* works, but on some pages it throws multiple of these errors:
    “System.NullReferenceException: Object reference not set to an instance of an object.
    at ar.a()”
    when I call the getLimitedWebpartManager line
    It does display the info for some of the webparts on the page, but doesn’t for others.

    Any idea why I get that error? or how to resolve?
    I’m running powershell 1.0 at the server (ckbox removed from ‘run with restricted access’), logged in as the farm administrator

    I’m trying to find a way of finding every page where we have certain webparts in our farm.

    Thanks

    script below:
    $web=get-web http://server/siteurl;
    $pageurl=”default.aspx”;
    $page=$web.GetFile($pageurl);
    $webpartManager=$web.getLimitedWebPartManager($page.url,[System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
    Write-host “Error occurs before here”
    $webpartManager.webparts | select-object Title, ID

  5. I am working on a SharePoint 2007 to 2010 upgrade and am using your stsadm -o gl-enumpagewebparts command to get additional information that the preupgrade checker did not provide. For the “The following web part(s) are referenced by the content, but they are not installed on the web server” error, I took the GUID provided and ran a query to determine the page then I ran the enumpagewebparts command for the page. The page has 5 web parts and each comes back with “Cannot import this Web Part.” or “Cannot import this Web Part. ” message. I have confirmed that all webparts on the site do not Error (IE “?content=1”) and the page does not contain any closed webparts.

    Do you have any idea why all webparts are invalid?

    Thanks!

  6. Also, I noticed the GUID that the preupgrade checker provides is not part of the output xml from the command. Not sure if it is possible to cross reference the error GUID with the xml results.

    Thanks again.

Leave a Reply

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

*