Testing

webTiger Logo Wide

Creating SharePoint Site Columns and Content Types Using PowerShell

SharePoint 2013 Logo

When developing new sites in SharePoint, using the web interface or SharePoint Designer is all well and good but it can become cumbersome when naming columns, getting their internal names, etc. A much better way is to use SharePoint’s rich PowerShell functionality.

Loading the SharePoint snap-in is as simple as:

Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinueCode language: PowerShell (powershell)

(This isn’t required if you are always going to run your script in the SharePoint Management Shell (as it is done for you), but it doesn’t hurt to include it in your scripts before any functional code because it allows the scripts to run in a normal PowerShell prompt!)

Before we can create any columns or content types, we need to connect to a site. If you want your columns/types to be globally visible/usable in your site collection then you’ll need to define them at the site collection level (the root site), but if you only want them available at a sub-site level you can connect at this level instead and they will be defined there.

Start-SPAssignment –Global
$ErrorActionPreference = 'Stop'
$web = Get-SPWeb $urlCode language: PowerShell (powershell)

So, what is happening here?

The first line, while not explicitly required, is handy to include as it promotes better memory management. Normally, variables associated with any commands are disposed of when their scope completes. In a loop construct this can mean that multiple variables are initialised and later disposed of. By starting a variable assignment session, variables can be maintained until they are no longer needed, and this can be explicitly controlled via named assignment stores or the global store can be used to persist variables for the lifetime of the script execution (and this is what the -Global script indicates.) This is particularly relevant when initialising many columns and then needing to assign them to content types further on in the script. The complementary Stop-SPAssignment -Global can be used to dispose of the variables the assignment store was managing!

The second line allows us to control the error handling behaviour for the script. Specifying ‘Stop’ indicates that the script will terminate on error. Elsewhere in the script we may want to update the error handling behaviour to suit our needs, as you’ll see further on!

The last line simply loads the site, ready for the columns and content types to be added.

Now, let’s look at creating site columns. This is a fairly straightforward, and the commands are explained using inline comments…

# Specify an explicit group name the site columns will be added to.
$myColGroup = "My Custom Columns"

# Check the column doesn't already exist. This isn't strictly required - you could use error handling instead - but is handy to stop errors if you are re-running a script you are developing/debugging.
$ErrorActionPreference = 'SilentlyContinue'
$givenName = $web.Fields.GetField("GivenName")

# Change the error handling behaviour back, and then create the site column if not already present.
$ErrorActionPreference = 'Stop'
if ($givenName -eq $null -or $givenName.Group -ne $myColGroup) {
    # Add the column to the site.
    $givenName = $web.Fields.GetField($web.Fields.Add(“GivenName", "Text", $true))

    # Update the column's group
    $givenName.Group = $myColGroup

    # Provide a description for the column.
    # (Unfortunately this doesn't update the description displayed to the user - it has to be done by editing the XML schema directly due to a long standing bug.)
    $givenName.Description = "The first name of a person."

    # Set some other column parameters...    
    $givenName.EnforceUniqueValues = $false
    $givenName.MaxLength = 50

    # Update the column and display a message in the console!
    $givenName.Update()
    Write-Host "Site column created! (" $worker.InternalName ")"
}Code language: PowerShell (powershell)

That’s it, we’ve just created a new site column!

Repeating the above process, we can create a set of new site columns that we’ll use with our content types (using different variables to hold the column references.)

Now, let’s look at creating a content type (once again comments are included inline)…

# Specify an explicit group name the content types will be added to.
$myTypeGroup = "My Custom Content Types"

# Retrieve objects for the base content types we'll be inheriting from.
$itemAsParent = $web.AvailableContentTypes["Item"]
$eventAsParent = $web.AvailableContentTypes["Event"]

# Check the content type doesn't already exist. This isn't strictly required - you could use error handling instead - but is handy to stop errors if you are re-running a script you are developing/debugging.
$userDetailsTypeName = "User Details"
$existingTypeCheck = $web.AvailableContentTypes[$userDetailsTypeName]

if ($existingTypeCheck -eq $null -or $existingTypeCheck.Group -ne $myTypeGroup) {
    # Create the new content type.
    $newType = New-Object Microsoft.SharePoint.SPContentType($itemAsParentType, $web.ContentTypes, $userDetailsTypeName)

    # Update the type's group name and then add it to the SharePoint site.
    $newType.Group = $myTypeGroup
    $web.ContentTypes.Add($newType)

    # Our content type inherits from Item but we don't want to use the Title field... Let's hide it...
    $newType.FieldLinks["Title"].Required = $false
    $newType.FieldLinks["Title"].Hidden = $true

    # Let's grab a field-link to our given-name field and add it to our content type. 
    # (This is where ensuring our variables don't get disposed of can be useful!)
    $columnLink = New-Object Microsoft.SharePoint.SPFieldLink($givenName)
    $newType.FieldLinks.Add($columnLink)

    # Let's add the other site columns we created. 
    # (Assumes additional columns of $lastName and $birthDate were defined.)
    $columnLink = New-Object Microsoft.SharePoint.SPFieldLink($lastName)
    $newType.FieldLinks.Add($columnLink)
    $columnLink = New-Object Microsoft.SharePoint.SPFieldLink($birthDate)
    $newType.FieldLinks.Add($columnLink)

    # Save the changes to the content type, and write a comment out to the console.
    $newType.Update()
    Write-Host "INFO: The content type '$userDetailsTypeName' was successfully created!"
}Code language: PowerShell (powershell)

That’s all there is to it. We’ve created some site columns, and content types, and added them to a site. Even better, we have more control over what the internal names of our columns are, and if they weren’t named exactly as specified (because an existing column with that name was present in a different group, for example) then the script will have outputted the actual names too.

All this makes developing solutions based on those site columns, content types, etc. much more straightforward as we don’t need to get the internal names of all the columns via the web interface!

If you’ve called Start-SPAssignment at the top of your script, remember to stop it again at the end…

Stop-SPAssignment –GlobalCode language: PowerShell (powershell)