When working with list or libraries, it is often a requirement to have a column that can be set automatically, perhaps by a workflow, but which you do not want users to be able to manually change. When creating a content type, each site column can be set to Required, Optional or Hidden. This can be set at the content type level or at the library level.
If the site column is left as Optional and then the content type is added to the library, the column is correctly added to the library and can be used as required and set to Hidden through the content type within the library settings. This ensures it does not appear in forms so applies a degree of protection against users changing it manually.
If this content type is added to one or more lists or libraries and then the site column is set to hidden at the content type level then this setting will be inherited by all the lists or libraries using that content type.
However, if the site column is set to hidden at the content type level before the content type is added to the library then this is where a problem arises. The column is not visible from the list settings, nor in the content types in the list settings. It is not available in views nor in filters nor sorts. However, if you try to add the site column manually then you will find it is not available to be added – because it has actually been added already as part of the content type.
A logical thought at this point would be to go back to the content type level and change the site column to Optional or Required. Sadly changing this does not seem to be inherited by the list.
My response at this stage was to resort to PowerShell – because that can do anything right?
$web = Get-SPWeb
$list = $web.Lists["List Name"]
$col = $list.Fields["Column Name"]
This will show True – so our problem is that the column has been added as hidden. You may think this is what we wanted but in fact the problem is that the column is hidden at the list level rather than at the content type level.
The easy option seemed to be:
$col.Hidden = $false
Sadly this fails as it is not allowed.
Another thought was to try changing the content type within the list through PowerShell:
$ct = $list.ContentTypes["Content Type Name"]
$field = $ct.FieldLinks["Column Name"]
$field.Hidden = $false
This succeeds – but sadly makes no difference.
So what about deleting the offending column?
Nope – this fails too as you cannot delete a column which is hidden – but you cannot unhide it . . .
So we now have a column in our list that we cannot use as we want to and we cannot even delete using PowerShell – or can we?
After a bit of fiddling and some suggestions from Microsoft we finally found a way to get rid of the column:
$col.AllowDeletion = $true
$col.Sealed = $false
Phew! Note that even though the column will say Sealed is False, you must set it to false as above – no idea why so if you have suggestions please let me know.
Microsoft has managed to reproduce this and is deciding whether or not it is a bug – I will keep you informed.