Hi ,
i am trying to add 3 entitlements to few roles which is already exist in sailpoint. via VS code but it is adding only 1 entitlement.
i tried with “;” separator and also tried with one one entitlement in each row but still it is updating only latest onr
Hi Rahul,
Could you provide a bit more detail on how you are updating the roles in ISC?
It is not fully clear from the description whether this is being done through:
Also, when you mention using a “;” separator, where exactly are you applying it?
For example:
In the role definition JSON?
In the access profile / entitlement mapping?
In a CSV or bulk input file?
If possible, please share a sanitized example (without confidential data) of the structure you are using. That will help identify why only the latest entitlement is being added and whether the current update is overwriting previous values or if there is a formatting issue.
For example in VS code through CSV file i am update the existing roles.
I am adding groups to roles, below is the example of csv data i am uploading in entitlements column
Sourcename1|mem of|group name1;sourcename2|mem of|groupname2
msingh900
(Manish Singh)
May 28, 2026, 5:32am
4
@RahulMekala
Can you please explain the steps that you are taking and through which API or VS Code configuration.
schattopadhy
(SHANTANU CHATTOPADHYAY)
May 28, 2026, 6:01am
5
@RahulMekala you can create a small script which can be useful here .
Hi @RahulMekala ,
You can use the SailPoint provided Bulk Role Importer Ruby script for this purpose. Please refer to the link below for more details:
IdentityNow Bulk Access Profile and Role Importer - Compass
schattopadhy
(SHANTANU CHATTOPADHYAY)
May 28, 2026, 6:48am
8
type or
<#
.SYNOPSIS
Patch SailPoint ISC roles by adding entitlements from a CSV file.
.DESCRIPTION
Reads a CSV with columns: roleId, entitlementId, entitlementName
and patches each role to add the specified entitlements via the V2025 API.
Groups entitlements by roleId so each role is patched once with all its new entitlements.
.PARAMETER CsvPath
Path to the input CSV file.
.PARAMETER Tenant
Your ISC tenant name (e.g., "sample").
.PARAMETER ClientId
OAuth client ID for API authentication.
.PARAMETER ClientSecret
OAuth client secret for API authentication.
#>
param(
[Parameter(Mandatory = $true)]
[string]$CsvPath,
[Parameter(Mandatory = $false)]
[string]$Tenant = "sample",
[Parameter(Mandatory = $true)]
[string]$ClientId,
[Parameter(Mandatory = $true)]
[string]$ClientSecret
)
# ── Validate CSV exists ──
if (-not (Test-Path $CsvPath)) {
Write-Error "CSV file not found: $CsvPath"
exit 1
}
# ── Get OAuth access token ──
function Get-AccessToken {
param([string]$Tenant, [string]$ClientId, [string]$ClientSecret)
$tokenUrl = "https://$Tenant.api.identitynow.com/oauth/token"
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
}
try {
$response = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body $body -ContentType "application/x-www-form-urlencoded"
return $response.access_token
}
catch {
Write-Error "Failed to obtain access token: $_"
exit 1
}
}
# ── Get current entitlements on a role ──
function Get-RoleEntitlements {
param([string]$AccessToken, [string]$Tenant, [string]$RoleId)
$url = "https://$Tenant.api.identitynow.com/v2025/roles/$RoleId"
$headers = @{
"Authorization" = "Bearer $AccessToken"
"Accept" = "application/json"
}
try {
$role = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
if ($role.entitlements) {
return $role.entitlements
}
return @()
}
catch {
Write-Warning "Failed to get role $RoleId : $($_.Exception.Message)"
return @()
}
}
# ── Patch a role to add entitlements ──
function Add-EntitlementsToRole {
param(
[string]$AccessToken,
[string]$Tenant,
[string]$RoleId,
[array]$NewEntitlements
)
$url = "https://$Tenant.api.identitynow.com/v2025/roles/$RoleId"
$headers = @{
"Authorization" = "Bearer $AccessToken"
"Content-Type" = "application/json-patch+json"
"Accept" = "application/json"
}
# Build the add operations for each entitlement
$patchOps = @()
foreach ($ent in $NewEntitlements) {
$patchOps += @{
op = "add"
path = "/entitlements/-"
value = @{
id = $ent.entitlementId
type = "ENTITLEMENT"
name = $ent.entitlementName
}
}
}
$bodyJson = $patchOps | ConvertTo-Json -Depth 5
# Ensure it's always an array
if ($patchOps.Count -eq 1) {
$bodyJson = "[$bodyJson]"
}
try {
$response = Invoke-RestMethod -Uri $url -Method Patch -Headers $headers -Body $bodyJson
return @{ Success = $true; Response = $response }
}
catch {
$errorDetail = $_.ErrorDetails.Message
if (-not $errorDetail) { $errorDetail = $_.Exception.Message }
return @{ Success = $false; Error = $errorDetail }
}
}
# ── Main ──
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Role Entitlement Patcher" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
$accessToken = Get-AccessToken -Tenant $Tenant -ClientId $ClientId -ClientSecret $ClientSecret
Write-Host "Access token obtained successfully." -ForegroundColor Green
$csvData = Import-Csv -Path $CsvPath
Write-Host "Loaded $($csvData.Count) rows from CSV.`n" -ForegroundColor Yellow
# Group entitlements by roleId so each role is patched once
$grouped = $csvData | Group-Object -Property roleId
$successCount = 0
$failCount = 0
$results = @()
foreach ($group in $grouped) {
$roleId = $group.Name
$entitlements = $group.Group
$entNames = ($entitlements | ForEach-Object { $_.entitlementName }) -join ", "
Write-Host "Patching role [$roleId] with $($entitlements.Count) entitlement(s): $entNames ..." -NoNewline
$result = Add-EntitlementsToRole `
-AccessToken $accessToken `
-Tenant $Tenant `
-RoleId $roleId `
-NewEntitlements $entitlements
if ($result.Success) {
Write-Host " SUCCESS" -ForegroundColor Green
$successCount++
$results += [PSCustomObject]@{
RoleId = $roleId
Count = $entitlements.Count
Status = "Success"
Detail = "Patched"
}
}
else {
Write-Host " FAILED" -ForegroundColor Red
Write-Host " Error: $($result.Error)" -ForegroundColor Red
$failCount++
$results += [PSCustomObject]@{
RoleId = $roleId
Count = $entitlements.Count
Status = "Failed"
Detail = $result.Error
}
}
# Brief pause to avoid rate limiting
Start-Sleep -Milliseconds 500
}
# ── Summary ──
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " Summary: $successCount role(s) patched, $failCount failed out of $($grouped.Count)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# Export results log
$logPath = [System.IO.Path]::ChangeExtension($CsvPath, "_results.csv")
$results | Export-Csv -Path $logPath -NoTypeInformation
Write-Host "Results exported to: $logPath" -ForegroundColor Yellow
paste code here
csv sample
roleId,entitlementId,entitlementName
8aa952420f9f4d9286e9ca3daea2333b,2c91808a7e6f12ab017e6f12ab0c0001,SalesforceEntitlement1
8aa952420f9f4d9286e9ca3daea2333b,2c91808a7e6f12ab017e6f12ab0c0002,SalesforceEntitlement2
abcd1234ef5678901234567890abcdef,2c91808a7e6f12ab017e6f12ab0c0003,AnotherRoleEntitlement
Hi @RahulMekala You cannot import multiple entitlements into a single role using “;”. I recommend using the pipe symbol “|” instead and then retrying—it should work.
Error : Invalid entitlement format: Active directory|memberOf|wlannet|Active directory|memberOf|1234Staff
i am getting error with the formate
Hi @RahulMekala Just do one thing, export the file from vscode and put replace with your needed roles and entitlements, also just fyi, i have added the sample file for your visibility, hoping this will work for you now
company19188-poc.identitynow-demo.com-Roles.csv (680 Bytes)
Can you please share the Screenshot of error.
Error : Invalid entitlement format: Active directory|memberOf|wlannet|Active directory|memberOf|1234Staff
If still your issues not yet resolved then please create a separate topic as this is already marked as resolved so that we can talk in brief . anyway, kindly try to remove member of and then try and do let me know. If not work
I unfrotunately clicked on solution, i am getting 0 lines processed error
try once like this Active directory|wlannet;Active directory|1234Staff
@RahulMekala , You can use the bulk role importer written in ruby script, it is available in sailpoint compass channel, it makes easy to bulk update or import roles.