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.

Tuesday, October 2, 2007

Set Web Part State

As part of my upgrade I needed to be able to delete some web parts (closed or open) and close and open some web parts. In many respects this command, gl-setwebpartstate, is basically the twin to the gl-movewebpart command which I recently posted about. In fact, I created that command as a template for this command - the only difference from a code standpoint is that instead of calling MoveWebPart I'm calling either DeleteWebPart, CloseWebPart, or OpenWebPart (based on a user provided parameter). Everything else is exactly the same so once I had the gl-movewebpart command done creating this command took me less than 5 minutes. Below is the bit of code that differs from the gl-movewebpart code (I won't show the rest as it's identical to the gl-movewebpart command):

   1: if (Params["delete"].UserTypedIn)
   2:  manager.DeleteWebPart(wp);
   3: else if (Params["close"].UserTypedIn)
   4:  manager.CloseWebPart(wp);
   5: else if (Params["open"].UserTypedIn)
   6:  manager.OpenWebPart(wp);
   7:  
   8: if (!Params["delete"].UserTypedIn)
   9:  manager.SaveChanges(wp);

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

C:\>stsadm -help gl-setwebpartstate

stsadm -o gl-setwebpartstate


Opens, Closes, Adds, or Deletes a web part on a page.

Parameters:
        -url <web part page URL>
        {-id <web part ID> |
         -title <web part title>}
        {-delete |
         -open |
         -close |
         -add}
        {[-assembly <assembly name>]
         [-typename <type name>] |
         [-webpartfile <web part file if adding>]}
        [-zone <zone ID>]
        [-zoneindex <zone index>]
        {[-properties <comma separated list of key value pairs: "Prop1=Val1,Prop2=Val2">] |
         [-propertiesfile <path to a file with xml property settings (<Properties><Property Name="Name1">Value1</Property><Property Name="Name2">Value2</Property></Properties>)>]}
        [-publish]

Here’s an example of how to close a web part on a given page:

stsadm -o gl-setwebpartstate -url "http://intranet/hr/pages/default.aspx" -title "Grouped Listings" -close -publish

Update 12/10/2007: I've updated this command to now support the adding of web parts to a page. In doing this I also added the ability to set the zone and zone ID of a web part (thus encapsulating the gl-movewebpart command - I needed this in order to know where to add the part to so I figured I'd just allow the user to provide the same information for any other changes). I also added the ability to set properties of the web part. This is done using a comma separated list of key value pairs for simple data or an XML file with any encoded data. Note that only primitive data types are supported so if you try to set a property that requires a complex data type it will error out. Also - if you only wish to set the properties of an existing web part then simply pass in a command that matches the current state of the web part (so if the web part is open already then use the "-open" parameter and then pass in any desired properties).

Here's an example of how to add a web part to a page using simple properties:

stsadm -o gl-setwebpartstate -url "http://intranet/testweb1/default.aspx" -title "Table of Contents" -add -assembly "Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" -typename "Microsoft.SharePoint.Publishing.WebControls.TableOfContentsWebPart" -zone "Left" -zoneindex 0 -properties "ShowPages=false,LevelsToShow=3" -publish

Here's an example of how to add a web part to a page using an XML file containing properties:

stsadm -o gl-setwebpartstate -url "http://teamsites/pages/default.aspx" -title "I need to..." -add -assembly "Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" -typename "Microsoft.SharePoint.Portal.WebControls.TasksAndToolsWebPart" -zone "MiddleRightZone" -zoneindex 0 -propertiesfile "c:\webpartprops.xml" -publish

The webpartprops.xml file will look like this:

<Properties> <Property Name="TasksAndToolsWebUrl">/SiteDirectory</Property> <Property Name="FilterFieldValue">Top Tasks</Property> <Property Name="FilterCategory">TasksAndTools</Property> <Property Name="TasksAndToolsListName">Sites</Property> <Property Name="Xsl">&lt;xsl:stylesheet xmlns:x=&quot;http://www.w3.org/2001/XMLSchema&quot; version=&quot;1.0&quot; exclude-result-prefixes=&quot;xsl ddwrt slwrt msxsl&quot; xmlns:ddwrt=&quot;http://schemas.microsoft.com/WebParts/v2/DataView/runtime&quot; xmlns:slwrt=&quot;http://schemas.microsoft.com/WebParts/v3/SummaryLink/runtime&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot; xmlns:tnt=&quot;urn:schemas-microsoft-com:sharepoint:TasksAndToolsWebPart&quot; &gt; &lt;xsl:param name=&quot;tasksAndtools_IsRTL&quot; /&gt; &lt;xsl:param name=&quot;tasksAndTools_Width&quot; /&gt; &lt;xsl:template match=&quot;/&quot;&gt; &lt;xsl:call-template name=&quot;MainTemplate&quot;/&gt; &lt;/xsl:template&gt; &lt;xsl:template name=&quot;MainTemplate&quot; xmlns:ddwrt=&quot;http://schemas.microsoft.com/WebParts/v2/DataView/runtime&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot;&gt; &lt;xsl:variable name=&quot;Rows&quot; select=&quot;/dsQueryResponse/NewDataSet/Row&quot;/&gt; &lt;xsl:variable name=&quot;RowCount&quot; select=&quot;count($Rows)&quot;/&gt; &lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse; margin:0px;&quot;&gt; &lt;tr style=&quot;margin-top:3px;margin-bottom:1px;height:28px;border:0px;&quot;&gt; &lt;td style=&quot;padding-left:4px; white-space:nowrap ;&quot;&gt; &lt;xsl:if test=&quot;string-length($tasksAndTools_Width) != 0&quot;&gt; &lt;select id=&quot;TasksAndToolsDDID&quot; class=&quot;ms-selwidth&quot; style=&quot;width:{$tasksAndTools_Width}&quot; size=&quot;1&quot; title=&quot;Choose a task that you need to perform&quot; &gt; &lt;option selected=&quot;true&quot; value=&quot;0&quot;&gt;Choose task&lt;/option&gt; &lt;xsl:call-template name=&quot;MainTemplate.body&quot;&gt; &lt;xsl:with-param name=&quot;Rows&quot; select=&quot;$Rows&quot;/&gt; &lt;/xsl:call-template&gt; &lt;/select&gt; &lt;/xsl:if&gt; &lt;xsl:if test=&quot;string-length($tasksAndTools_Width) = 0&quot;&gt; &lt;select id=&quot;TasksAndToolsDDID&quot; class=&quot;ms-selwidth&quot; size=&quot;1&quot; title=&quot;Choose a task that you need to perform&quot;&gt; &lt;option selected=&quot;true&quot; value=&quot;0&quot;&gt;Choose task&lt;/option&gt; &lt;xsl:call-template name=&quot;MainTemplate.body&quot;&gt; &lt;xsl:with-param name=&quot;Rows&quot; select=&quot;$Rows&quot;/&gt; &lt;/xsl:call-template&gt; &lt;/select&gt; &lt;/xsl:if&gt; &lt;/td&gt; &lt;xsl:if test=&quot;$tasksAndtools_IsRTL = true()&quot;&gt; &lt;td style=&quot;padding-right:5px; padding-left: 14px;white-space:nowrap ;&quot;&gt; &lt;a id=&quot;TasksAndToolsGo&quot; accesskey=&quot;G&quot; title=&quot;Go&quot; href=&quot;javascript:TATWP_jumpMenu()&quot;&gt; &lt;img title=&quot;Go&quot; alt=&quot;Go&quot; border=&quot;0&quot; src=&quot;/_layouts/images/icongo01RTL.gif&quot; style=&quot;border-width:0px;&quot; onmouseover=&quot;this.src='/_layouts/images/icongo02RTL.gif'&quot; onmouseout=&quot;this.src='/_layouts/images/icongo01RTL.gif'&quot;/&gt; &lt;/a&gt; &lt;/td&gt; &lt;/xsl:if&gt; &lt;xsl:if test=&quot;$tasksAndtools_IsRTL = false()&quot;&gt; &lt;td style=&quot;padding-right:14px; padding-left: 5px;white-space:nowrap ;&quot;&gt; &lt;a id=&quot;TasksAndToolsGo&quot; accesskey=&quot;G&quot; title=&quot;Go&quot; href=&quot;javascript:TATWP_jumpMenu()&quot;&gt; &lt;img title=&quot;Go&quot; alt=&quot;Go&quot; border=&quot;0&quot; src=&quot;/_layouts/images/icongo01.gif&quot; style=&quot;border-width:0px;&quot; onmouseover=&quot;this.src='/_layouts/images/icongo02.gif'&quot; onmouseout=&quot;this.src='/_layouts/images/icongo01.gif'&quot; /&gt; &lt;/a&gt; &lt;/td&gt; &lt;/xsl:if&gt; &lt;/tr&gt; &lt;/table&gt; &lt;/xsl:template&gt; &lt;xsl:template name=&quot;MainTemplate.body&quot; xmlns:ddwrt=&quot;http://schemas.microsoft.com/WebParts/v2/DataView/runtime&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:msxsl=&quot;urn:schemas-microsoft-com:xslt&quot;&gt; &lt;xsl:param name=&quot;Rows&quot;/&gt; &lt;xsl:for-each select=&quot;$Rows&quot;&gt; &lt;xsl:variable name=&quot;GroupStyle&quot; select=&quot;'auto'&quot;/&gt; &lt;option style=&quot;display:{$GroupStyle}&quot; value=&quot;{ddwrt:EnsureAllowedProtocol(substring-before(@URL, ', '))}&quot; &gt; &lt;xsl:value-of select=&quot;@Title&quot;/&gt; &lt;/option&gt; &lt;/xsl:for-each&gt; &lt;/xsl:template&gt; &lt;/xsl:stylesheet&gt;</Property> </Properties>

Update 7/8/2008: I've added a new parameter, -webpartfile, which can be used to effectively import an exported web part file.  Just use it in conjunction with the -add option (do not use the -assembly or -typename parameters).  I also adjusted the code so that if it fails to add the web part using the object model it will revert to the web service - this is to account for some web parts (like the KPI web part) that require a valid SPContext object.

28 comments:

supergahar said...

Hi Gary, what a nice command that you created. But i wondering how bout if i want to remove error web part, which its title is nothing?
i tried to put -title "" but it said wrong command.

thanks in advance.

Patrick said...

How can I output the XML definition of a webpart I've created on a site?

Gary Lapointe said...

Patrick - use the enumpagewebparts command - it will output the xml of all web parts on a given page.

Patrick said...

Thanks Gary. Not sure if I am doing this right though. I need to add a list webpart to every subsite on a WSS v3 web app (about 1800 subsites). I am trying the following-

stsadm.exe -o setwebpartstate -url http://wsstest/wpTest -open -title "Site Owners" -assembly "Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" -typename "Microsoft.SharePoint.WebPartPages.ListViewWebPart" - zone "Right" -zoneindex 0

But keep getting a "Value does not fall within the expected range" error.

I got the assmebly and typename from the the enumpagewebparts dump. The name of the list is also "Site Owners". I've tried both -add and -open

Thanks for your help on this, your stsadm extension is great help!

Gary Lapointe said...

Patrick - you need to use the add parameter and you have to set a couple of properties for the ListViewWebPart - specifically "ListName" and possibly "ListViewXml" (which will be the more difficult one to set if you have to change any of the xml values).

Patrick said...

Got it working, thanks for the help. My disconnect not using the GUID for the list, I was trying to use the display name.

Gary Lapointe said...

Supergahar - sorry for not getting back to you sooner - you can use the ID of the web part (parameter is "-id"). If you don't know the ID you can get it by using the enumpagewebparts command.

supergahar said...

Thanks Gary. =)

David Tappan said...

Another great command, Gary. BTW, what specifically counts as a "primitive data type" versus "complex data type" in this case? Does that include strings, including XML strings inside XML properties?

Gary Lapointe said...

David - I'm basically just referring to things like strings, int, bool, etc. If the XML property takes a string then it will work fine - if it expects an XmlDocument then it won't work.

David Tappan said...

Thanks Gary. Can you tell me, would an element like this work (this is from the .webpart file--and I took off the leading [greater than] sign on the property element so it would let me post this).

property name="Configuration" type="string"><?xml version="1.0" encoding="utf-8"?><DatasourceConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><DatasourceID>contenttype</DatasourceID><GroupBy>01a9ea29-5a5b-49c4-899f-129aa0cd0b8a</GroupBy><ItemMenu>FileLeafRef_Url</ItemMenu><SortBy>{00000000-0000-0000-0000-000000000000}</SortBy><SortOrder>asc</SortOrder><PageSize>0</PageSize><MaximumItems>0</MaximumItems><CustomProperties><CustomProperty><Value>0x0101004679C7EC42F9464CA8EDA551B54EE8ED</Value><Id>contenttype</Id></CustomProperty><CustomProperty><Value>false</Value><Id>includedescending</Id></CustomProperty><CustomProperty><Value>1</Value><Id>scope</Id></CustomProperty><CustomProperty><Value>-1</Value><Id>listservertemplate</Id></CustomProperty><CustomProperty><Value>false</Value><Id>debug</Id></CustomProperty></CustomProperties><Filters /><FieldReferences><FieldReference><LinkFieldId>FileLeafRef_Url</LinkFieldId><Id>8553196d-ec8d-4564-9861-3dbe931050c8</Id></FieldReference><FieldReference><LinkFieldId>{00000000-0000-0000-0000-000000000000}</LinkFieldId><Id>01a9ea29-5a5b-49c4-899f-129aa0cd0b8a</Id></FieldReference><FieldReference><LinkFieldId>{00000000-0000-0000-0000-000000000000}</LinkFieldId><Id>2eab48ae-74f5-4005-8d23-aadb95e4e1e5</Id></FieldReference></FieldReferences></DatasourceConfiguration> /property>

-David

Gary Lapointe said...

David - this should work - you can always give it a try :)

Merlin said...

Hi Gary,

really great command...again :-)

I'm trying to add a webpart from a list (ex. Documents library) and I got some difficulties.

Can you give a complete example for this ?

thx

Merlin

Gary Lapointe said...

Merlin - you just need to specify the class type information for the ListViewWebPart and set the appropriate properties (an easy way to get the information is to set up a web part using the browser and then export the web part - you can then get the assembly and type information as well as any properties). Note that to target the web part to the appropriate list you need the GUID of the list which makes this approach near useless for this type of web part in a scripted fashion.

Paul said...

Would it be possible to extend this so that the -close option works with the ErrorWebPart. At the moment it results in a message:

An ErrorWebPart cannot be saved during browse.

The -delete option works ok, but I'd rather just close it as you can do interactively from the web part maintenance page.

Gary Lapointe said...

Unfortunately this is a limitation of the API and not my code.

Pablo said...

Hy Gary, thanks for your contribution. I am trying to delete web parts located "out of the web part zone", but I can´t do it. The extension ... is supporting this?

I have tried to enumerate them, but they didn´t appeared.

Gary Lapointe said...

Pablo - I've not tested the command with web parts out of zone. My gut tells me that if you use the ID then it will work but if you can't even see the web part when enumerating then there's a pretty good chance it won't work.

Anonymous said...

Hi Gary. Thanks for the great work.

For the -url parameter, can you set it to a site collection, rather than an individual page. I need to delete a webpart from a number of sites within a site collection found on the root default.aspx of each site. I'm consistently getting "Value does not fall within the expected rage." when not specifying a page.

Gary Lapointe said...

It has to be a page. I'd recommend using powershell to loop through all of your sites that you want to update and then call this command.

glen said...

comma separated list of key value pairs: "Prop1=Val1,Prop2=Val2">

I got an error when webpart paremeter value contains '='.
For example:
"Prop1='prop=!',Prop2='Val2'"

IMHO, should be fixed by changing parsing.

Gary Lapointe said...

Thanks for the feedback - I have a fix for that which will go out today.

Anonymous said...

From John T.
Good Day Gary,
We have been using your custom commands for quite some time with great success.
Recently I have had the need to work with some third party custom web parts on a page (move, open, close, add, etc.)
I have attempted to work with these web parts both using your custom stsadm commands and from SharePoint Obj Model code I have written as well.
In every case (except for deleting a web part from a page, which works fine) when I attempt to run a command I get errors and the web part either does not respond (does not get added, etc.) or the web part display title get corrupted.
Please see example below:
Note: I exported the .webpart file and copied it into the same folder "UpgradePropertiesStage2ReleaseScript" that the addpart.bat file is in.

C:\UpgradePropertiesStage2ReleaseScript>stsadm -o gl-setwebpartstate -url "http:
//popspsintweb4/agreements/10398/Pages/default.aspx" -title "Property Map" -add
-zone "RightColumnZone" -zoneindex 0 -webpartfile "PropertyMapWebPart.webpart" -
publish

Object reference not set to an instance of an object.

After that the command window crashes

PS: I am hoping you are still replying to these comments as I am under a looming deadline and I am not at all sure what is the cause or what the fix is for this
Thanks


C:\UpgradePropertiesStage2ReleaseScript>pause
Press any key to continue . . .

Gary Lapointe said...

There could be any number of issues but what I suspect is that the web part requires a valid HttpContext - this is pretty common with some web parts (especially custom ones as people tend not to think about manipulating them via the console). Unfortunately I just haven't had time to update this code to add a context but it's not hard to do. I'd know more if there was a stack trace.

Anonymous said...

Thanks for the quick reply.
I think I am on the right track now.
I ran the same command after developing a "propertiesfile" file and exporting a "webpartfile" file and the web part added successfully:

stsadm -o gl-setwebpartstate -url "http://popspsintweb4/agreements/10398/Pages/default.aspx" -title "Property Map" -add -webpartfile "PropertyMapWebPart.webpart" -zone "RightColumnZone" -zoneindex 0 -propertiesfile "C:\UpgradePropertiesStage2ReleaseScript\webpartprops.xml" -publish

properties file:


http://popgisapp01.pop.portptld.com/ArcGIS/rest/services
http://popgisweb01.pop.portptld.com/Bookmarks
45.586173064456233
-122.66029357910158
11
http://popgisweb01.pop.portptld.com
http://localhost/sendFeedback
10398
Value cannot be null.Parameter name: input

So, I think I will be OK shortly.
The challenge here is that there are 800 plus site collections so I need to develop custom C# code to traverse all the sites and dynamically write these properties to the web part (the lease number changes for each site), then add the web part.

!!!Stupid Question: Can I write C# Code that runs your "gl-setwebpartstate" command from within the code?
if so I can save a lot of time...
Thanks again for the reply

Anonymous said...

Update and thanks from John T.
No need to reply just sending this update as a "Thanks" for your quick reply...

Your response steered me in the right direction, and as I needed to work with some custom web parts contained in over 800 site collections I had to get my console app (c#) to correctly add a custom GIS web part to each page.
I accomplished this by dynamically writing all the required custom properties into a dictionary object and then saving those properties along with adding the web part via invoking the MOSS web service methods.
This provided the http context required to set the properties at run time for each Lease Site.
So the script is now ready and I made my deadline.
Now I can apply this same approach to working with the custom (consultant name removed) web parts (address info and agreement info) to address the documented issue with the page layout being incorrect for some sites.
Note: This needs to be fixed in many existing Lease sites and in some newly provisioned Lease sites as well as the Site Provisioning web part randomly swaps the web part positions from time to time...
Of course having your source code available made this task much more doable.
Thanks

Gary Lapointe said...

"Can I write C# Code that runs your "gl-setwebpartstate" command from within the code?": Yes, you can reference my assembly and write code that consumes it.

Daniel said...

Hi Gary,

thanks for the tools, it's great.

Can I set ChromeState to "minimized" using -properties?

I'm trying the following: stsadm -o gl-setwebpartstate -url "http://server/default.aspx" -title "Test" -open -properties
"ChromeState=Minimized"

This error:
"Error setting property value ChromeState to Minimized"

How can I set this property?

Thanks,