From f0b5d60e4f075cb056c83ad48ec462d123b5a04f Mon Sep 17 00:00:00 2001 From: "VISUALBI\\SHANKARN" Date: Mon, 10 Dec 2018 16:01:54 -0600 Subject: [PATCH 1/6] Added uploadapplication --- README.md | 2 + uploadapplication.ps1 | 192 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 uploadapplication.ps1 diff --git a/README.md b/README.md index 08ee557..a12ced4 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ This repo contains samples for calling the Power BI REST APIs using PowerShell. * [Zero-Downtime-Capacity-Scale.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/Zero-Downtime-Capacity-Scale.ps1) - scale Power BI Embedded capacity resource, up or down, with no downtime (i.e. embedded content is available during the scaling process). +* [uploadapplication.ps1] - Upload local Power BI Application to the specified Workspace + ## Prerequisites To run the scripts in this repo, please install [PowerShell](https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) and the [Azure Resource Manager PowerShell cmdlets](https://www.powershellgallery.com/packages/AzureRM/). diff --git a/uploadapplication.ps1 b/uploadapplication.ps1 new file mode 100644 index 0000000..753ddd6 --- /dev/null +++ b/uploadapplication.ps1 @@ -0,0 +1,192 @@ +# This script calls the Power BI API to programmatically upload the local PBIX files +# into a Workspace + +[cmdletbinding()] +param ( + [Parameter(Mandatory=$true)][string]$Workspace +) + +# Instructions: +# 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) +# and the Azure PowerShell cmdlets (Install-Module AzureRM) +# 2. Run PowerShell as an administrator +# 3. Follow the instructions below to fill in the client ID +# 4. Change PowerShell directory to where this script is saved +# 5. > ./uploadApplication.ps1 - Workspace + +# Parameters - fill these in before running the script! +# ====================================================== + +# AAD Client ID +# To get this, go to the following page and follow the steps to provision an app +# https://dev.powerbi.com/apps +# ensure that you have the following fields: +# App Type: Native app +# Redirect URL: urn:ietf:wg:oauth:2.0:oob +# Level of access: check all boxes + +$clientId = " FILL ME IN " + +# Report Folder +# Local Folder which has the PBIX files. The folder has to be created and PBIX files has to be placed in that +# Default Path is Reports + +$report_path_root = "$PSScriptRoot\Reports" + +# End Parameters ======================================= + +# Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD +function GetAuthToken +{ + if(-not (Get-Module AzureRm.Profile)) { + Import-Module AzureRm.Profile + } + + $redirectUri = "urn:ietf:wg:oauth:2.0:oob" + + $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" + + $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; + + $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority + + $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") + + return $authResult +} + +function get_groups_path($group_id) { + if ($group_id -eq "me") { + return "myorg" + } else { + return "myorg/groups/$group_ID" + } +} + +# PART 1: Authentication +# ================================================================== +$token = GetAuthToken + +Add-Type -AssemblyName System.Net.Http + +# Building Rest API header with authorization token +$auth_header = @{ + 'Content-Type'='application/json' + 'Authorization'=$token.CreateAuthorizationHeader() +} + + +# PART 2: Checking the Workspace if it exists, if not creating it +# ================================================================== + +try +{ + $target_group_name = $Workspace + # Checking if the Workspace already exist that the user can access + $uri = "https://api.powerbi.com/v1.0/myorg/groups?`$filter=name eq '$target_group_name'" + $response = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value + $target_group_id = $response.id + + if(!$target_group_id) { + # Checking if the Workspace exist in the Organization + $uri = "https://api.powerbi.com/v1.0/myorg/admin/groups?`$filter=(name eq '$target_group_name') and (state eq 'Active')" + $response = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value + $target_group_id = $response.id + if (!$target_group_id) { + # Creating the Workspace + $uri = "https://api.powerbi.com/v1.0/myorg/groups" + $body = "{`"name`":`"$target_group_name`"}" + $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $body + $target_group_id = $response.id + } + else { + # TODO: add logic to add the user to the Workspace + "Please add the Service user to the Workspace or try again with the user who has access to the Workspace" + Break + } + } +} catch { + "Could not find or create a group with that name. Please try again" + "More details: " + Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ + Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription + Break +} + + +# PART 3: Copying reports and datasets using Export/Import PBIX APIs +# ================================================================== +$failure_log = @() +$import_jobs = @() +$target_group_path = get_groups_path($target_group_ID) + +$reports = Get-ChildItem $report_path_root + +# import the reports that are built on PBIXes + +Foreach($report in $reports) { + + $report_name = $report.Name + $temp_path = "$report_path_root\$report_name" + + try { + "== Importing $report_name to target workspace" + $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/?datasetDisplayName=$report_name.pbix&nameConflict=CreateOrOverwrite" + + # Here we switch to HttpClient class to help POST the form data for importing PBIX + $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler + $httpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $token.AccessToken); + $packageFileStream = New-Object System.IO.FileStream @($temp_path, [System.IO.FileMode]::Open) + + $contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data" + $contentDispositionHeaderValue.Name = "file0" + $contentDispositionHeaderValue.FileName = $file_name + + $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream + $streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue + + $content = New-Object System.Net.Http.MultipartFormDataContent + $content.Add($streamContent) + + $response = $httpClient.PostAsync($Uri, $content).Result + + if (!$response.IsSuccessStatusCode) { + $responseBody = $response.Content.ReadAsStringAsync().Result + "= This report cannot be imported to target workspace. Skipping..." + $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody + throw [System.Net.Http.HttpRequestException] $errorMessage + } + + # save the import IDs + $import_job_id = (ConvertFrom-JSON($response.Content.ReadAsStringAsync().Result)).id + + # wait for import to complete + $upload_in_progress = $true + while($upload_in_progress) { + $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/$import_job_id" + $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET + + if ($response.importState -eq "Succeeded") { + "Publish succeeded!" + break + } + + if ($response.importState -ne "Publishing") { + "Error: publishing failed, skipping this. More details: " + $response + break + } + + Write-Host -NoNewLine "." + Start-Sleep -s 5 + } + + + } catch [Exception] { + Write-Host $_.Exception + Write-Host "== Error: failed to import PBIX" + Write-Host "= HTTP Status Code:" $_.Exception.Response.StatusCode.value__ + Write-Host "= HTTP Status Description:" $_.Exception.Response.StatusDescription + continue + } +} \ No newline at end of file From 8413805b35b25c012e10a48c403a788db26d6288 Mon Sep 17 00:00:00 2001 From: "VISUALBI\\SHANKARN" Date: Mon, 10 Dec 2018 16:07:11 -0600 Subject: [PATCH 2/6] Updated link for uploadapplication in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a12ced4..4e573c1 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This repo contains samples for calling the Power BI REST APIs using PowerShell. * [Zero-Downtime-Capacity-Scale.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/Zero-Downtime-Capacity-Scale.ps1) - scale Power BI Embedded capacity resource, up or down, with no downtime (i.e. embedded content is available during the scaling process). -* [uploadapplication.ps1] - Upload local Power BI Application to the specified Workspace +* [uploadapplication.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/uploadapplication.ps1) - Upload local Power BI Application to the specified Workspace ## Prerequisites From 1454eb144cc86dbb5b4a0cd0e9d06f7f9f21ba10 Mon Sep 17 00:00:00 2001 From: Shankar Narayanan SGS Date: Sun, 10 Feb 2019 05:45:32 -0600 Subject: [PATCH 3/6] Replaced Invoke-method with Powershell Commandlets. --- uploadapplication.ps1 | 133 +++++------------------------------------- 1 file changed, 14 insertions(+), 119 deletions(-) diff --git a/uploadapplication.ps1 b/uploadapplication.ps1 index 753ddd6..93dfef3 100644 --- a/uploadapplication.ps1 +++ b/uploadapplication.ps1 @@ -8,24 +8,10 @@ param ( # Instructions: # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) -# and the Azure PowerShell cmdlets (Install-Module AzureRM) +# and Azure PowerShell cmdlets (Install-Module AzureRM) and the Microsoft Power BI Cmdlets (https://docs.microsoft.com/en-us/powershell/power-bi/overview) # 2. Run PowerShell as an administrator -# 3. Follow the instructions below to fill in the client ID -# 4. Change PowerShell directory to where this script is saved -# 5. > ./uploadApplication.ps1 - Workspace - -# Parameters - fill these in before running the script! -# ====================================================== - -# AAD Client ID -# To get this, go to the following page and follow the steps to provision an app -# https://dev.powerbi.com/apps -# ensure that you have the following fields: -# App Type: Native app -# Redirect URL: urn:ietf:wg:oauth:2.0:oob -# Level of access: check all boxes - -$clientId = " FILL ME IN " +# 3. Change PowerShell directory to where this script is saved +# 4. > ./uploadApplication.ps1 - Workspace # Report Folder # Local Folder which has the PBIX files. The folder has to be created and PBIX files has to be placed in that @@ -35,45 +21,12 @@ $report_path_root = "$PSScriptRoot\Reports" # End Parameters ======================================= -# Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD -function GetAuthToken -{ - if(-not (Get-Module AzureRm.Profile)) { - Import-Module AzureRm.Profile - } - - $redirectUri = "urn:ietf:wg:oauth:2.0:oob" - - $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" - - $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; - - $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority - - $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") - - return $authResult -} - -function get_groups_path($group_id) { - if ($group_id -eq "me") { - return "myorg" - } else { - return "myorg/groups/$group_ID" - } -} - # PART 1: Authentication # ================================================================== -$token = GetAuthToken - -Add-Type -AssemblyName System.Net.Http +Connect-PowerBIServiceAccount -# Building Rest API header with authorization token -$auth_header = @{ - 'Content-Type'='application/json' - 'Authorization'=$token.CreateAuthorizationHeader() -} +# Getting Header with Token +$auth_header = Get-PowerBIAccessToken # PART 2: Checking the Workspace if it exists, if not creating it @@ -83,20 +36,17 @@ try { $target_group_name = $Workspace # Checking if the Workspace already exist that the user can access - $uri = "https://api.powerbi.com/v1.0/myorg/groups?`$filter=name eq '$target_group_name'" - $response = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value + $reponse = Get-PowerBIWorkspace -Name "$target_group_name" -Scope Individual $target_group_id = $response.id if(!$target_group_id) { # Checking if the Workspace exist in the Organization - $uri = "https://api.powerbi.com/v1.0/myorg/admin/groups?`$filter=(name eq '$target_group_name') and (state eq 'Active')" - $response = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value + $reponse = Get-PowerBIWorkspace -Name "$target_group_name" -Scope Organization $target_group_id = $response.id if (!$target_group_id) { # Creating the Workspace - $uri = "https://api.powerbi.com/v1.0/myorg/groups" $body = "{`"name`":`"$target_group_name`"}" - $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $body + $response = Invoke-PowerBIRestMethod -Url 'groups' –Headers $auth_header –Method POST -Body $body $target_group_id = $response.id } else { @@ -108,85 +58,30 @@ try } catch { "Could not find or create a group with that name. Please try again" "More details: " - Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ - Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription + Write-Host $_.Exception + Write-Host Resolve-PowerBIError -Last Break } # PART 3: Copying reports and datasets using Export/Import PBIX APIs # ================================================================== -$failure_log = @() -$import_jobs = @() -$target_group_path = get_groups_path($target_group_ID) $reports = Get-ChildItem $report_path_root # import the reports that are built on PBIXes - Foreach($report in $reports) { - + $report_name = $report.Name $temp_path = "$report_path_root\$report_name" try { - "== Importing $report_name to target workspace" - $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/?datasetDisplayName=$report_name.pbix&nameConflict=CreateOrOverwrite" - - # Here we switch to HttpClient class to help POST the form data for importing PBIX - $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler - $httpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $token.AccessToken); - $packageFileStream = New-Object System.IO.FileStream @($temp_path, [System.IO.FileMode]::Open) - - $contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data" - $contentDispositionHeaderValue.Name = "file0" - $contentDispositionHeaderValue.FileName = $file_name - - $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream - $streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue - - $content = New-Object System.Net.Http.MultipartFormDataContent - $content.Add($streamContent) - - $response = $httpClient.PostAsync($Uri, $content).Result - - if (!$response.IsSuccessStatusCode) { - $responseBody = $response.Content.ReadAsStringAsync().Result - "= This report cannot be imported to target workspace. Skipping..." - $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody - throw [System.Net.Http.HttpRequestException] $errorMessage - } - - # save the import IDs - $import_job_id = (ConvertFrom-JSON($response.Content.ReadAsStringAsync().Result)).id - - # wait for import to complete - $upload_in_progress = $true - while($upload_in_progress) { - $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/$import_job_id" - $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET - - if ($response.importState -eq "Succeeded") { - "Publish succeeded!" - break - } - - if ($response.importState -ne "Publishing") { - "Error: publishing failed, skipping this. More details: " - $response - break - } - - Write-Host -NoNewLine "." - Start-Sleep -s 5 - } - + New-PowerBIReport -Path '$temp_path' -Name '$report_name' -ConflictAction CreateOrOverwrite -WorkspaceId '$target_group_id' } catch [Exception] { Write-Host $_.Exception Write-Host "== Error: failed to import PBIX" - Write-Host "= HTTP Status Code:" $_.Exception.Response.StatusCode.value__ - Write-Host "= HTTP Status Description:" $_.Exception.Response.StatusDescription + Write-Host Resolve-PowerBIError -Last continue } } \ No newline at end of file From b9c2d41a14ed87e214b7ec42f51c6e666596c8d8 Mon Sep 17 00:00:00 2001 From: Shankar Narayanan SGS Date: Thu, 28 Feb 2019 21:11:08 -0600 Subject: [PATCH 4/6] Added Add-User-All-Workspace.ps1 --- Add-User-All-Workspace.ps1 | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Add-User-All-Workspace.ps1 diff --git a/Add-User-All-Workspace.ps1 b/Add-User-All-Workspace.ps1 new file mode 100644 index 0000000..b985b5b --- /dev/null +++ b/Add-User-All-Workspace.ps1 @@ -0,0 +1,41 @@ +# This script adds the specified user to +# the Workspace mentioned. If no Workspace +# is mentioned, it would add to all the Workspaces + +[cmdletbinding()] +param ( + [Parameter(Mandatory=$true)][string]$UserEmail, + [Parameter][string]$Workspace, + [Parameter][string]$AccessRight +) + +# Instructions: +# 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) +# and the PowerShell cmdlets (Install-Module -Name MicrosoftPowerBIMgmt) +# 2. Run PowerShell as an administrator +# 3. Change PowerShell directory to where this script is saved +# 4. > ./Add-User-All-Workspace.ps1 + +# Authentication and Header +Connect-PowerBIServiceAccount +$headers = Get-PowerBIAccessToken + +# Defaults to Admin is access right is not specified +if(!$AccessRight) { + $AccessRight = 'Admin' +} + +# If a Workspace is specified, if not all the available Workspace is taken +if($Workspace) { + $Workspace = Get-PowerBIWorkspace -Scope Organization -Name $Workspace + $target_group_id = $Workspace.Id + Add-PowerBIWorkspaceUser -Scope Organization -Id $target_group_id -UserEmailAddress $UserEmail -AccessRight $AccessRight +} +else { + $Workspaces = Get-PowerBIWorkspace -Scope Organization -Filter "Type eq 'Workspace'" + Foreach($Workspace in $Workspaces) { + Write-Host $Workspace.Name + $target_group_id = $Workspace.Id + Add-PowerBIWorkspaceUser -Scope Organization -Id $target_group_id -UserEmailAddress $UserEmail -AccessRight $AccessRight + } +} From 493aaeffdbc1510309487246fed0d986fd3773d7 Mon Sep 17 00:00:00 2001 From: Shankar Narayanan SGS Date: Thu, 28 Feb 2019 21:14:25 -0600 Subject: [PATCH 5/6] Added Exception Handling --- Add-User-All-Workspace.ps1 | 43 ++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/Add-User-All-Workspace.ps1 b/Add-User-All-Workspace.ps1 index b985b5b..ae95ac6 100644 --- a/Add-User-All-Workspace.ps1 +++ b/Add-User-All-Workspace.ps1 @@ -16,26 +16,33 @@ param ( # 3. Change PowerShell directory to where this script is saved # 4. > ./Add-User-All-Workspace.ps1 -# Authentication and Header -Connect-PowerBIServiceAccount -$headers = Get-PowerBIAccessToken +try { -# Defaults to Admin is access right is not specified -if(!$AccessRight) { - $AccessRight = 'Admin' -} + # Authentication and Header + Connect-PowerBIServiceAccount + $headers = Get-PowerBIAccessToken -# If a Workspace is specified, if not all the available Workspace is taken -if($Workspace) { - $Workspace = Get-PowerBIWorkspace -Scope Organization -Name $Workspace - $target_group_id = $Workspace.Id - Add-PowerBIWorkspaceUser -Scope Organization -Id $target_group_id -UserEmailAddress $UserEmail -AccessRight $AccessRight -} -else { - $Workspaces = Get-PowerBIWorkspace -Scope Organization -Filter "Type eq 'Workspace'" - Foreach($Workspace in $Workspaces) { - Write-Host $Workspace.Name + # Defaults to Admin is access right is not specified + if(!$AccessRight) { + $AccessRight = 'Admin' + } + + # If a Workspace is specified, if not all the available Workspace is taken + if($Workspace) { + $Workspace = Get-PowerBIWorkspace -Scope Organization -Name $Workspace $target_group_id = $Workspace.Id Add-PowerBIWorkspaceUser -Scope Organization -Id $target_group_id -UserEmailAddress $UserEmail -AccessRight $AccessRight } -} + else { + $Workspaces = Get-PowerBIWorkspace -Scope Organization -Filter "Type eq 'Workspace'" + Foreach($Workspace in $Workspaces) { + Write-Host $Workspace.Name + $target_group_id = $Workspace.Id + Add-PowerBIWorkspaceUser -Scope Organization -Id $target_group_id -UserEmailAddress $UserEmail -AccessRight $AccessRight + } + } +} catch { + Write-Host $_.Exception + Write-Host Resolve-PowerBIError -Last + Break +} \ No newline at end of file From a108696daef02819741929e72bd10826e8549e3a Mon Sep 17 00:00:00 2001 From: Shankar Narayanan SGS Date: Thu, 28 Feb 2019 21:20:29 -0600 Subject: [PATCH 6/6] updated README.md to reflect Add-User-All-Workspace --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e573c1..935ab6a 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,11 @@ This repo contains samples for calling the Power BI REST APIs using PowerShell. * [uploadapplication.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/uploadapplication.ps1) - Upload local Power BI Application to the specified Workspace +* [Add-User-All-Workspace.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/Add-User-All-Workspace.ps1) - Add specified user to mentioned or all the Workspace + ## Prerequisites -To run the scripts in this repo, please install [PowerShell](https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) and the [Azure Resource Manager PowerShell cmdlets](https://www.powershellgallery.com/packages/AzureRM/). +To run the scripts in this repo, please install [PowerShell](https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell), [Azure Resource Manager PowerShell cmdlets](https://www.powershellgallery.com/packages/AzureRM/) and the [Microsoft Power BI Cmdlets](https://docs.microsoft.com/en-us/powershell/power-bi/overview) . ## Contributing