One of the things I've been working on recently was trying to get the site directory into a useable state post upgrade. The main issue I needed to address was that the upgrade resulted in duplicate columns for Division and Region. The duplication was because the default Site Directory template creates columns with a display name of Division (and Region) but the internal name is DivisionMulti (and RegionMulti). So when the upgrade moved the source list over it saw the names as being differing so instead of replace or merging the columns it just added new ones (this time with the internal name matching the display name).
So, I needed a simple command to allow me to delete the DivisionMulti and RegionMulti columns. The problem that I encountered was that the indexer for the Fields collection of the list (SPFieldCollection.Item[string]) wants the display name - this threw me off at first and I can see where it could potentially mess someone up really bad if they're not paying close attention to how they are using it. By passing in only the display name you will be returned back the first item that it comes across with no indication whatsoever that there may actually be another item in the list with the same name.
So my challenge here was to make the command as "safe" as I could. I accomplished this by allowing the user to pass in either the display name or the internal name (with the internal name being the safest approach). If the display name was passed in then I do a check to make sure that there's only one field with that display name - if I find more than one then I return back the matches along with the internal name so that the command can be attempted again. I thought about only allowing the internal name but figured that 90% of the time the display name will work just fine and it's easier to discover.
The other thing I needed to do was to provide some details as to why a field may not be able to be deleted. To do this I had to look into the CanBeDeleted property of the SPField object. From this I was able to see that if the field is derived from a base type or if it's sealed or if it's marked as not allowing deletion via the AllowDeletion property then it cannot be deleted. The AllowDeletion property is an easy enough one to get around so I provided a "-force" switch to allow the user to override this setting and delete the field regardless. I chose not to do anything (not allow the deletion) if it's derived from a base type or if it's sealed only because of numerous ramifications that result from attempting to delete these fields.
There's only two core parts to this code - the first involves a utility method that I created to retrieve the SPField object and the other is a small amount of code to determine whether or not the field can be deleted or not:
The syntax of the command I created, gl-deletelistfield, can be seen below:
C:\>stsadm -help gl-deletelistfield stsadm -o gl-deletelistfield Deletes a field (column) from a list. Parameters: -url <list view URL> [-fielddisplayname <field display name>] / [-fieldinternalname <field internal name>] [-force (used to force deletion if AllowDeletion property is false)]
Here’s an example of how to delete the DivisionMulti column from the site directory:
stsadm –o gl-deletelistfield -url "http://intranet/sitedirectory/lists/sites/allitems.aspx" -fieldinternalname DivisionMulti