As part of my upgrade I’ve discovered a need to be able to add items to various lists. I considered a couple of approaches including creating a command that would allow me to specify the field names and values that I wanted to add to the list. Eventually though I concluded that the best and most flexible approach was to use the deployment API to export list items and then import them. The nice part about this approach was that the code was very similar to what I did for exporting and importing of lists. Another benefit is that if you are importing list items into a list that does not have all the fields needed those fields will be automatically created without any extra coding.
I originally set out to just create the export and import commands and then decided to create a delete command so that I could clean up all my test entries. Once I had the export and import done creating a copy command was really simple as it just wraps up those commands. The code to work with the content deployment API is pretty straightforward. Stefan Goßner does a really good job at explaining how to use the API in his blog Deep Dive into SharePoint Content Deployment and Migration API so I won’t reiterate it here. The commands I created are detailed below.
This command works almost identically to the gl-exportlist command that I created earlier. The main difference is that it takes in an optional "id" parameter which can be a single list item ID or a comma separated list of list item IDs. The syntax of the command can be seen below:
C:\>stsadm -help gl-exportlistitem stsadm -o gl-exportlistitem Exports a list item or items. Parameters: -url <list view url> -filename <export file name> [-id <list item ID (separate multiple items with a comma)>] [-overwrite] [-includeusersecurity] [-haltonwarning] [-haltonfatalerror] [-nologfile] [-versions <1-4> 1 - Last major version for files and list items 2 - The current version, either the last major or the last minor 3 - Last major and last minor version for files and list items 4 - All versions for files and list items (default)] [-cabsize <integer from 1-1024 megabytes> (default: 25)] [-nofilecompression] [-quiet]
Here’s an example of how to export 3 items from the site directory list:
stsadm –o gl-exportlistitem -url "http://intranet/sitedirectory/siteslist/AllItems.aspx" -id "1,2,3" -filename "c:\SiteDirItems" -includeusersecurity -versions 4 -nofilecompression
Running the above will create a folder called "SiteDirItems" in the root c: drive. You’ll also find a log file there containing the same information that was dumped to the console. This same output can then be used by the gl-importlistitem command to copy the list items to another list in any site collection (note that the target could be on any web app in any farm). To export all items in a list simply omit the "id" parameter.
This command has almost exactly the same parameters as the built in "import" command. One additional parameter of note is the "-retargetlinks" parameter. If this parameter is specified then you must also specify the "-sourceurl" parameter which corresponds to a view of the source list. The "retargetlinks" parameter tells the code to find any links that point to items in the source list and make them point to the target list.
This becomes helpful in a move operation. Note that only items identified by the list items BackwardLinks collection will get modified (unfortunately I’m not 100% clear about when and how this collection is set so I don’t claim that using this will fix every link to your items, though I do have another command that will loop through every field of every item of every list of every site and adjust the field value by replacing one value with another). The syntax of the command can be seen below:
C:\>stsadm -help gl-importlistitem stsadm -o gl-importlistitem Imports a list item or items. Parameters: -url <list view url to import into> -filename <import file name> [-includeusersecurity] [-haltonwarning] [-haltonfatalerror] [-nologfile] [-updateversions <1-3> 1 - Add new versions to the current file (default) 2 - Overwrite the file and all its versions (delete then insert) 3 - Ignore the file if it exists on the destination] [-nofilecompression] [-quiet] [-retargetlinks (resets links pointing to the source to now point to the target)] [-sourceurl <url to a view of the original list> (use if retargetlinks)] [-retainobjectidentity]
Here’s an example of how to import the items into the SiteDirectory list that we exported above and re-target any links pointing to the original documents so that they now point to the new documents (note that just like the built in import operation if you specify nofilecompression for the export you must also specify it for the import):
stsadm –o gl-importlistitem -url "http://teamsites/sitedirectory/siteslist/allitems.aspx" -filename "c:\SiteDirItems" -includeusersecurity -updateversions 2 -nofilecompression -retargetlinks -sourceurl "http://intranet/sitedirectory/siteslist/AllItems.aspx"
As with the exportlistitem operation a log file will be generated which will include all the details that were dumped to the console.
Update 11/15/2007: Apparently there’s some sort of funky bug with the deployment API which is preventing the importing of list items from functioning 100% (see the comments below from David who discovered the issue). The problem is that if you import a list item that has dependencies in different folders either the dependencies or the dependent items will be placed in the wrong folder. There’s a way with code that you can set the TargetParentUrl for orphaned items which is supposed to correct this – unfortunately it appears that whatever URL is first set gets used for all remaining items. The interesting thing is that you shouldn’t need to set this property at all because all the list items are going to the same targe web and the WebUrl property of the SPImportSettings object is being set but if I don’t set anything then the items still end up in the wrong location. The unfortunate side affect of this is that in order to prevent things from appearing in what would seem random locations and thus making it difficult to find imported items I’ve had to force everything to go to the root folder. Fortunately it’s fairly easy to move things around after the import but it’s still what should be an unnecessary pain in the butt. If anyone has any information which can help me solve this problem please pass it along (I spent two days picking through disassembled code trying to identify where the failure was but was not able to find anything conclusive – I also spent quite a bit of time trying to provide a work around to fix it but ran into to many issues where I’d fix one thing and break another (it’s just too hard to predict every possible combination of possibilities that could occur)).
If you’ve got the ability to import and export list items then why not make it a one step operation to copy a list item or move a list item. Once I had the code for the import and export the copy was nothing more than a wrapper which would call into the appropriate methods. By adding an extra parameter to support deleting the source list item I now also had a move command. The syntax of the command is just the combination of the import and export minus that which I don’t need the user to set. The syntax of the command can be seen below:
C:\>stsadm -help gl-copylistitem Copies a list item or items to another list. Parameters: -sourceurl <list view url to copy> -targeturl <url of a web site to copy to> [-id <list item ID (separate multiple items with a comma)>] [-includeusersecurity] [-haltonwarning] [-haltonfatalerror] [-nologfile] [-versions <1-4> 1 - Last major version for files and list items 2 - The current version, either the last major or the last minor 3 - Last major and last minor version for files and list items 4 - All versions for files and list items (default)] [-updateversions <1-3> 1 - Add new versions to the current file (default) 2 - Overwrite the file and all its versions (delete then insert) 3 - Ignore the file if it exists on the destination] [-quiet] [-retargetlinks (resets links pointing to the source to now point to the target)] [-deletesource]
Here’s an example of how to perform the same operation that the above import and export commands were doing but with just one step while at the same time deleting the source list items:
stsadm –o gl-copylistitem -sourceurl "http://intranet/sitedirectory/siteslist/AllItems.aspx" -targeturl "http://teamsites/sitedirectory/siteslist/allitems.aspx" -id "1,2,3" -includeusersecurity -updateversions 2 -versions 4 -nofilecompression -retargetlinks -deletesource
If the source list items were deleted then the result of the export operation is saved to a temp folder, the path to which is displayed to the user upon completion. To delete all items in a list simply ommit the "id" parameter.
I created this command because I needed a quick way to clean up all my test items that I was creating while testing the gl-importlistitem command. So even though I didn’t need it for my upgrade project specifically it came in handy for me so I figure someone else may benefit from it as well. The command allows you to either delete all items or specific items by passing in an "id" parameter. The syntax of the command can be seen below:
C:\>stsadm -help gl-deletelistitem Deletes an item or items from a list. Parameters: -url <list view URL> [-id <list item ID (separate multiple items with a comma)>] [-deletefolders]
Here’s an example of how to delete items from a list:
stsadm –o gl-deletelistitem -url "http://intranet/sitedirectory/siteslist/AllItems.aspx" -id "1,2,3"
To delete all items from a list simply omit the "id" parameter.
Update 12/18/2007: I’ve added a deletefolders option to the gl-deletelistitem command. This parameter only takes affect when you don’t specify an ID because you could previously delete a folder by specifying the folder’s ID.