Friday, October 11, 2013

PowerShell script to create Content Types

Continuing with the same scenario/example described in my previous post PowerShell Script to create Site Columns, here is a powershell script which creates site content types in bulk by reading the input from a list or a .csv file.

The pre-req for this script is to create site columns that will be assigned to these content types. You can use existing ones too if they are already created. In case, you wish to create empty content types without adding any site columns, please leave the "Site Columns" column blank. You will see errors in the output window when you run the script but they can be safely ignored.

So lets dive in..

As mentioned earlier; the script can read input from either a list or a .csv file. My input looks something like this. This time I went with the data list approach in contract with the creation of site columns, coz I wanted to give a group of users the ability to define what content types they wish to use for their set of documents.
You can choose to change the properties/columns as per your requirement but do not forget to tweak the code appropriately
 (or)


 



 
 





 
Please note, I did not populate  the Document Template column in my list entries for this example, however if you wish to do so, the input must be in the form of http://servername/sitecollectionname/subweb/documentlibrary/documentname.fileextension

# Description
#          This script is used to create content types by reading data from a SharePoint Data List.
#          The data list must have the columns
#                                    Content Type Name                  Single line of text           Required
#                                    Group                                           Single line of text           Optional
#                                    Parent                                          Single line of text           Required
#                                    Description                                 Multiple lines of text     Optional
#                                    Read Only                                   Yes/No                              Optional
#                                    Update Child Content Types   Yes/No                             Optional
#                                    Division                                       Choice                               Required
#                                    Site Columns                              Multiple lines of text     Optional
#                                    Document Template                 Hyperlink or Picture      Optional

# To input data from a csv file(Optional)
# Get the CSV File location which contains the input values. Change value in "" to match appropriate location
$inputFile = "C:\/*Folder lcoation*/\ContentTypesToBeAdded.csv"
#Import values from the CSV
$ctToBeAdded = import-csv $inputFile
# To input Data from data list
# Get the web in which the input data list is located
$listWeb = Get-SPWeb "/*Url of web*/"
 
# Get the List which stores the input values. Change the value in "" to match appropriate list name
$list = $listWeb.Lists["Content types to be Created"]
# Get the list items
$listItems = $list.Items
# Create an array to store the field links to all site columns that will be added to the content type
$fieldLinksArray = @()
# for each list item in the data list, do the following
foreach($item in $listItems)
{
   # Get the SPSite object for the site collection the content types are created in 
    $ctToBeAddedSite = new-Object Microsoft.SharePoint.SPSite "/*Url of Site Collection*/"
    # If the content types are created at a site collection level - Get the root web
    $ctToBeAddedWeb= $ctToBeAddedSite.RootWeb
   
    # If the script is used for creating web content types, get the rootweb first and store in a seperate variable say "$ctToBeAddedRootWeb" and the use the Get-SPWeb cmdlet to get the url of subweb
    # The reason why you need another variable to store the root web is if your parent content type is a built in content type for eg: Document, it can only be accessed from the rootweb contenttypes collection folder 
    # $ctToBeAddedWeb = Get-SPWeb "/*Url of sub web*/"
    # Parent content type
    # Note: If you are adding the content types to a subweb, use
    # $parentContentType= $ctToBeAddedRootWeb.ContentTypes[$item[$list.Fields["Parent"]]]
    $parentContentType = $ctToBeAddedWeb.ContentTypes[$item[$list.Fields["Parent"]]]
    # Content Type collection the new content type will be added to
    $ctToBeAddedCollection = $ctToBeAddedWeb.ContentTypes
    # Name of content type to be added   
    $ctToBeAddedName = $item[$list.Fields["Content Type Name"]]
    # Names of site columns to be added seperated by ','
    $ctSiteColumns = $item[$list.Fields["Site Columns"]]

    # When adding site columns to a content type; reading the input from a string with values separated by comma, for some reason, PowerShell skips the last value (still researching on this error).
    # You will notice that the array will be built with all the values in it, but the last value is always skipped when the field links are added.
    # To avoid this, my code adds a "," at the end of the input string and treat the last value as a blank.
    # This step can be avoided by adding a "," at the end of the string in the input list
    # Check if the input string ends with a comma, if it doesn’t append a “,”  to the end of the string.
    if($ctSiteColumns.EndsWith(",") -eq $false)
    {
        # Append a comma at the end of the string
        $ctSiteColumnsFinalString = $ctSiteColumns + ","
    }
    else # Keep the input as is
    {
        $ctSiteColumnsFinalString = $ctSiteColumns
    }   

     # Store all site columns in an array by splitting values at "," 
    $ctSiteColumnsArray = $ctSiteColumnsFinalString.Split(",")
    # for each site column in the array; do the following   
    foreach($siteColumn in $ctSiteColumnsArray)
    {
        # Get the SPField object
        $ctSiteColumnToBeAdded = $ctToBeAddedWeb.Fields[$siteColumn]       
        # If it exists
        if($ctSiteColumnToBeAdded -ne $null)
        {
            # Create a field link to the site column
            $fieldLink = new-object Microsoft.SharePoint.SPFieldLink $ctSiteColumnToBeAdded
        
            # Add it to the field link array
            $fieldLinksArray += ,$fieldLink
        }
        else # Site column does not exist
        {
            write-host "The Site Column:" $siteColumn "to be added to content type:" $ctToBeAddedName "does not exist"
        }        
    }
 
    # Check if the content type exists   
    if($ctToBeAddedWeb.ContentTypes[$item[$list.Fields["Content Type Name"]]] -eq $null)
    {
       # Create a new content type
        $newContentType = new-object Microsoft.SharePoint.SPContentType($parentContentType,$ctToBeAddedCollection,$ctToBeAddedName)

        # Add the content type to the content type collection
        $ctToBeAddedCollection.Add($newContentType)    
        # Set the content type properties
        $newContentType.Group = $item[$list.Fields["Group"]]
        $newContentType.Description = $item[$list.Fields["Description"]]
        [boolean]$newContentType.ReadOnly = [System.Convert]::ToBoolean($item[$list.Fields["Read Only"]])
        #Setting this property is optional. I chose to store the documents in a separate library, create a hyperlink column called “Document Template” in my list/.csv file and then attach the link to the content type
        $newContentType.DocumentTemplate = $item[$list.Fields["Document Template"]]
      
       # Foreach field link in the array
       foreach($link in $fieldLinksArray)
      {
           # Add the column to the new content type
           $newContentType.FieldLinks.Add($link)
      }

      # Update the content type definition that is stored in the database and update all content types that inherit from this content type.
        $newContentType.Update([System.Convert]::ToBoolean($item[$list.Fields["Update Child Content Types"]]))
   }
    else # Content type already exists
    {
       write-host "Content Type:" $item[$list.Fields["Content Type Name"]] "already exists"
    }
}
# Dispose the web and site ** Important **
$ctToBeAddedWeb.Dispose()
$listWeb.Dispose()
$ctToBeAddedSite.Dispose()

Output:






 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



 
 
 
Sources:
1. Google.com

No comments:

Post a Comment