Powered by Zoomin Software. For more details please contactZoomin

Use Semaphore for SharePoint Online

Configure SIM settings

  • Last Updated: May 1, 2026
  • 6 minute read
    • Semaphore
    • Documentation

This sample PowerShell script automates the configuration of SIM (Semaphore Intelligent Metadata) field settings for a SharePoint list or content type via the Progress Data Cloud API. It is an alternative to manually configuring settings from the Library Settings or Site Content Types tabs in the Progress Data Cloud interface.

Script overview

The Configure-SimSettings.ps1 script applies SIM field configuration using a JSON settings file. It supports two modes:

  • ByList: Resolves a Site Library ID for a given site URL and list ID, then posts the SIM settings to the list endpoint.
  • ByContentType: Posts the SIM settings directly to a content type endpoint for a given site URL and content type ID.

The workflow is:

  1. Authenticates to the Progress Data Cloud using an API key.
  2. Validates and loads the JSON settings file.
  3. For ByList mode: resolves the Site Library ID via the PDC API.
  4. Posts the SIM field settings to the appropriate API endpoint.
  5. Outputs status messages for success or failure.

Prerequisites

Before running the script, ensure the following:

  • Windows PowerShell 5.1 or PowerShell 7+.
  • A valid Progress Data Cloud API key for an appropriately permissioned user. For information about API key management, see the API key management script in the Use Progress Data Cloud guide.
  • A JSON settings file containing the SIM field configuration. See Settings file format for details.
  • The site must already be deployed and configured in Progress Data Cloud.

Parameters

Shared parameters

Parameter Required Description
SettingsFile Yes Path to a JSON file containing the SIM field configuration payload.
CloudUrl Yes The base URI of the Progress Data Cloud API (for example, https://tenant.data.progress.cloud).
ApiKey Yes The API key used to authenticate with Progress Data Cloud.
SiteUrl Yes The SharePoint site URL (for example, https://tenant.sharepoint.com/sites/Finance).

ByList parameters

Parameter Required Description
ListId Yes The SharePoint list GUID whose Site Library ID will be resolved and targeted for SIM configuration.

ByContentType parameters

Parameter Required Description
ContentTypeId Yes The SharePoint content type ID (for example, 0x0101...) to configure.

Usage examples

Configure SIM settings for a list:

.\Configure-SimSettings.ps1 `
    -SettingsFile .\sim-settings.json `
    -CloudUrl 'https://tenant.data.progress.cloud' `
    -ApiKey '***' `
    -SiteUrl 'https://tenant.sharepoint.com/sites/Finance' `
    -ListId '7b9c1f9a-1234-5678-9abc-def012345678' `
    -Verbose

Configure SIM settings for a content type:

.\Configure-SimSettings.ps1 `
    -SettingsFile .\sim-settings.json `
    -CloudUrl 'https://tenant.data.progress.cloud' `
    -ApiKey '***' `
    -SiteUrl 'https://tenant.sharepoint.com/sites/Finance' `
    -ContentTypeId '0x0101AABBCC' `
    -Verbose

Preview actions without making changes (WhatIf):

.\Configure-SimSettings.ps1 `
    -SettingsFile .\sim-settings.json `
    -CloudUrl 'https://tenant.data.progress.cloud' `
    -ApiKey '***' `
    -SiteUrl 'https://tenant.sharepoint.com/sites/Finance' `
    -ContentTypeId '0x0101AABBCC' `
    -WhatIf

Important:

For enhanced security, consider storing your API key in a secure keystore rather than passing it as a plain text parameter. You can retrieve the key from your preferred secure storage solution (such as Azure Key Vault, HashiCorp Vault, or Windows Credential Manager).

Settings file format

Create a JSON file containing the SIM field configuration. For example:

{
    "articleType": 0,
    "bodyType": 0,
    "classificationMode": 1,
    "clusteringThreshold": null,
    "clusteringType": 0,
    "csServerId": "f35a8615-a8f2-47d2-a67a-5f0a80aaf250",
    "displayName": "Test1",
    "fieldId": "0c5f9765-3c37-4934-aca6-e2fc87c4c4d7",
    "fieldType": "Note",
    "inheritAdvancedOptions": false,
    "selectedRulebaseClasses": [
        "Vehicle"
    ],
    "threshold": null
}

PowerShell script

<#
.SYNOPSIS
Configures SIM (Semaphore Intelligent Metadata) field settings either by SharePoint list or by 
content type, using a settings JSON file and a cloud API.

.DESCRIPTION
This script applies SIM field configuration to a SharePoint field via the Progress Data Cloud API. 
It supports two mutually exclusive parameter sets:

- **ByList**: Resolves a Site Library ID (for a given SiteUrl and ListId) and POSTs SIM settings 
  to /api/sim/list/{siteLibraryId}/field.
- **ByContentType**: Uses the given ContentTypeId and SiteUrl and POSTs SIM settings to 
  /api/sim/contenttype/{contentTypeId}/field?siteUrl={siteUrl}.

.PARAMETER SettingsFile
Path to a JSON file containing the SIM field configuration payload.

.PARAMETER CloudUrl
The base URI of the cloud API (e.g., https://tenant.data.progress.cloud).

.PARAMETER ApiKey
The API key used to connect to Progress Data Cloud for an appropriately permissioned user.

.PARAMETER SiteUrl
The SharePoint site URL (e.g., https://tenant.sharepoint.com/sites/Finance).

.PARAMETER ListId
(ByList only) The SharePoint list GUID whose Site Library ID will be resolved.

.PARAMETER ContentTypeId
(ByContentType only) The SharePoint content type ID (e.g., 0x0101...).

.INPUTS
None. This script does not accept pipeline input.

.OUTPUTS
Information, Warning, and Verbose messages.

.NOTES
- Requires Windows PowerShell 5.1 or PowerShell 7+.
- REST calls use retry logic with exponential backoff.
- The JSON in SettingsFile is sent as-is with ContentType = 'application/json'.

.EXAMPLE
PS> .\Configure-SimSettings.ps1 -SettingsFile .\sim-settings.json -CloudUrl 'https://tenant.data.progress.cloud' -ApiKey '***' -SiteUrl 'https://tenant.sharepoint.com/sites/Finance' -ListId '7b9c1f9a-1234-5678-9abc-def012345678'

Configures the SIM field settings for the specified list.
#>

#Requires -Version 5.1
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ByList')]
param(
    [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByList')]
    [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByContentType')]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({ Test-Path $_ -PathType Leaf })]
    [string]$SettingsFile,

    [Parameter(Mandatory, Position = 1, ParameterSetName = 'ByList')]
    [Parameter(Mandatory, Position = 1, ParameterSetName = 'ByContentType')]
    [ValidateNotNullOrEmpty()]
    [uri]$CloudUrl,

    [Parameter(Mandatory, Position = 2, ParameterSetName = 'ByList')]
    [Parameter(Mandatory, Position = 2, ParameterSetName = 'ByContentType')]
    [ValidateNotNullOrEmpty()]
    [string]$ApiKey,

    [Parameter(Mandatory, Position = 3, ParameterSetName = 'ByList')]
    [Parameter(Mandatory, Position = 3, ParameterSetName = 'ByContentType')]
    [ValidateNotNullOrEmpty()]
    [uri]$SiteUrl,

    [Parameter(Mandatory, Position = 4, ParameterSetName = 'ByList')]
    [ValidateNotNullOrEmpty()]
    [string]$ListId,

    [Parameter(Mandatory, Position = 4, ParameterSetName = 'ByContentType')]
    [ValidateNotNullOrEmpty()]
    [string]$ContentTypeId
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

function Invoke-WithRetry {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [scriptblock]$ScriptBlock,
        [int]$MaxAttempts = 3,
        [int]$InitialDelaySeconds = 2
    )

    $attempt = 0
    $delay = $InitialDelaySeconds

    while ($attempt -lt $MaxAttempts) {
        try {
            return & $ScriptBlock
        }
        catch {
            $attempt++
            $statusCode = $null
            try { $statusCode = $_.Exception.Response.StatusCode.Value__ } catch { }

            Write-Verbose ("Attempt {0} failed{1}: {2}" -f $attempt, 
                ($(if ($statusCode) { " (HTTP $statusCode)" } else { "" })), $_.Exception.Message)

            if ($attempt -ge $MaxAttempts) {
                throw
            }

            Start-Sleep -Seconds $delay
            $delay = [math]::Min($delay * 2, 30)
        }
    }
}

function Get-CloudToken {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][uri]$BaseUrl,
        [Parameter(Mandatory)][string]$ApiKey
    )

    $uri = [uri]::new($BaseUrl, '/token')
    $body = @{
        grant_type = 'apikey'
        key        = $ApiKey
    }

    $requestParams = @{
        Method      = 'Post'
        ContentType = 'application/x-www-form-urlencoded'
        Uri         = $uri
        Body        = $body
        ErrorAction = 'Stop'
    }

    Write-Verbose "Requesting token from $($uri.AbsoluteUri)"
    $response = Invoke-WithRetry -ScriptBlock { Invoke-RestMethod @requestParams }
    if (-not $response.access_token) { throw "Token response missing 'access_token'." }
    return [string]$response.access_token
}

function New-AuthHeader {
    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$Token)
    return @{
        Authorization = "Bearer $Token"
        Accept        = 'application/json'
    }
}

function Get-SiteLibraryId {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][uri]$BaseUrl,
        [Parameter(Mandatory)][hashtable]$Headers,
        [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$SiteUrl,
        [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$ListId
    )

    $eSite = [System.Net.WebUtility]::UrlEncode($SiteUrl)
    $eList = [System.Net.WebUtility]::UrlEncode($ListId)
    $relative = "/api/sitelibrary?listId=$eList&siteUrl=$eSite"
    $uri = [uri]::new($BaseUrl, $relative)

    $requestParams = @{
        Method      = 'Get'
        Uri         = $uri
        Headers     = $Headers
        ErrorAction = 'Stop'
    }
    Write-Verbose "Resolving Site Library ID for listId=$ListId siteUrl=$SiteUrl"
    $resp = Invoke-WithRetry -ScriptBlock { Invoke-RestMethod @requestParams }
    if (-not $resp.id) { throw "Response missing 'id' for listId=$ListId." }
    return [string]$resp.id
}

# --- Load and validate settings JSON ---
$settingsJson = Get-Content -Path $SettingsFile -Raw
try {
    $null = $settingsJson | ConvertFrom-Json -Depth 10
}
catch {
    throw "Settings file '$SettingsFile' is not valid JSON: $($_.Exception.Message)"
}

# --- Resolve base endpoint from parameter set ---
switch ($PSCmdlet.ParameterSetName) {
    'ByList' { $baseEndpoint = '/api/sim/list' }
    'ByContentType' { $baseEndpoint = '/api/sim/contenttype' }
    default { throw "Invalid parameter set: $($PSCmdlet.ParameterSetName)" }
}

# --- Auth ---
try {
    $token = Get-CloudToken -BaseUrl $CloudUrl -ApiKey $ApiKey
    $header = New-AuthHeader -Token $token
}
catch {
    Write-Error "Authentication failed: $($_.Exception.Message)"
    exit 1
}

# --- Execute ---
if ($PSCmdlet.ParameterSetName -eq 'ByList') {
    try {
        $siteLibraryId = Get-SiteLibraryId -BaseUrl $CloudUrl -Headers $header `
            -SiteUrl $SiteUrl.AbsoluteUri -ListId $ListId

        $relative = "$baseEndpoint/$siteLibraryId/field"
        $uri = [uri]::new($CloudUrl, $relative)
        $req = @{
            Method      = 'Post'
            Uri         = $uri
            Headers     = $header
            ContentType = 'application/json'
            Body        = $settingsJson
            ErrorAction = 'Stop'
        }
        if ($PSCmdlet.ShouldProcess("SiteLibraryId=$siteLibraryId", 'Configure SIM settings')) {
            Write-Verbose "Configuring SIM settings for site library $siteLibraryId"
            Invoke-WithRetry -ScriptBlock { Invoke-RestMethod @req } | Out-Null
        }
        Write-Information "Configured SIM settings for SiteLibraryId=$siteLibraryId"
    }
    catch {
        Write-Warning "Failed for ListId=$ListId at site $($SiteUrl.AbsoluteUri): $($_.Exception.Message)"
    }
}
else {
    try {
        $ctId = [System.Net.WebUtility]::UrlEncode($ContentTypeId)
        $relative = "$baseEndpoint/$ctId/field?siteUrl=$($SiteUrl.AbsoluteUri)"
        $uri = [uri]::new($CloudUrl, $relative)
        $req = @{
            Method      = 'Post'
            Uri         = $uri
            Headers     = $header
            ContentType = 'application/json'
            Body        = $settingsJson
            ErrorAction = 'Stop'
        }
        if ($PSCmdlet.ShouldProcess("ContentTypeId=$ContentTypeId", 'Configure SIM settings')) {
            Write-Verbose "Configuring SIM settings for content type $ContentTypeId"
            Invoke-WithRetry -ScriptBlock { Invoke-RestMethod @req } | Out-Null
        }
        Write-Information "Configured SIM settings for ContentTypeId=$ContentTypeId"
    }
    catch {
        Write-Warning "Failed for ContentTypeId=$ContentTypeId at site $($SiteUrl.AbsoluteUri): $($_.Exception.Message)"
    }
}
TitleResults for “How to create a CRG?”Also Available inAlert