Forum Discussion

ReyCarter_777's avatar
10 months ago
Solved

User account access to the dashboard via API

Good afternoon!
We have a very important and urgent task.
As you all know, you can give access to a specific Power BI dashboard in the Report Server version to a specific user account or Active Directory group (through the interface in Management-Security). In our case, we cannot give access to a group, and when a request comes in for 100+ users to access a specific dashboard, it is not possible to add them one by one. In this regard, the idea came up to create a python script in which to add users through the PBIRS API. But the problem is, which of the API to use for this? There are many methods on the site, what should we apply for this task?
https://app.swaggerhub.com/apis/microsoft-rs/PBIRS/2.0#/info
Also thought about adding through SQL Server to system tables, but the method is very risky for the server's performance, so we abandoned it.
Please help us, I can't believe that there is no other method besides using Active Directory groups.

  • Yay, it worked. Used just the API I mentioned above (PUT request) and python script. Thanks for the help!

10 Replies

  • Hi ReyCarter_777

     

    Do you have admin access to the server that RS is hosted on? If so, you can do this with PowerShell. 

     

    Below I have attached a sample PowerShell script. This script takes a single username and role, and assigns it to all reports that have broken inherentience (useful for admins to recover a report if users removed everyone in the security tab), but with some tweaks you could get it to pull from a csv file of users and add one role to all those users for a specific report. 

     

    Is there a particular reason you can't use AD groups? This is a much easier way of adding and maintaining users. 

     

    ' rs.exe -v variables expected:
    '   userName, roleName, rootPath, forceOverlay
    
    Dim addedCount As Integer = 0
    Dim skippedCount As Integer = 0
    Dim alreadyHadCount As Integer = 0
    Dim errorCount As Integer = 0
    
    Public Sub Main()
        If rootPath Is Nothing OrElse rootPath = "" Then rootPath = "/"
        If roleName Is Nothing OrElse roleName = "" Then roleName = "Content Manager"
    
        Dim overlay As Boolean = False
        If Not (forceOverlay Is Nothing) Then
            Try : overlay = System.Convert.ToBoolean(forceOverlay) : Catch : overlay = False : End Try
        End If
    
        Console.WriteLine("Starting...")
        Console.WriteLine("  Root path : " & rootPath)
        Console.WriteLine("  User      : " & userName)
        Console.WriteLine("  Role      : " & roleName)
        Console.WriteLine("  Overlay?  : " & overlay.ToString())
    
        Try
            Dim items() As CatalogItem = rs.ListChildren(rootPath, True)
            Console.WriteLine("Found " & items.Length & " items. Processing...")
    
            For Each it As CatalogItem In items
                ProcessItem(it, overlay)
            Next
    
            Console.WriteLine("Done.")
            Console.WriteLine("  Added     : " & addedCount)
            Console.WriteLine("  Already   : " & alreadyHadCount)
            Console.WriteLine("  Skipped   : " & skippedCount)
            Console.WriteLine("  Errors    : " & errorCount)
    
        Catch ex As Exception
            Console.WriteLine("FATAL: " & ex.ToString())
        End Try
    End Sub
    
    Sub ProcessItem(it As CatalogItem, overlay As Boolean)
        Try
            Dim inheritParent As Boolean = True
            Dim policies() As Policy = rs.GetPolicies(it.Path, inheritParent) ' ByRef param
    
            ' If not forcing overlay and this item still inherits, skip it.
            If (inheritParent AndAlso Not overlay) Then
                skippedCount += 1
                Return
            End If
    
            ' Start with existing policies (if any)
            Dim current As New System.Collections.Generic.List(Of Policy)
            If Not (policies Is Nothing) Then current.AddRange(policies)
    
            ' Check if our user already has the desired role
            Dim hasUser As Boolean = False
            Dim hasRole As Boolean = False
    
            For Each p As Policy In current
                If StringComparer.OrdinalIgnoreCase.Equals(p.GroupUserName, userName) Then
                    hasUser = True
                    If Not (p.Roles Is Nothing) Then
                        For Each r As Role In p.Roles
                            If StringComparer.OrdinalIgnoreCase.Equals(r.Name, roleName) Then
                                hasRole = True
                                Exit For
                            End If
                        Next
                    End If
                    Exit For
                End If
            Next
    
            If hasUser AndAlso hasRole Then
                alreadyHadCount += 1
                Return
            End If
    
            ' Merge or create our policy
            If hasUser Then
                For Each p As Policy In current
                    If StringComparer.OrdinalIgnoreCase.Equals(p.GroupUserName, userName) Then
                        Dim rolesList As New System.Collections.Generic.List(Of Role)
                        If Not (p.Roles Is Nothing) Then rolesList.AddRange(p.Roles)
    
                        Dim roleExists As Boolean = False
                        For Each r As Role In rolesList
                            If StringComparer.OrdinalIgnoreCase.Equals(r.Name, roleName) Then
                                roleExists = True
                                Exit For
                            End If
                        Next
    
                        If Not roleExists Then
                            Dim newRole As New Role()
                            newRole.Name = roleName
                            rolesList.Add(newRole)
                            p.Roles = rolesList.ToArray()
                        End If
                        Exit For
                    End If
                Next
            Else
                Dim newP As New Policy()
                newP.GroupUserName = userName
                Dim newRole As New Role()
                newRole.Name = roleName
                newP.Roles = New Role() { newRole }
                current.Add(newP)
            End If
    
            ' Apply policies (this breaks inheritance if it was inheriting and overlay=True)
            rs.SetPolicies(it.Path, current.ToArray())
            addedCount += 1
    
        Catch ex As Exception
            errorCount += 1
            Console.WriteLine("ERROR on '" & it.Path & "': " & ex.Message)
        End Try
    End Sub

     

     

    If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.

    • ReyCarter_777's avatar
      ReyCarter_777
      Icon for Helper I rankHelper I

      Yes, I am the server administrator. Our task is to assign the Browser role to the specified users on a specific dashboard. This means that we specify the path or ID of the dashboard and the users at the entrance. As a result, we should have the specified users with the Browser role in the Security section of the dashboard. We cannot use AD because this server is managed by other company employees who are not interested in the development of Report Server. In this case, you will have to constantly maintain and develop your AD groups, which is a huge labor-intensive task.

      • tayloramy's avatar
        tayloramy
        Icon for Super User rankSuper User

        Hi ReyCarter_777

         

        How adept are you in PowerShell? Are you able to modify my powershell script to read from a csv of users and add them to a report path/ID given as a parameter? 

         

        If you found this helpful, consider giving some Kudos. If I answered your question or solved your problem, mark this post as the solution.

  • Yay, it worked. Used just the API I mentioned above (PUT request) and python script. Thanks for the help!