diff --git a/scripts/spo-add-fields-to-contenttypes/README.md b/scripts/spo-add-fields-to-contenttypes/README.md
index 71daec97a..3906452f2 100644
--- a/scripts/spo-add-fields-to-contenttypes/README.md
+++ b/scripts/spo-add-fields-to-contenttypes/README.md
@@ -94,100 +94,159 @@ finally {
# [CLI for Microsoft 365](#tab/cli-m365-ps)
```powershell
+# .\Add-FieldsToContentTypes.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/CLIForM365" -ContentTypes "My Review CT","Global User Review CT" -WhatIf
+[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
+param (
+ [Parameter(Mandatory = $true, HelpMessage = "Absolute URL of the site where the fields and content types exist.")]
+ [ValidatePattern('^https://')]
+ [string]$SiteUrl,
+
+ [Parameter(Mandatory = $true, HelpMessage = "Content type names to which the fields should be added.")]
+ [ValidateNotNullOrEmpty()]
+ [string[]]$ContentTypes,
+
+ [Parameter(HelpMessage = "Optional override for the field definitions.")]
+ [ValidateNotNull()]
+ [System.Collections.Hashtable[]]$FieldDefinitions
+)
+
+begin {
+ Write-Verbose "Ensuring CLI for Microsoft 365 session."
+ m365 login --ensure
+
+ if (-not $FieldDefinitions) {
+ $FieldDefinitions = @(
+ @{ FieldName = 'admin_review'; FieldId = '3eccccb1-9789-40e9-bee8-0e27a2b0ea9f'; FieldXml = "" },
+ @{ FieldName = 'admin_reviewdate'; FieldId = 'bee79067-c92c-4d9c-b80c-63a75a468b16'; FieldXml = "" }
+ )
+ }
-function CreateField {
- param ([string] $FieldName, [string] $FieldXML)
+ $Script:Results = [System.Collections.Generic.List[pscustomobject]]::new()
- try {
- # Check if the field exists and create
- $field = m365 spo field get --webUrl $siteUrl --title $FieldName | ConvertFrom-Json
+ function Ensure-SiteField {
+ param (
+ [Parameter(Mandatory = $true)] [string]$WebUrl,
+ [Parameter(Mandatory = $true)] [System.Collections.Hashtable]$Definition
+ )
- if ($null -eq $field) {
- # Add new field based on XML
- m365 spo field add --webUrl $siteUrl --xml $FieldXML
- Write-Host "Successfully created field '$FieldName'" -ForegroundColor Green
+ $fieldLookup = m365 spo field list --webUrl $WebUrl --output json | ConvertFrom-Json
+ $existingField = $fieldLookup | Where-Object { $_.Title -eq $Definition.FieldName -or $_.InternalName -eq $Definition.FieldName -or $_.Id -eq $Definition.FieldId }
+
+ if ($existingField) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'Field'
+ Target = $Definition.FieldName
+ Status = 'Skipped'
+ Message = 'Field already exists'
+ })
+ return $existingField
}
- else {
- Write-Host "Field '$FieldName' already exists. Skipping creation" -f Green
+
+ if (-not $PSCmdlet.ShouldProcess($Definition.FieldName, 'Create site column')) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'Field'
+ Target = $Definition.FieldName
+ Status = 'WhatIf'
+ Message = 'Field creation skipped'
+ })
+ return $null
}
- }
- catch {
- Write-Error "Error in CreateField - $_"
- throw
- }
-}
-function CreateAndAddFieldsToCTs {
- param ([string[]] $ContentTypes)
+ $createOutput = m365 spo field add --webUrl $WebUrl --xml $Definition.FieldXml --output json 2>&1
+ if ($LASTEXITCODE -ne 0) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'Field'
+ Target = $Definition.FieldName
+ Status = 'Failed'
+ Message = $createOutput
+ })
+ return $null
+ }
- try {
- #region Create SharePoint Site Columns
- $fieldsToCreate = @(
- @{
- FieldName = "admin_review"
- FieldID = "3eccccb1-9789-40e9-bee8-0e27a2b0ea9f"
- FieldXML = ""
- },
- @{
- FieldName = "admin_reviewdate"
- FieldID = "bee79067-c92c-4d9c-b80c-63a75a468b16"
- FieldXML = ""
- }
+ $createdField = $createOutput | ConvertFrom-Json
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'Field'
+ Target = $Definition.FieldName
+ Status = 'Created'
+ Message = 'Field created successfully'
+ })
+ return $createdField
+ }
+
+ function Add-FieldToContentType {
+ param (
+ [Parameter(Mandatory = $true)] [string]$WebUrl,
+ [Parameter(Mandatory = $true)] [string]$ContentTypeName,
+ [Parameter(Mandatory = $true)] [System.Collections.Hashtable]$Definition
)
- foreach ($fieldToCreate in $fieldsToCreate) {
- Write-Host "Creating the field - $($fieldToCreate.FieldName)" -ForegroundColor Yellow
- CreateField -FieldName $($fieldToCreate.FieldName) -FieldXML $($fieldToCreate.FieldXML)
+ $contentTypeJson = m365 spo contenttype get --webUrl $WebUrl --name $ContentTypeName --output json 2>&1
+ if ($LASTEXITCODE -ne 0) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'ContentType'
+ Target = $ContentTypeName
+ Status = 'Failed'
+ Message = $contentTypeJson
+ })
+ return
}
- Write-Host `n `n
- #endregion
- #region Add Site Columns to Content Types
- foreach ($contentType in $ContentTypes) {
- $contentTypeObj = m365 spo contenttype get --webUrl $siteUrl --name $contentType | ConvertFrom-Json
- if ($contentTypeObj.StringId) {
- foreach ($fieldToCreate in $fieldsToCreate) {
- Write-Host "Adding field - $($fieldToCreate.FieldName) to CT $contentType" -ForegroundColor Yellow
-
- m365 spo contenttype field set --webUrl $siteUrl --contentTypeId $contentTypeObj.StringId --id $fieldToCreate.FieldID
- Write-Host "Successfully added fields to CT $contentType" -ForegroundColor Green
- Write-Host `n
- }
- }
- else {
- Write-Host "Content Type not found: $contentType" -ForegroundColor Green
- Write-Host `n
- }
+ $contentType = $contentTypeJson | ConvertFrom-Json
+ if (-not $contentType.StringId) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'ContentType'
+ Target = $ContentTypeName
+ Status = 'Failed'
+ Message = 'Content type not found'
+ })
+ return
+ }
+ if (-not $PSCmdlet.ShouldProcess($ContentTypeName, "Add field $($Definition.FieldName)")) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'ContentType'
+ Target = $ContentTypeName
+ Status = 'WhatIf'
+ Message = "Skipped adding field $($Definition.FieldName)"
+ })
+ return
}
- #endregion
- }
- catch {
- Write-Error "Error in CreateAndAddFieldsToCTs - $_"
+
+ $setOutput = m365 spo contenttype field set --webUrl $WebUrl --contentTypeId $contentType.StringId --id $Definition.FieldId --output json 2>&1
+ if ($LASTEXITCODE -ne 0) {
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'ContentType'
+ Target = $ContentTypeName
+ Status = 'Failed'
+ Message = $setOutput
+ })
+ return
+ }
+
+ $Script:Results.Add([pscustomobject]@{
+ Action = 'ContentType'
+ Target = $ContentTypeName
+ Status = 'Updated'
+ Message = "Field $($Definition.FieldName) bound successfully"
+ })
}
}
-try {
- # SharePoint Online Site Url
- $siteUrl = "https://contoso.sharepoint.com/sites/CLIForM365"
-
- # Get Credentials to connect
- $m365Status = m365 status
- if ($m365Status -match "Logged Out") {
- m365 login
+process {
+ foreach ($definition in $FieldDefinitions) {
+ Ensure-SiteField -WebUrl $SiteUrl -Definition $definition
}
- # Create and add fields to SharePoint content types
- CreateAndAddFieldsToCTs -ContentTypes @("My Review CT", "Global User Review CT")
-}
-catch {
- Write-Error "Something wrong: " $_
-}
-finally {
- # Disconnect SharePoint online connection
- m365 logout
+ foreach ($contentType in $ContentTypes) {
+ foreach ($definition in $FieldDefinitions) {
+ Add-FieldToContentType -WebUrl $SiteUrl -ContentTypeName $contentType -Definition $definition
+ }
+ }
}
+end {
+ $Script:Results | Sort-Object Action, Target | Format-Table -AutoSize
+}
```
[!INCLUDE [More about CLI for Microsoft 365](../../docfx/includes/MORE-CLIM365.md)]
@@ -200,6 +259,7 @@ finally {
| ------------------- |
| Ahamed Fazil Buhari |
| [Ganesh Sanap](https://ganeshsanapblogs.wordpress.com/about) |
+| Adam Wójcik |
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
diff --git a/scripts/spo-add-fields-to-contenttypes/assets/sample.json b/scripts/spo-add-fields-to-contenttypes/assets/sample.json
index 2c6932147..a1af84906 100644
--- a/scripts/spo-add-fields-to-contenttypes/assets/sample.json
+++ b/scripts/spo-add-fields-to-contenttypes/assets/sample.json
@@ -9,8 +9,10 @@
"Script to create site columns and add them to content types"
],
"creationDateTime": "2023-09-06",
- "updateDateTime": "2023-10-24",
- "products": ["SharePoint"],
+ "updateDateTime": "2025-11-12",
+ "products": [
+ "SharePoint"
+ ],
"metadata": [
{
"key": "PNP-POWERSHELL",
@@ -18,19 +20,18 @@
},
{
"key": "CLI-FOR-MICROSOFT365",
- "value": "7.0.0"
+ "value": "11.0.0"
}
],
- "categories": ["Provision"],
+ "categories": [
+ "Provision"
+ ],
"tags": [
"Connect-PnPOnline",
"Get-PnPField",
"Add-PnPFieldFromXml",
"Add-PnPFieldToContentType",
- "m365 status",
- "m365 login",
- "m365 logout",
- "m365 spo field get",
+ "m365 spo field list",
"m365 spo field add",
"m365 spo contenttype get",
"m365 spo contenttype field set"
@@ -55,6 +56,11 @@
"company": "",
"pictureUrl": "https://github.com/ahamedfazil.png",
"name": "Ahamed Fazil Buhari"
+ },
+ {
+ "gitHubAccount": "Adam-it",
+ "pictureUrl": "https://avatars.githubusercontent.com/u/58668583?v=4",
+ "name": "Adam Wójcik"
}
],
"references": [