for executive PowerShell script to call Fabric API i am getting the error

Kakade, Dipali 0 Reputation points
2026-10-21T09:51:52.8+00:00
2026-10-19T14:41:56.0496759Z SPN Login Successful
2026-10-19T14:41:56.3618670Z Token type returned: System.Security.SecureString
2026-10-19T14:41:56.3692266Z Fabric Token Acquired (valid JWT format)
2026-10-19T14:42:02.8913977Z Git status call failed: The remote server returned an error: (401) Unauthorized.
2026-10-19T14:42:02.9781662Z Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
2026-10-19T14:42:02.9783210Z At D:\a\_temp\434305ee-e33f-48b6-afdf-042bb20b8937.ps1:101 char:18
2026-10-19T14:42:02.9784384Z +     $gitStatus = Invoke-RestMethod -Method GET `
2026-10-19T14:42:02.9785453Z +                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2026-10-19T14:42:02.9786720Z     + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc 
2026-10-19T14:42:02.9790320Z    eption
2026-10-19T14:42:02.9791535Z     + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
2026-10-19T14:42:02.9798752Z  
2026-10-19T14:42:03.2099790Z ##[error]PowerShell exited with code '1'.
2026-10-19T14:42:03.2385953Z ##[section]Finishing: PowerShell Script


Azure DevOps

2 answers

Sort by: Most helpful
  1. AI answer

    2026-10-22T14:05:50.12+00:00

    Capture the Fabric response body and errorCode first, because a 401 means token authentication or validation failed; missing workspace privileges normally produces 403, so reconfiguring Git permissions before validating the token may not address this failure.^1^

    1. Capture the actual Fabric error

    Replace the current Git status call temporarily with:

    $uri = "https://api.fabric.microsoft.com/v1/workspaces/$workspaceId/git/status"
    
    try {
        $gitStatus = Invoke-RestMethod -Method Get -Uri $uri `
            -Headers $headers -ErrorAction Stop
    }
    catch {
        $response = $_.Exception.Response
        $requestId = $response.Headers["requestId"]
    
        $reader = [IO.StreamReader]::new($response.GetResponseStream())
        $body = $reader.ReadToEnd()
    
        Write-Error "Fabric request failed. RequestId=$requestId Body=$body"
        throw
    }
    

    Fabric returns a structured error containing errorCode, message, and requestId. Preserve the requestId for support escalation.^1^

    Act on the returned code:

    • TokenExpired: acquire a fresh token immediately before the API call.
    • InsufficientScopes: verify that the token was requested for the Fabric API.
    • Another code: use that code rather than the changing human-readable message to select the next action.

    2. Validate the token claims without printing the token

    A JWT-shaped value only confirms its format. Check its audience, tenant, expiry, and calling application:

    $payload = $token.Split('.')[1].Replace('-', '+').Replace('_', '/')
    $payload += '=' * ((4 - $payload.Length % 4) % 4)
    
    $claims = [Text.Encoding]::UTF8.GetString(
        [Convert]::FromBase64String($payload)
    ) | ConvertFrom-Json
    
    [pscustomobject]@{
        Audience = $claims.aud
        Tenant   = $claims.tid
        AppId    = if ($claims.azp) { $claims.azp } else { $claims.appid }
        Expires  = [DateTimeOffset]::FromUnixTimeSeconds($claims.exp).UtcDateTime
    }
    

    Confirm that:

    • Audience is the Fabric API audience.
    • Tenant is the tenant containing the target Fabric workspace.
    • AppId is the service principal used by the Azure DevOps pipeline.
    • Expires is later than the API-call time.

    The documented app-only request uses scope=https://api.fabric.microsoft.com/.default.^2^ Your Get-AzAccessToken -ResourceUrl "https://api.fabric.microsoft.com" pattern is also the documented Fabric PowerShell pattern, provided the active Az context is the intended service principal and tenant.^3^

    For direct service-principal access, delegated scopes such as Workspace.GitUpdate.All are not the governing authorization mechanism; service principals are controlled through Fabric tenant controls and Fabric resource permissions.^4^

    3. After token authentication succeeds, configure this SPN as the Git caller

    The Git status endpoint supports service principals, but the caller must have Contributor or higher workspace access and must have its own Git credentials configured.^5^

    For a workspace already connected to Azure DevOps under a user identity:

    1. A workspace Admin adds the SPN to the workspace. The documented existing-workspace setup uses the Admin role.
    2. The Azure DevOps cloud-connection owner shares that connection with the SPN through Manage users, or creates a connection using the SPN.
    3. Call GET /v1/connections as the SPN and verify that the required connection is returned.
    4. Configure the connection specifically for this caller:
    $body = @{
        source       = "ConfiguredConnection"
        connectionId = $connectionId
    } | ConvertTo-Json
    
    $uri = "https://api.fabric.microsoft.com/v1/workspaces/$workspaceId/git/myGitCredentials"
    
    Invoke-RestMethod -Method Patch -Uri $uri `
        -Headers $headers -Body $body -ErrorAction Stop
    

    These are the documented steps required before that service principal performs Fabric Git REST operations.^2^

    If the SPN has not been added to the Azure DevOps organization/project, an Azure DevOps administrator must add it under Organization settings → Users, then add it to the relevant project team.^6^

    If the request still returns 401 after the claims are correct, provide Microsoft Support with the captured errorCode, requestId, UTC timestamp, endpoint, and non-secret claim values. Do not include the Bearer [Token] or client secret.


    References

    1. Troubleshoot Microsoft Fabric REST APIs
    2. Automate git integration with a service principal in Azure DevOps
    3. Automate Git integration by using APIs
    4. Scopes
    5. Git - Get Status
    6. Manual git integration with a service principal in Azure DevOps
    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

  2. Alex Burlachenko 25,615 Reputation points MVP Volunteer Moderator
    2026-10-21T14:00:51.32+00:00

    Hi Kakade, Dipali & thx for join me at Q&A platform,

    important detail in ur logs is that SPN authentication succeeds, but the Fabric Git status API returns 401. Those are two different checks. Getting a valid JWT doesn't necessarily mean the token is intended for Microsoft Fabric or that the service principal has access to the workspace.

    I'd check the token audience first. For Fabric REST APIs, the token needs to target https://api.fabric.microsoft.com, not Azure Resource Manager or Azure DevOps. If you're using Get-AzAccessToken, request it explicitly:

    $token = Get-AzAccessToken -ResourceUrl "https://api.fabric.microsoft.com"

    $plainToken = [System.Net.NetworkCredential]::new(

    "", $token.Token
    

    ).Password

    $headers = @{

    Authorization = "Bearer $plainToken"
    
    "Content-Type" = "application/json"
    

    }

    $gitStatus = Invoke-RestMethod -Method GET `

    -Uri "https://api.fabric.microsoft.com/v1/workspaces/$workspaceId/git/status" `
    
    -Headers $headers
    

    The SecureString message in ur log is worth checking too. If ur script passes the SecureString object directly into the Authorization header instead of converting it to the actual token text, the API won't receive a valid bearer token.

    Next, check Fabric Admin portal > Tenant settings > Developer settings > Service principals can call Fabric public APIs. Make sure it's enabled and that ur service principal belongs to an allowed security group if the setting is restricted.

    The Git status endpoint does support service principals, but the SPN needs at least Contributor access to the Fabric workspace. Also, Fabric Git integration has its own authentication configuration. For service principals, the Git credential source should be ConfiguredConnection, not Automatic, and the SPN needs permission to use that Azure DevOps connection.

    You can check the Git credential configuration using:

    Invoke-RestMethod -Method GET `

    -Uri "https://api.fabric.microsoft.com/v1/workspaces/$workspaceId/git/myGitCredentials" `
    
    -Headers $headers
    

    If that returns "source": "None" or "Automatic", you'll need to configure an appropriate Azure DevOps cloud connection and associate it with the SPN using the Update My Git Credentials API.

    I'd also try a simpler Fabric API request, such as GET https://api.fabric.microsoft.com/v1/workspaces, using the same token. If that fails with 401 too, focus on the token, tenant configuration, and Authorization header. If it succeeds but Git status fails, investigate workspace access and Git credentials.

    One more thing: decode the JWT locally and inspect its aud, tid, and appid/azp claims. Don't paste the full token into pipeline logs, tho. Also capture the response body and x-ms-request-id from the failed request if available.

    Could u share the PowerShell section where you're obtaining the token and constructing the Authorization header (with secrets removed)? That would help determine whether the 401 is caused by token handling or Fabric permissions.

    rgds,

    Alex

    p.s. if my answer is help - pls mark it as an answer

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.