Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Functional Requirement
Admin wants to create Content Type, Site Columns and associate them with Custom List or Document Library at the site level to his O365 SharePoint Online tenant from any remote machine.
Environment Setup for remote machine
In order to enable SharePoint Online PowerShell Script execution from your remote machine. Click here for setup steps
Download
Solution Architecture
This tool is responsible for the creation of Content Type, Site Columns and associates them with Custom List or Document Library at the site level by using an array of Site Columns, Content Type etc. The tool is designed for PowerShell SharePoint Online Tool. This is using CSOM as client object model. The architecture of the tool is depicted as below.
A. Tenant Site
Admin has setup an Office 365 tenant account with Microsoft. The O365 E1, E2, E3 or above plan has been provided. The architecture is based on the O365 mentioned plan.
B. Location Site Collection
There will be separate site collection for every identified capability location.
C. Site
There will be separate sub site for every identified location site collection.
D. Site Column
Site Columns will be created at Site Collection level.
E. Content Type
Content Type will be created at Site Collection level. These Content Type would be referring to available site columns.
F. Document Library or Custom List
Content Type will be associated with site level Document Library or Custom List.
Z. Remote Provisioning Pattern Tool
Remote Provision pattern tool is responsible for the creation of sub site based on the defined array.
Interface Architecture of Provisioning Pattern
1. InstallProvisioning.ps1
This consists of the specific logic of PowerShell scripting relevant to Subsites creation.
#This file consist of function calls to generic functions which are used to deploy Site Provisioning to specified Site Collection
# .\InstallProvisioning.ps1 -Username "admin@XXX.sharepoint.com" -AdminUrl " https://XXX.sharepoint.com " -siteURL " https://XXX.sharepoint.com/sites/US " -groupName "US"
# Global Parameters Defined
param(
[string]$Username= "" ,
[string]$siteCollectionUrl= "" ,
[string]$siteURL = "" ,
[string[]]$arrSubSite = ( "HR" , "Finance" , "IT"),
[string]$groupName = "US" ,
[string[]]$arrsiteColumns = ( "FileSize125" , "FileType125" ),
[string[]]$arrcontentTypeName = ( "CTFinanancial" , "CTAccounts" ),
[string]$workFolder = (Get-Item (“.”)).FullName,
[string]$Logfile = "$workFolder\$(gc env:computername).log"
)
#Locate the path where Site Provisioning code files are stored
$workFolder = (Get-Item (“.”)).FullName
. "$workFolder\ProvisioningLibrary.ps1"
#These are the Function calls to Execute Generic Site Provisioning Functions
#This call is responsible for creating site column at site collection level
Add-SPOSiteColumns $Username $AdminPassword $siteCollectionUrl $arrsiteColumns
#This call is responsible for creating Content Type and adding site columns to it
Add-SPOContentType $Username $AdminPassword $siteCollectionUrl $arrsiteColumns $arrcontentTypeName
#This call is responsible for associating the Content Type with a List or Library
Add-SPOAddContentTypeToList $Username $AdminPassword $siteURL $arrcontentTypeName
2. ProvisioningLibrary.ps1
This consists of PowerShell scripting reusable logic for Provisioning pattern.
#This file consist of generic functions used to deploy Site Provisioning to specified Site Collection
#Locate the path where Site Provisioning code files are stored
$workFolder = (Get-Item (".")).FullName
. "$workFolder\CommonLibrary.ps1"
#This function used to create site columns to the specific site collection
function Add-SPOSiteColumns{
# Catch the parameters received through the function call
param(
[Parameter(Mandatory=$true,Position=1)]
[string]$Username,
[Parameter(Mandatory=$true,Position=2)]
[string]$AdminPassword,
[Parameter(Mandatory=$true,Position=3)]
[string]$Url,
[Parameter(Mandatory=$true,Position=4)]
[string[]]$arrsiteColumns
)
# Creating client context object
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$context.credentials = $SPOCredentials
$fields = $context.web.fields
$context.load($fields)
#Send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Loaded all the Site Columns from the site Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
#Loop through each entry and create the columnGroup
foreach ($column in $arrsitecolumns){
#check if column already exists
foreach($field in $fields){
if ($field.internalname -eq $column.name){
$columnExists = 1
}
else{
$columnExists = 0
}
}
#Executes if Site Column does not exist already
if ($columnExists -eq 0){
#create XML entry for a new field
$fieldAsXML = "<Field Type='Text'
DisplayName='$column'
Name='$column'
Group='$groupName'/>"
#See tips below for info about fieldOptions
$fieldOption = [Microsoft.SharePoint.Client.AddFieldOptions]::AddFieldInternalNameHint
$field = $fields.AddFieldAsXML($fieldAsXML, $true, $fieldOption)
$context.load($field)
#Send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Site Column : $column created Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
}
else{
LogProcess "WARNING: The Site Column : $column already exists." "yellow"
}
}
}
#This function used to create Content Type to the specific site collection
function Add-SPOContentType{
# Catch the parameters received through the function call
param(
[Parameter(Mandatory=$true,Position=1)]
[string]$Username,
[Parameter(Mandatory=$true,Position=2)]
$AdminPassword,
[Parameter(Mandatory=$true,Position=3)]
[string]$Url,
[Parameter(Mandatory=$true,Position=4)]
[string[]]$arrsiteColumns,
[Parameter(Mandatory=$true,Position=5)]
[string[]]$arrcontentTypeName
)
# Local Variables
$contentTypeGroup = "$groupName"
$parentContentTypeID = "0x0101"
# Creating client context object
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$context.credentials = $SPOCredentials
$fields = $context.web.fields
$contentTypes = $context.web.contenttypes
$context.load($fields)
$context.load($contentTypes)
# Send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Loaded all the Fields and Content Types from the site Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
# Loop through all content types to verify it doesn't exist
foreach ($contentType in $contentTypes){
for($i = 0; $i-le $arrcontentTypeName.Length; $i++){
if ($contentType.name -eq $arrcontentTypeName[$i]){
LogProcess "WARNING: The content type $($contentType.name) already exists." "Yellow"
$contentTypeExists = $true
}
else{
$contentTypeExists = $false
}
}
}
# Create content type if it doesn't exist based on specified Content Type ID
if($contentTypeExists -eq $false){
# load parent content type
$parentContentType = $contentTypes.GetByID($parentContentTypeID)
$context.load($parentContentType)
# Send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Loaded parent Content Type Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
# Create Content Type using ContentTypeCreationInformation object (ctci)
foreach ($contenttypename in $arrcontentTypeName){
$ctci = new-object Microsoft.SharePoint.Client.ContentTypeCreationInformation
$ctci.Name = $contenttypename
$ctci.ParentContentType = $parentContentType
#$ctci.Id = $ContentTypeID
$ctci.group = $contentTypeGroup
$ctci = $contentTypes.add($ctci)
$context.load($ctci)
# Send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Content Type : $contenttypename created Successfully " "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
# Get the new content type object
#$newContentType = $context.web.contenttypes.getbyid($ctci.Name)
# Loop through all the columns that needs to be added
foreach ($column in $arrsiteColumns){
$field = $fields.GetByInternalNameOrTitle($column)
#create FieldLinkCreationInformation object (flci)
$flci = new-object Microsoft.SharePoint.Client.FieldLinkCreationInformation
$flci.Field = $field
$addContentType = $ctci.FieldLinks.Add($flci)
LogProcess "Added Site Columns: $column to the array Successfully" "Green"
}
#$newContentType.Update($true)
$ctci.Update($true)
}
# send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Added Site Columns : $arrsiteColumns to Content Types : $arrcontentTypeName Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
}
}
#This function used to create sub site to the specific site collection
function Add-SPOSubsite{
# Catch the parameters received through the function call
param(
[Parameter(Mandatory=$true,Position=1)]
[string]$Username,
[Parameter(Mandatory=$true,Position=2)]
$AdminPassword,
[Parameter(Mandatory=$true,Position=3)]
[string]$Url,
[Parameter(Mandatory=$true,Position=4)]
[string]$SubSite
)
# Creating client context object
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$context.credentials = $SPOCredentials
$rootWeb = $Context.Web
$Context.Load($rootWeb)
$childWebs = $rootWeb.Webs
$Context.Load($childWebs)
try{
$Context.executeQuery()
LogProcess "Loaded all Subsites Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
#Create Subsite
$WCI = New-Object Microsoft.SharePoint.Client.WebCreationInformation
$WCI.WebTemplate = "BDR#0"
$WCI.Description = "Finance"
$WCI.Title = "Finance"
$WCI.Url = "Finance"
$WCI.Language = "1033"
foreach($subweb in $childwebs.Title){
if($subweb -eq "$SubSite"){
$columnExists = 1
LogProcess "WARNING: Subsite $SubSite already Exists" "Yellow"
}
else
{
$columnExists = 0
}
}
if ($columnExists -eq 0){
try{
$Sub = $Context.Web.Webs.Add($WCI)
$context.executeQuery()
LogProcess "Subsite $SubSite created Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
}
}
#This function used to associate Content Type to specific document library
function Add-SPOAddContentTypeToList {
# Catch the parameters received through the function call
param(
[Parameter(Mandatory=$true,Position=1)]
[string]$Username,
[Parameter(Mandatory=$true,Position=2)]
$AdminPassword,
[Parameter(Mandatory=$true,Position=3)]
[string]$Url,
[Parameter(Mandatory=$true,Position=4)]
[string[]]$arrcontentTypeName
)
# Local Variables
$listTitle = "Document Record"
$listDescription = "This is Testing Library"
$listTemplate = 101
# Creating client context object
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$context.credentials = $SPOCredentials
$web = $context.Web
#$web1 = $web.Webs
$site = $context.Site
$context.Load($web)
#$context.Load($web1)
$context.Load($site)
try
{
$context.ExecuteQuery()
LogProcess "Authenticated and Connected to SharePoint Online Tenant site $Url Successfully" "Green"
}
catch
{
LogProcess "Not able to authenticate to SharePoint Online $_.Exception.Message" "Red"
return
}
#Getting all the list information
$Lists = $web.Lists
$Context.Load($Lists)
$ContentTypes = $web.AvailableContentTypes
$Context.Load($ContentTypes)
try
{
$Context.ExecuteQuery()
LogProcess "Successfully retrieved all the List and Content Type information from the site" "Green"
}
catch
{
LogProcess "Error while getting the List and Content Type information from the site" "Red"
}
# send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Loaded all the Content Types and Lists from the site Successfully" "Green"
}
catch{
LogProcess "$($_.Exception.Message)" "Red"
}
#Loop through all Document library to verify it doesn't exist
foreach ($list in $Lists){
if ($list.Title -eq $listTitle){
LogProcess "WARNING: The list : $listTitle already exists." "Yellow"
$listExists = $true
}
else{
$listExists = $false
}
}
# create list if it doesn't exist
if($listExists -eq $false){
#create list using ListCreationInformation object (lci)
$lci = New-Object Microsoft.SharePoint.Client.ListCreationInformation
$lci.title = $listTitle
$lci.description = $listDescription
$lci.TemplateType = $listTemplate
$lci = $lists.add($lci)
$context.load($lci)
#send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Created List : $listTitle Successfully" "Green"
}
catch{
LogProcess "info: $($_.Exception.Message)" "Red"
}
# get the new list object
$newList = $context.Web.Lists.GetByTitle($lci.title)
# loop through all the Content Types that needs to be added
# create Content Type using ContentTypeCreationInformation object (ctci)
$ctci = new-object Microsoft.SharePoint.Client.ContentTypeCreationInformation
foreach($ct in $ContentTypes){
$CTNAME = $ct.Name
for($i = 0; $i-le $arrcontentTypeName.Length; $i++){
if($CTNAME -eq $arrcontentTypeName[$i]){
$ctci = $context.Web.AvailableContentTypes.GetById($ct.Id)
$newList.ContentTypesEnabled=$true
$addList = $newList.ContentTypes.AddExistingContentType($ctci)
$newList.Update()
}
}
}
# send the request containing all operations to the server
try{
$context.executeQuery()
LogProcess "Added ContentTypes : $arrcontentTypeName to List : $listTitle Successfully " "Green"
}
catch{
LogProcess "info: $($_.Exception.Message)" "Red"
}
}
}
3. CommonLibrary.ps1
This consists of PowerShell scripting reusable logic that can be used across the different projects.
# This file consist of Reusable Components amongst all the generic functions that are used to deploy Site Provisioning to specified Site Collection
# Paths to SDK. Please verify location on your computer
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
# Accept the Password of the admin site
$AdminPassword=Read-Host -Prompt "Password" -AsSecureString
$SPOCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $AdminPassword)
#This function Logs the entire activity of the script to console and write it to $Logfile
Function LogProcess
{
Param ([string]$logstring,
[string]$color
)
if($color -eq "Red")
{
$now = Get-Date -f "yyyy-MM-dd HH:mm:ss"
Add-content $Logfile -value "Error Details: $($now) $($logstring)"
}
else
{
$now = Get-Date -f "yyyy-MM-dd HH:mm:ss"
write-host $logstring -foregroundcolor $color
Add-content $Logfile -value "$($now) $($logstring)"
}
}