Skip to main content

#Get0 personne en discute

Hi all.

 

I am new on Python and and I wrote a code which is comparing the Site users between 2 servers (Prod and DEV) for validation purposes.

 

What I would like to know is: How to get ALL users from a Site and from a Project, as the GUI list?

 

My issue is after collecting the users source_server.users.get(), it is not reporting ALL the site users as I can see in the GUI.

 

I did identified that Server Administrators are not returning with this Site specific function, but there is also Viewer or Explorer only members that are missing in the API list.

 

May it be because these users does exist in multiple Sites?

 

with target_server.auth.sign_in(target_tableau_auth):

      target_all_sites, pagination_item = target_server.sites.get()

 for source_site in source_all_sites:

      source_tableau_auth.site_id = source_site.content_url

      with source_server.auth.sign_in(source_tableau_auth):  ⌗Connect to Source Site

        print("\nConnected to Source '{0}' Site on {1} Server".format(source_tableau_auth.site_id, source_server.server_address))

        source_all_users, pagination_item = source_server.users.get()  #Get User list from Source Site

12 réponses
  1. 25 août 2020, 15:15

    Thanks @Keshia Rose (Inactive)​ 

    There is the point I don't understand:

     

    This specific user Alexander is not listed in the Data Analytics Site, but when I check for users on All Sites, the user is listed as a Viewer for Data Analytics Site.

     

    In this case, the server.sites.get() is able to retrieve the user, but I can't see it on the GUI.

     

    When I created this topic I had the opposite situation. The API was not able to retrieve the user, related to the Site.

    Thanks @Keshia Rose (Inactive)​ There is the point I don't understand: This specific user Alexander is not listed in the Data Analytics Site, but when I check for users on All Sites, the user is liste

     

    Capture

0/9000

Hi Team,

I am trying to get details of Project,workbook and Groups having access to workbooks.

but not able to figure out join for the same.

Project and Workbook table have a direct join but in order to jin group table (via Site table) I am getting cartesion product.

7 réponses
  1. 9 sept. 2022, 01:48

    @Ayush Kedia​ 

    I have been trying to find a solution, however Max DeRung specifies in his site, there are several points to take into account:

    https://maxderungs.com/tableau-server-permissions/

     

    So, I really give up, on trying to make a query. Instead, I built the following python code, that uses Tableau Server Client, to get a csv of what workbookds a user has view access:

     

    import tableauserverclient as TSC

    import csv

     

    SERVER_NAME = "https://www.yourserver.com"

    SERVER_SITE = ''

    ⌗Credentials needed for Admin, Login with username and password is needed

    ⌗If login with token. TSC PAT auth does not allow impersonation. :(

    SERVER_USERNAME = "yourusername"

    SERVER_PASSWORD = "yourpassword"

     

     

    def main():

    ⌗Sign in with Username and password

    server = TSC.Server(SERVER_NAME, use_server_version=True)

    tableau_auth = TSC.TableauAuth(SERVER_USERNAME, SERVER_PASSWORD, SERVER_SITE)

    ⌗Obtain server sites

    site_auths = []

    with server.auth.sign_in(tableau_auth):

    site_auths.extend(

    site.content_url

    for site in TSC.Pager(server.sites))

    print(site_auths)

    ⌗Create csv file to obtain results

    csvfile = open('permissions.csv', 'w', encoding='utf-8-sig', newline='')

    writer = csv.writer(csvfile, delimiter=";")

    header = ['Site','User', 'Project', 'Workbook']

    writer.writerow(header)

    site_users = []

    for site_auth in site_auths:

    ⌗Get site users

    site_users = []

    with server.auth.sign_in(TSC.TableauAuth(SERVER_USERNAME,SERVER_PASSWORD,site_auth)):

    site_users.extend(

    [user.id, user.name]

    for user in TSC.Pager(server.users))

    server.auth.sign_out()

    for site_user in site_users:

    ⌗Impersonate user

    server, isUserLoggedInToServer = loginToServer(site_auth,site_user[0])

    ⌗Retrieve Workbooks for impersonated user

    if isUserLoggedInToServer == True:

    request_options = setPagination()

    all_workbook_items, pagination_item = server.workbooks.get(request_options)

    for workbook in all_workbook_items:

    if site_auth == "":

    row = ["Default", site_user[1], workbook.project_name ,workbook.name]

    else:

    row = [site_auth, site_user[1], workbook.project_name ,workbook.name]

    writer.writerow(row)

    server.auth.sign_out()

     

    def setPagination ():

    return TSC.RequestOptions(pagesize=1000)

    def loginToServer (*args):

    server = TSC.Server(SERVER_NAME, use_server_version=True)

    print("Login into site:", args[0], " userid:", args[1] )

    if args:

    try :

    tableau_auth = TSC.TableauAuth(SERVER_USERNAME, SERVER_PASSWORD, site_id=args[0], user_id_to_impersonate=args[1])

    server.auth.sign_in(tableau_auth)

    isUserLoggedInToServer = True

    print("Login into server in site ", args[0], " with userid", args[1] ," ", isUserLoggedInToServer)

    except:

    isUserLoggedInToServer = False

    print("Failed Login into server in site ", args[0], " with userid", args[1] ," ", isUserLoggedInToServer)

    else :

    try:

    server.auth.sign_out()

    tableau_auth = TSC.TableauAuth(SERVER_USERNAME, SERVER_PASSWORD, SERVER_SITE)

    server.auth.sign_in(tableau_auth)

    isUserLoggedInToServer = True

    print("Login into server as Administrator in Default Site ", isUserLoggedInToServer)

    except:

    isUserLoggedInToServer = False

    return server, isUserLoggedInToServer

    if __name__ == '__main__':

    main()

    I hope this will work for you. It works for me!!

     

    Take into account that for server admins, that does not appear in the site user list, workbooks won't show. But, I think this code is good enough.

     

    If this post resolves the question, would you be so kind to "Select as Best"?. This will help other users find the same answer/resolution and help community keep track of answered questions. Thank you.

     

    Regards,

     

    Diego Martinez

    Tableau Visionary and Forums Ambassador

0/9000

We are using Azure Devops to build a CICD pipeline for mulesoft. We are using the hybrid on prem model.

 

At the moment I have a build pipeline outputting a .jar file as an artifact using maven package

 

My Release pipeline takes this file using the Anypoint-cli and deploys it onto either dev, qa or production.

I am using the following command to modify an application and setting the correct OS env variables:

runtime-mgr standalone-application modify [options] <identifier> <zipfile>

 

I would like to pass properties using anypoint-cli along with my deployment but there doesn't appear to be an option. Whereas I notice that the cloudhub version does have the option to pass in properties.

 

Therefore, the work around I can see is to go into runtime manager on the anypoint platform to update properties manually. This works, but it is not going to be a great long term solution.

 

Is there a way to deploy an application which is already a .jar (build once, deploy anywhere), to multiple environments without having to intervene manually? We need environment variables to be set at the time of deployment, for security reasons. Therefore we can't have multiple yaml files at build time, even as secure-configuration properties.

 

Is a later version of Anypoint Platform CLI going to have this functionality?

Or perhaps have I missed something here and is this already possible?

 

Thanks so much in advance,

 

Toby.

14 réponses
  1. 27 janv. 2021, 17:13

    Do you need to stick it to exchange? I feel like that is an unnecessary turn to the goal.

0/9000
1 réponse
  1. 27 janv. 2021, 17:56

    Does anyone had made it?

    I do have a set of groups defined on Default Project/Default Site, and would like to replicate the permissions I have on each one to other Projects.

     

    The attached picture is the set of permissions I want to transpose.

     

    Below is the code, and the results I can get from it...

    Does anyone had made it?I do have a set of groups defined on Default Project/Default Site, and would like to replicate the permissions I have on each one to other Projects.with server.auth.sign_in(tableau_auth):

      print("Connected to Site: ", site_url)

       

      endpoint = server.projects

      all_project_items = list(TSC.Pager(endpoint, request_option))

         

      for project in all_project_items:         

        #get permissions from Projects (related to Groups and Users)     

        if project.name == 'Default':

          project_Default = project

          break

           

      print(project_Default.name)

       

      server.projects.populate_permissions(project_Default)

               

      #List Groups

      endpoint = server.groups

      all_groups = list(TSC.Pager(endpoint, request_option))

      for group in all_groups :

        print(group.name)

         

      print("")

      ⌗Validate the User Group is related to the Project         

      for permission in project_Default.permissions:           

          

        ⌗ProjectLeader Group           

        for capability in permission.capabilities:

         

          for group in all_groups:

            ⌗ProjectLeader Groups

            if group.id == permission.grantee.id:

              print(group.name, " - ", capability, " - ", permission.capabilities)   

     

    ############################

    RESULT

    ############################

    Connected to Site:  

    Default

    All Users

    forge rock

    Project_Owners

    Project_Analysts

    Project_Viewers

     

    All Users - Read - {'Read': 'Allow'}

    Project_Owners - ProjectLeader - {'ProjectLeader': 'Allow'}

    Project_Analysts - Read - {'Read': 'Allow'}

    Project_Viewers - Read - {'Read': 'Allow'}

0/9000

How to update / create users coming from Active Directory in Tableau?🙂

 

I have been asked this question many times in last few months in many forums, how to automatically inactive the users in Tableau server if they are getting inactive in Active Directory or how to create Users in Tableau Server in case any users are newly on boarded in AD users groups available in Tableau, hence writing this solution here

 

I will not write full code here, it will give you fair enough idea how to achieve the other things

 

Requirements

  1. Active Directory details
  2. PowerShell
  3. Obdc Driver to reach to Tableau Postgres data base
  4. Make sure Tableau database should be enabled
  5. Administrative privileges on the Tableau server

Script:

 

Clear

⌗Get users from ad server

 

Get-ADUser -Filter * -Properties Name, SamAccountName, EmailAddress, UserPrincipalName, Enabled, Company | Select-Object Name, SamAccountName,UserPrincipalName, EmailAddress, Enabled, Company | where {$_.company -eq "ABHICL"} | Export-Csv "E:\Sandip_SQL\ADUsers_group.csv"

 

⌗export all the users from Tableau Server

⌗importing my tableau server postgres details kept in csv file

$PostgreSQL_Connection_String = import-csv -path "E:\Sandip_SQL\PostgreSQL_Connection_String.csv"

 

foreach ($Row in $PostgreSQL_Connection_String)

{

$connectionString = "Driver=$($Row.Driver);Server=$($Row.Server);Port=$($Row.Port);Database=$($Row.Database);Uid=$($Row.User);Pwd=$($Row.Password);"

}

$connection = New-Object System.Data.Odbc.OdbcConnection

$connection.ConnectionString = $connectionString

$connection.Open()

 

$query = "SELECT name AS UserID,friendly_name AS UserName,licensing_role_name AS Role FROM public._users where name not in ('_system','guest')”

 

$command = $connection.CreateCommand()

$command.CommandText = $query

$command.CommandTimeout = 0 

$result = $command.ExecuteReader()

$table = new-object “System.Data.DataTable”

$table.Load($result)

$table |Export-Csv -path "E:\Sandip_SQL\tableauusers.csv" ⌗ROWS_INSERTED

$connection.Close()

 

⌗importing both files ad users and Tableau users

 

$adusers = import-csv -path "E:\Sandip_SQL\ADUsers_group.csv"

$tabusers = import-csv -path "E:\Sandip_SQL\tableauusers.csv"

 

#I will first check the records only if exist in both csv and then will mark them unlicensed in Tableau server if their status is not active in AD and License type is still allocated to user

⌗matching counter and monitoring of time taken by the script

$matchcounter

$start = [system.datetime]::Now

 

# create new CSV file

foreach ($order1 in $adusers){

  $matched = $false

  foreach ($order2 in $tabusers){

    $obj = "" | select "SamAccountName","Ad_Status","Tableau_Role"

    if(($order1.SamAccountName ) -eq $order2.userid ){

      $matchCounter++

      $matched = $true

      $obj.SamAccountName = $order1.SamAccountName

      $obj.Ad_Status = $order1.Enabled

      $obj.Tableau_Role = $order2.role

      Write-Host "Match Found Orders " "$matchCounter"

      $obj | Export-Csv -Path E:\Sandip_SQL\AD_Tableau_Users_Match.csv -Append -NoTypeInformation

    }

  }

}

$end = [system.datetime]::Now

$resultTime = $end - $start

Write-Host "Execution took : $($resultTime.TotalSeconds) seconds."

 

$updateuser = import-csv -path "E:\Sandip_SQL\AD_Tableau_Users_Match.csv"

 

# Setup to connect

 

$server = "your tableau server url"

 

$s = Invoke-RestMethod -Uri $server/api/3.7/serverinfo -Method get ⌗works on server version 10.1 and later

 

$api = $s.tsResponse.serverInfo.restApiVersion #2020.1 server

 

echo $api

 

⌗make sure you should use either site admin or administrator account only to perform below activity

$username = “your tableau user”

 

$password = “your tableau password”

 

$sitelogin = "" ⌗keep site as blank in case of default site

 

# generate body for sign in

 

$signin_body = (’<tsRequest>

 

 <credentials name=“’ + $username + ’” password=“’+ $password + ’” >

 

  <site contentUrl="'+$sitelogin +'" />

 

 </credentials>

 

</tsRequest>’)

 

$response = Invoke-RestMethod -Uri $server/api/$api/auth/signin -Body $signin_body -Method post

 

# save the auth token, site id and my user id

 

$authToken = $response.tsResponse.credentials.token

 

$siteID = $response.tsResponse.credentials.site.id

 

$myUserID = $response.tsResponse.credentials.user.id

 

$siteURL = $response.tsResponse.credentials.site.contentUrl

 

echo $siteID

 

# set up header fields with auth token

 

$headers = New-Object “System.Collections.Generic.Dictionary[[String],[String]]”

 

# add X-Tableau-Auth header with our auth token

 

$headers.Add(“X-Tableau-Auth”, $authToken)

 

⌗tests whether logged in user is an Administrator (site or server)

 

$loginUserid = Invoke-RestMethod -Uri $server/api/$api/sites/$siteID/users/$myUserID -Headers $headers -Method Get

 

$admin = $loginUserid.tsResponse.user.siteRole -like "*Administrator"

 

if($admin)

{

 

foreach ($line in $updateuser )

 

  {

    if($line.Ad_Status -eq "FALSE" -and $line.Tableau_Role -ne "Unlicensed")

      {

        $userid = $line.SamAccountName

        $SiteRole = "Unlicensed"

                 

        ⌗user update body

        $userupdate = ( '<tsRequest> <user siteRole="'+$SiteRole+'" /> </tsRequest>' )

 

        $response = Invoke-RestMethod -Uri $server/api/$api/sites/$siteID/users/$userid -Headers $headers -Method Put -Body $userupdate

         

        write-host $response.tsResponse.user

 

      }

 

  }

}

 

@Ciara Brennan​  @David Browne​  @Veronica Simoes​ 

3 commentaires
  1. 14 sept. 2020, 15:08

    That's Great @SANDIP SHARMA​ !

0/9000

I'm not sure the best way to put this into words, so I wrote it out in what I hope is an English legible pseudo code. # denotes a comment for explanation purposes. I've been trying to do this in tableau with LOD descriptions, for example {FIXED [Subscriber ID]:COUNT([Subscriber ID])} counts the number of instances of the same ID but it doesn't exclude those not made within 24 hours of one another. Any help would be greatly appreciated

 

for each entry:

     get list of all other entries with same UserID

          for each entry in list:

               if thisEntry.date-entryWithSameUserID.date < 24 hours:

                    add to resultsList

                    break

 

⌗now I have a results list with a bunch of entries that were logged

⌗within 24 hours of one another from the same user ID

⌗note that if a user made 2 entries in our data base on 1/1/2019

⌗and then the same user made 2 entries in our data base on 2/2/2019

⌗the same user would be in our results list multiple times for the

⌗two seperate occasions that s/he made multiple purchases within 24 hours

 

for each entry in resultsList

     ⌗get how many entries were made within a 24 hour period per ID

     Count instances of each ID

 

     ⌗get which purchases led to more purchases within 24 hours

     ⌗ex. if someone buys a puppy, are they likely to also buy a bed within 24 hours?

     ⌗ex. if someone buys a puppy, are they likely to also buy a bed AND food within 24 hours?

     for each set of purchases made within 24 hours

          count which purchases were made with the earliest date

3 réponses
  1. 1 mai 2019, 19:52

    The relative date will consider the computer date (unless you specify at the bottom that the date is relative to a specific date).

     

    But this can cause problems if your data is not updated. If someday you don't have your data refresh done the dashboard will appear empty (which is never good).

     

    To address that I had to apply something like this LOD on a dashboard I built:

     

    {FIXED [Dimension] :

        SUM(IIF(DATETRUNC('day', [Date]) = [MAX Date],[Measure],NULL))

    }

     

    And the MAX Date field is just a check on your MAX(Date) (which you can define as anything you want). For me it looks like this:

     

    DATE({MAX([Date])})

     

    I hope these helps.

    Rodrigo

0/9000

Does anyone have a solution to "run schedules" using the API (2.8, 2.7, 2.6)?

 

I have seen "undocumented references" like (/api/2.x/run/schedules/) to run schedules, but am reticent to use....

 

The "run schedule" from tabcmd is very helpful in that, it can trigger an extract refresh for MULTIPLE books that happen to be on the same schedule_id... And I'm trying to recreate that ability once the data is ready rather than what for say, 10 o'clock.

 

Does anyone know if I can use the schedule_id as input to a refresh extract and it will work?? Or, better know of a way to avoid hardcoding the books so that I can run extract commands programitically when the ETL finishes??

 

thanks!

jim!

3 réponses
  1. 28 mars 2018, 14:44

    Hi Gaurav

    Have written the following REST API code in Powershell to run all tasks assigned to a schedule.

    Hopefully this will resolve your problem

    You will need to save the code into a .ps1 file

    and then run in powershell window.

     

    ie. .\RunSchedule.ps1 -server localhost -username glen -password password -Schedule "Every 15 Mins"

     

    param(

       [string[]] $server,

       [string[]] $username,

       [string[]] $password,

       [validateset('http','https')][string[]] $protocol = 'http',

       [string[]] $siteID = "",

       [string[]] $ScheduleName

    )

     

    function TS-GetScheduleDetails

    {

    param(

    [string[]] $Name = ""

    )

     

    $PageSize = 100

    $PageNumber = 1

    $done = 'FALSE'

     

    While ($done -eq 'FALSE')

    {

      $response = Invoke-RestMethod -Uri ${protocol}://$server/api/$api_ver/schedules?pageSize=$PageSize`&pageNumber=$PageNumber -Headers $headers -Method Get

      $totalAvailable = $response.tsResponse.pagination.totalAvailable

      If ($PageSize*$PageNumber -gt $totalAvailable) { $done = 'TRUE'}

      $PageNumber += 1

      foreach ($detail in $response.tsResponse.schedules.schedule)

       {

        if ($Name -eq $detail.name){Return $detail.ID}

       }

    }

     

    }

     

    $api_ver = '2.8'

     

    $global:server = $server

    $global:protocol = $protocol

    $global:username = $username

    $global:password = $password

     

    # generate body for sign in

    $signin_body = (’<tsRequest>

      <credentials name=“’ + $username + ’” password=“’+ $password + ’” >

       <site contentUrl="’ + $siteID +’"/>

      </credentials>

    </tsRequest>’)

     

       $response = Invoke-RestMethod -Uri ${protocol}://$server/api/$api_ver/auth/signin -Body $signin_body -Method Post

       # get the auth token, site id and my user id

       $authToken = $response.tsResponse.credentials.token

       $siteID = $response.tsResponse.credentials.site.id

       $myUserID = $response.tsResponse.credentials.user.id

     

       # set up header fields with auth token

       $headers = New-Object “System.Collections.Generic.Dictionary[[String],[String]]”

       # add X-Tableau-Auth header with our auth tokents-

       $headers.Add(“X-Tableau-Auth”, $authToken)

     

    #Get Schedule ID

     

    $ScheduleID = TS-GetScheduleDetails -Name $ScheduleName

    $ScheduleID

     

    #Get Tasks assigned to this schedule and run them8

     

      $PageSize = 100

      $PageNumber = 1

      $done = 'FALSE'

     

      While ($done -eq 'FALSE')

       {

        $response = Invoke-RestMethod -Uri ${protocol}://$server/api/$api_ver/sites/$siteID/schedules/$ScheduleID/extracts?pageSize=$PageSize`&pageNumber=$PageNumber -Headers $headers -Method Get

        $totalAvailable = $response.tsResponse.pagination.totalAvailable

     

        If ($PageSize*$PageNumber -gt $totalAvailable) { $done = 'TRUE'}

     

        $PageNumber += 1

     

        ForEach ($detail in $response.tsResponse.extracts.extract)

         {

           $TaskID = $detail.ID

           $body = "<tsRequest></tsRequest>"

           $response = Invoke-RestMethod -Uri ${protocol}://$server/api/$api_ver/sites/$siteID/tasks/extractRefreshes/$TaskID/runNow -Headers $headers -Method POST -Body $body -ContentType "text/xml"

           $response.tsresponse.job

               }

       }

     

      $response = Invoke-RestMethod -Uri ${protocol}://$server/api/$api_ver/auth/signout -Headers $headers -Method Post

      "Signed Out Successfully from: " + ${protocol}+ "://"+$server

0/9000

Hi There,

 

We are trying to parse XML using REST API "Query Workbooks for Site" to get the workbook id, workbook name, tags associated with the workbook and the project it belongs to.

Expected Response body:

<tsResponse>

  <pagination pageNumber="page-number"

 

     pageSize="page-size"

 

     totalAvailable="total-available" />

  <workbooks>

    <workbook id="workbook-id" name="name"

 

          contentUrl="content-url" 

 

          showTabs="show-tabs-flag"

 

          size="size-in-megabytes"

 

          createdAt="datetime-created"

 

          updatedAt="datetime-updated"  >

      <project id="project-id" name="project-name" />

      <owner id="user-id" />

      <tags>

        <tag label="tag"/>

        ... additional tags ...

     </tags>

   </workbook>

   ... additional workbooks ...

  </workbooks>

 

We are unable to get the project id, project name, owner id and the tags associated with the workbook

 

We use the below to parse XML.

import xml.etree.ElementTree as ET

Below is the query

def query_workbooks():

 

    """

 

    Returns a list of workbooks on the site (a list of <workbook> elements).

 

    The function paginates over results (if required) using a page size of 100.

 

    """

 

  

 

    #GET /api/api-version/sites/site-id/workbooks?pageSize=page-size&pageNumber=page-number

 

    url = SERVER + "/api/{0}/sites/{1}/workbooks".format(API_VERSION,SITE_ID)

 

 

    pageNum, pageSize = 1, 100

    paged_url = url + "?pageSize={}&pageNumber={}".format(pageSize, pageNum)

    server_response = requests.get(paged_url, headers={"x-tableau-auth": TOKEN},verify=False)

 

    server_response.encoding = "utf-8";

 

    if server_response.status_code != 200:

 

        print(_encode_for_display(server_response.text))

 

        sys.exit(1)

 

    xml_response = ET.fromstring(_encode_for_display(server_response.text))

    total_count_of_workbooks = int(xml_response.find('t:pagination', namespaces=xmlns).attrib.get('totalAvailable'))

 

   

 

   

 

    if total_count_of_workbooks > pageSize:

 

        workbooks = []

 

        workbooks.extend(xml_response.findall('.//t:workbooks/workbook', namespaces=xmlns))

 

        number_of_pages = int(math.ceil(total_count_of_workbooks / pageSize))

 

       

 

        # Starts from page 2 because page 1 has already been returned

 

        for page in range(2, number_of_pages + 1):

 

            paged_url = url + "?pageSize={}&pageNumber={}".format(pageSize, page)

 

            server_response = requests.get(paged_url, headers={"x-tableau-auth": TOKEN},verify=False)

 

            if server_response.status_code != 200:

 

                print(_encode_for_display(server_response.text))

 

                sys.exit(1)

 

            workbooks_from_page = ET.fromstring(_encode_for_display(server_response.text)).findall('.//t:workbook', namespaces=xmlns)

 

            workbooks.extend(workbooks_from_page)

 

    else:

 

        workbooks = xml_response.findall('.//t:workbook', namespaces=xmlns)

 

          

 

    return workbooks

````````````````

for WB in list_of_workbooks:

        print("IN A WB : "+ str(WB))

        '''

        a = a + 1

        print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :" + str(a))

        print("WB #" + str(a) + "           is:" +  WB.get('name'))

        print("              id is:        " +  WB.get('id'))

        print("      contentUrl is:" +  WB.get('contentUrl'))

        print("       updatedAt is:" +  WB.get('updatedAt'))

        '''

       

    for tag in list_of_tags:

        print("IN A TAG"  + tag.get(tag))

 

Can someone help us to understand what's wrong with this query, why we are not able to get the tags, project id, project name, owner id in the response.

Thanks,

Shoba

3 réponses
0/9000

I am developing a Powershell-based deployment model for our Tableau environment utilizing the Tableau Server REST API (Server v10; API version 2.3). I am able to login to server, login to sites, query projects, query workbooks, query data sources, and upload file, but encounter an error when attempting to publish a previously uploaded file:

<error code="400011"><summary>Bad Request</summary><detail>There was a problem publishing the file '10356:81CF357C252F4EA19FE7CE27F9F6B3FD-0:0'.</detail></error>

 

This same file upload succeeds when I execute the Python sample code provided, so I know the .twbx file is good, and the Tableau Server REST API is functioning. Using Fiddler, I have compared line-by-line the PowerShell POST request and Python POST request, and cannot see any differences. I'm not sure what I'm missing. Using PowerShell is a requirement.

 

1. Has anyone successfully published a workbook with the REST API and PowerShell? If so, what's your secret to success?

2. Does Tableau Server have API logs that provide more details than the useless error that is returned?

 

Thanks for any assistance you can provide.

6 réponses
  1. 27 sept. 2016, 19:26

    Hi Chuck

    I have been through the very same issue.

    It seems that using the Powershell Invoke-RestMethod (and Invoke-WebRequest) works fine with text based requests, but does something weird when uploading a twbx, tdsx, or tde.

     

    Therefore I used the System.New.WebClient method instead

     

    The setup is the same as with the Invoke-RestMethod, but using the following process.

     

      $wc = New-Object System.Net.WebClient

      $wc.Headers.Add('X-Tableau-Auth',$headers.Values[0])

      $wc.Headers.Add('ContentLength', $request_body.Length)

      $wc.Headers.Add('Content-Type', 'multipart/mixed; boundary=6691a87289ac461bab2c945741f136e6')

      $response = $wc.UploadString($url ,'POST', $request_body)

     

    The $request_body is of the following format

     

    Hi ChuckI have been through the very same issue.

     

    the boundary=xxxx needs to be the same as the boundary-string in the request_body

    the $url is of the format "http://servername/api/2.2/sites/<siteID>/workbooks"

     

    Hope this helps

     

    All the best

    Glen

0/9000