├── LICENSE ├── README.md ├── Zero-Downtime-Capacity-Scale.ps1 ├── bindtogateway.ps1 ├── copyWorkspace.ps1 ├── manageRefresh.ps1 ├── rebindReport.ps1 └── takeover-dataset.ps1 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | languages: 3 | - powershell 4 | products: 5 | - power-bi 6 | page_type: sample 7 | description: "Samples for calling the Power BI REST APIs using PowerShell." 8 | --- 9 | 10 | # Microsoft Power BI PowerShell samples 11 | 12 | ## Introduction 13 | 14 | This repo contains samples for calling the Power BI REST APIs using PowerShell. Each PowerShell script is self-documenting. 15 | 16 | * [manageRefresh.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/manageRefresh.ps1) - trigger scheduled refresh and check refresh history 17 | 18 | * [rebindReport.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/rebindReport.ps1) - clone a report in the Power BI service and rebind it to a different dataset 19 | 20 | * [copyWorkspace.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/copyWorkspace.ps1) - duplicate a workpsace in the Power BI service 21 | 22 | * [bindtogateway.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/bindtogateway.ps1) - Binds a dataset to a new gateway. 23 | 24 | * [takeover-dataset.ps1](https://github.com/Azure-Samples/powerbi-powershell/blob/master/takeover-dataset.ps1) - Takes ownership of a dataset to your account. 25 | 26 | * [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). 27 | 28 | ## Prerequisites 29 | 30 | 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/). 31 | 32 | ## Contributing 33 | 34 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 35 | -------------------------------------------------------------------------------- /Zero-Downtime-Capacity-Scale.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API and ARM REST API to programmatically scale capacity resource with no downtime (i.e. embedded content is available during the scaling process). 2 | # It also provides an option to reassign workspaces from one capacity resource to another. 3 | # The procedure creates a temporary capacity resource and reassigns the workspaces to it during the scaling process. 4 | # Once the procedure is completed, the workspaces are assigned back to the original capacity resource and the temporary capacity resource is deleted. 5 | # 6 | # 7 | # MAIN TEMP 8 | # ========== ========== 9 | # | SKU-X | | TEMPORARY| 10 | # STEP 1 - Create temporary capacity | | | CAPACITY | 11 | # |WORKSPACES| | | 12 | # ========== ========== 13 | # 14 | # ========== ========== 15 | # | | | TEMPORARY| 16 | # STEP 2 - Reassign workspaces to temporary capacity| SKU-X |--------->| CAPACITY,| 17 | # | | |WORKSPACES| 18 | # ========== ========== 19 | # 20 | # ========== ========== 21 | # | | | TEMPORARY| 22 | # STEP 3 - Scale main capacity | SCALING | | CAPACITY,| 23 | # | | |WORKSPACES| 24 | # ========== ========== 25 | # 26 | # ========== ========== 27 | # | SKU-Y | | TEMPORARY| 28 | # STEP 4 - Assign workspaces back to main capacity | |<---------| CAPACITY | 29 | # |WORKSPACES| | | 30 | # ========== ========== 31 | # 32 | # ========== ========== 33 | # | SKU-Y | | | 34 | # STEP 5 - Delete temporary capacity | | | DELETED | 35 | # |WORKSPACES| | | 36 | # ========== ========== 37 | 38 | # For more information, see the accompanying blog post: 39 | # TODO : Add link to blog 40 | 41 | # Instructions: 42 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell), and the Azure PowerShell cmdlets (Install-Module AzureRM) 43 | # 2. Run PowerShell as an administrator 44 | # 3. Follow the instructions below to fill in the client ID 45 | # 4. Change PowerShell directory to where this script is saved 46 | # 5. Run Login-AzureRmAccount (In order to be able to run the script, the user should have an Azure RBAC 'owner' role, or any other Azure RBAC role with write permissions on the resource) 47 | # 6. Run the script with params 48 | 49 | # Scale Up example: 50 | # .\Zero-Downtime-Capacity-Scale.ps1 -CapacityName 'democap1' -CapacityResourceGroup 'demorg' -TargetSku A3 51 | # 52 | # Workspaces Migration example: 53 | # .\Zero-Downtime-Capacity-Scale.ps1 -CapacityName 'democap1' -CapacityResourceGroup 'demorg' -AssignWorkspacesOnly $true -SourceCapacityName 'democap2' -SourceCapacityResourceGroup 'demorg' 54 | 55 | # Parameters - fill these in before running the script! 56 | # ====================================================== 57 | 58 | # AAD Client ID: 59 | # To get this, go to the following page and follow the steps to register an app 60 | # https://app.powerbi.com/embedsetup/AppOwnsData 61 | # To get the sample to work, ensure that you have the following fields: 62 | # App Type: Native app 63 | # Redirect URL: urn:ietf:wg:oauth:2.0:oob 64 | # Level of access: check all boxes 65 | 66 | [CmdletBinding()] 67 | Param( 68 | [Parameter(Mandatory=$TRUE, HelpMessage="Name of capacity for scaling or target for workspaces migration.")] 69 | [string]$CapacityName, 70 | 71 | [Parameter(Mandatory=$TRUE, HelpMessage="ResourceGroup of capacity for scaling or target for workspaces migration")] 72 | [string]$CapacityResourceGroup, 73 | 74 | [Parameter(Mandatory=$False, HelpMessage="True if you want to assign all workspaces from srouce capacity only, provide SourceCapacityName and SourceCapacityResourceGroup params")] 75 | [bool]$AssignWorkspacesOnly = $FALSE, 76 | 77 | [Parameter(Mandatory=$FALSE, HelpMessage="Target SKU for scaling, e.g. A3")] 78 | [string]$TargetSku, 79 | 80 | [Parameter(Mandatory=$False, HelpMessage="Name of source capacity for workspaces migration.")] 81 | [string]$SourceCapacityName, 82 | 83 | [Parameter(Mandatory=$False, HelpMessage="ResourceGroup of source capacity for workspaces migration.")] 84 | [string]$SourceCapacityResourceGroup, 85 | 86 | [Parameter(Mandatory=$False, HelpMessage="User Name")] 87 | [string]$username, 88 | 89 | [Parameter(Mandatory=$False, HelpMessage="Password")] 90 | [string]$Password 91 | 92 | ) 93 | 94 | # ===================================================== 95 | # $clientId = "FILL ME IN" 96 | # ===================================================== 97 | 98 | 99 | $apiUri = "https://api.powerbi.com/v1.0/myorg/" 100 | 101 | # ===================================================== 102 | # Get authentication token for PowerBI API 103 | FUNCTION GetAuthToken 104 | { 105 | Import-Module AzureRm 106 | 107 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 108 | 109 | $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" 110 | 111 | $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; 112 | 113 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 114 | 115 | IF ($username -ne "" -and $Password -ne "") 116 | { 117 | $creds = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $Username,$Password 118 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $creds) 119 | } 120 | ELSE 121 | { 122 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, 'Always') 123 | } 124 | 125 | return $authResult 126 | } 127 | 128 | $token = GetAuthToken 129 | 130 | # ===================================================== 131 | # Building Rest API header with authorization token 132 | $auth_header = @{ 133 | 'Content-Type'='application/json' 134 | 'Authorization'=$token.CreateAuthorizationHeader() 135 | } 136 | 137 | # ===================================================== 138 | # Helper function used for gettting the capacity object ID by capacity Name 139 | FUNCTION GetCapacityObjectID($capacitiesList, $capacity_name) 140 | { 141 | $done = $False 142 | 143 | # loop over capacitis list and find the right capacity by name 144 | $capacitiesList.value | ForEach-Object -Process { 145 | # Find main capacity ID 146 | if ($_.DisplayName -eq $capacity_name) 147 | { 148 | Write-Host ">>> Object ID for" $capacity_name "is" $_.id 149 | $done = $True 150 | return $_.id 151 | } 152 | } 153 | 154 | # If capacity was not found then print error and exit 155 | IF ($done -ne $True) { 156 | $errmsg = "Capacity " + $capacity_name + " object ID was not found!" 157 | Write-Error $errmsg 158 | Break Script 159 | } 160 | } 161 | 162 | # ===================================================== 163 | # Helper function used for assigning workspaces from source to target capacity 164 | FUNCTION AssignWorkspacesToCapacity($source_capacity_objectid, $target_capacity_objectid) 165 | { 166 | $getCapacityGroupsUri = $apiUri + "groups?$" + "filter=capacityId eq " + "'$source_capacity_objectid'" 167 | $capacityWorkspaces = Invoke-RestMethod -Method GET -Headers $auth_header -Uri $getCapacityGroupsUri 168 | 169 | # Assign workspaces to temporary capacity 170 | $capacityWorkspaces.value | ForEach-Object -Process { 171 | Write-Host ">>> Assigning workspace Name:" $_.name " Id:" $_.id "to capacity id:" $target_capacity_objectid 172 | $assignToCapacityUri = $apiUri + "groups/" + $_.id + "/AssignToCapacity" 173 | $assignToCapacityBody = @{capacityId=$target_capacity_objectid} | ConvertTo-Json 174 | Invoke-RestMethod -Method Post -Headers $auth_header -Uri $assignToCapacityUri -Body $assignToCapacityBody -ContentType 'application/json' 175 | 176 | # Validate workspace to capacity assignment status was completed successfully, if not then exit script 177 | DO 178 | { 179 | $assignToCapacityStatusUri = $apiUri + "groups/" + $_.id + "/CapacityAssignmentStatus" 180 | $status = Invoke-RestMethod -Method Get -Headers $auth_header -Uri $assignToCapacityStatusUri 181 | 182 | # Exit script if workspace assignment has failed 183 | IF ($status.status -eq 'AssignmentFailed') 184 | { 185 | $errmsg = "workspace " + $_.id + " assignment has failed!, script will stop." 186 | Break Script 187 | } 188 | 189 | Start-Sleep -Milliseconds 200 190 | 191 | Write-Host ">>> Assigning workspace Id:" $_.id "to capacity id:" $target_capacity_objectid "Status:" $status.status 192 | } while ($status.status -ne 'CompletedSuccessfully') 193 | } 194 | 195 | $getCapacityGroupsUri = $apiUri + "groups?$" + "filter=capacityId eq " + "'$target_capacity_objectid'" 196 | $capacityWorkspaces = Invoke-RestMethod -Method GET -Headers $auth_header -Uri $getCapacityGroupsUri 197 | 198 | return $capacityWorkspaces 199 | } 200 | 201 | # ===================================================== 202 | # Helper function used for validation capacity in Active state 203 | FUNCTION ValidateCapacityInActiveState($capacity_name, $resource_group) 204 | { 205 | # Get capacity and validate its in active state 206 | $getCapacityResult = Get-AzureRmPowerBIEmbeddedCapacity -Name $capacity_name -ResourceGroup $resource_group 207 | 208 | IF (!$getCapacityResult -OR $getCapacityResult -eq "") 209 | { 210 | $errmsg = "Capacity " + $capacity_name +" was not found!" 211 | Write-Error -Message $errmsg 212 | Break Script 213 | } 214 | ELSEIF ($getCapacityResult.State.ToString() -ne "Succeeded") 215 | { 216 | $errmsg = "Capacity " + $capacity_name + " is not in active state!" 217 | Write-Error $errmsg 218 | Break Script 219 | } 220 | 221 | return $getCapacityResult 222 | } 223 | 224 | # Start watch to measure E2E time duration 225 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 226 | 227 | # Get and Validate main capacity is in active state 228 | $mainCapacity = ValidateCapacityInActiveState $CapacityName $CapacityResourceGroup 229 | 230 | # Check if script execution is for assigning workspaces only 231 | IF ($AssignWorkspacesOnly -ne $TRUE) 232 | { 233 | # Check if user is a capacity administrator, if not exist script 234 | $context = Get-AzureRmContext 235 | $isUserAdminOnCapacity = $False 236 | $mainCapacity.Administrator | ForEach-Object -Process { 237 | IF ($_ -eq $context.Account.Id) 238 | { 239 | $isUserAdminOnCapacity = $TRUE 240 | } 241 | } 242 | 243 | IF ($isUserAdminOnCapacity -eq $False) 244 | { 245 | $errmsg = "User is not capacity administrator!" 246 | Write-Error $errmsg 247 | Break Script 248 | } 249 | 250 | # Check if Current SKU is equal to main SKU 251 | IF ($mainCapacity.Sku -eq $TargetSku) 252 | { 253 | Write-Host "Current SKU is equal to the target SKU, No scale is needed!" 254 | Break Script 255 | } 256 | 257 | Write-Host 258 | Write-Host "========================================================================================================================" -ForegroundColor DarkGreen 259 | Write-Host " SCALING CAPACITY FROM" $mainCapacity.Sku "To" $TargetSku -ForegroundColor DarkGreen 260 | Write-Host "========================================================================================================================" -ForegroundColor DarkGreen 261 | Write-Host 262 | Write-Host ">>> Capacity" $CapacityName "is available and ready for scaling!" 263 | 264 | # Create new temporary capacity to be used for scale 265 | $guid = New-Guid 266 | $temporaryCapacityName = 'tmpcapacity' + $guid.ToString().Replace('-','s').ToLowerInvariant() 267 | $temporarycapacityResourceGroup = $mainCapacity.ResourceGroup 268 | 269 | Write-Host 270 | Write-Host ">>> STEP 1 - Creating a temporary capacity name:"$temporaryCapacityName 271 | $newcap = New-AzureRmPowerBIEmbeddedCapacity -ResourceGroupName $mainCapacity.ResourceGroup -Name $temporaryCapacityName -Location $mainCapacity.Location -Sku $TargetSku -Administrator $mainCapacity.Administrator 272 | 273 | # Check if new capacity provisioning succeeded 274 | IF (!$newcap -OR $newcap.State.ToString() -ne 'Succeeded') 275 | { 276 | Remove-AzureRmPowerBIEmbeddedCapacity -Name $temporaryCapacityName -ResourceGroupName $temporarycapacityResourceGroup 277 | $errmsg = "Try to remove temporary capacity due to some failure while provisioning!, Please restart script!" 278 | Write-Error -Message $errmsg 279 | Break Script 280 | } 281 | 282 | # Get capacities from PowerBI to find the capacities ID 283 | $getCapacityUri = $apiUri + "capacities" 284 | $capacitiesList = Invoke-RestMethod -Method Get -Headers $auth_header -Uri $getCapacityUri 285 | $sourceCapacityObjectId = GetCapacityObjectID $capacitiesList $CapacityName 286 | $targetCapacityObjectId = GetCapacityObjectID $capacitiesList $temporaryCapacityName 287 | Write-Host ">>> STEP 1 - Completed!" 288 | 289 | Write-Host 290 | Write-Host ">>> STEP 2 - Assigning workspaces" 291 | $assignedMainCapacityWorkspaces = AssignWorkspacesToCapacity $sourceCapacityObjectId $targetCapacityObjectId 292 | Write-Host ">>> STEP 2 Completed!" 293 | 294 | Write-Host 295 | Write-Host ">>> STEP 3 - Scaling capacity " $CapacityName "to" $targetSku 296 | Update-AzureRmPowerBIEmbeddedCapacity -Name $CapacityName -sku $targetSku 297 | $mainCapacity = ValidateCapacityInActiveState $CapacityName $CapacityResourceGroup 298 | Write-Host ">>> STEP 3 completed!" $CapacityName "to" $targetSku 299 | 300 | Write-Host 301 | Write-Host ">>> STEP 4 - Assigning workspaces to main capacity" 302 | $AssignedTargetCapacityWorkspaces = AssignWorkspacesToCapacity $targetCapacityObjectId $sourceCapacityObjectId 303 | 304 | # validate all workspaces were assigned back to the main capacity 305 | $diff = Compare-Object $AssignedTargetCapacityWorkspaces.value $assignedMainCapacityWorkspaces.value 306 | if ($diff -ne $null) 307 | { 308 | $errmsg = "Something went wrong while assigning workspaces to the main capacity, Please re-execute the script" 309 | Write-Error -Message $errmsg 310 | Break Script 311 | } 312 | Write-Host ">>> STEP 4 Completed!" 313 | 314 | Write-Host 315 | Write-Host ">>> STEP 5 - Delete temporary capacity" 316 | # Delete temporary capacity if it was newly created 317 | Remove-AzureRmPowerBIEmbeddedCapacity -Name $temporaryCapacityName -ResourceGroupName $temporarycapacityResourceGroup 318 | Write-Host ">>> STEP 5 Completed!" 319 | } 320 | ELSE 321 | { 322 | # Get capacities from PowerBI to find the capacities ID 323 | $getCapacityUri = $apiUri + "capacities" 324 | $capacitiesList = Invoke-RestMethod -Method Get -Headers $auth_header -Uri $getCapacityUri 325 | 326 | ValidateCapacityInActiveState $CapacityName $CapacityResourceGroup 327 | Write-Host ">>> Capacity" $CapacityName "is available and ready!" 328 | $sourceCapacityObjectId = GetCapacityObjectID $capacitiesList $SourceCapacityName 329 | 330 | ValidateCapacityInActiveState $SourceCapacityName $SourceCapacityResourceGroup 331 | $targetCapacityObjectId = GetCapacityObjectID $capacitiesList $CapacityName 332 | Write-Host ">>> Capacity" $SourceCapacityName "is available and ready!" 333 | 334 | $assignedcapacities = AssignWorkspacesToCapacity $sourceCapacityObjectId $targetCapacityObjectId 335 | } 336 | 337 | Write-Host 338 | Write-Host "========================================================================================================================" -ForegroundColor DarkGreen 339 | Write-Host " Completed Successfully" -ForegroundColor DarkGreen 340 | Write-Host " Total Duration" -ForegroundColor DarkGreen 341 | Write-Host " "$stopwatch.Elapsed -ForegroundColor DarkGreen 342 | Write-Host "========================================================================================================================" -ForegroundColor DarkGreen 343 | -------------------------------------------------------------------------------- /bindtogateway.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API to progammatically rebind a dataset to 2 | # another gateway. 3 | 4 | # For documentation, please see: 5 | # https://msdn.microsoft.com/en-us/library/mt784650.aspx 6 | 7 | # Instructions: 8 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) 9 | # and the Azure PowerShell cmdlets (Install-Module AzureRM) 10 | # 2. Run PowerShell as an administrator 11 | # 3. Fill in the parameters below 12 | # 4. Change PowerShell directory to where this script is saved 13 | # 5. > ./bindtogateway.ps1 14 | 15 | # Parameters - fill these in before running the script! 16 | # ===================================================== 17 | 18 | $groupId = " FILL ME IN " # the ID of the group (workspace) that hosts the dataset. 19 | $newGatewayId = " FILL ME IN " # the ID of the new gateway 20 | $datasetId = " FILL ME IN " # the ID of dataset to rebind 21 | 22 | # AAD Client ID 23 | # To get this, go to the following page and follow the steps to provision an app 24 | # https://dev.powerbi.com/apps 25 | # To get the sample to work, ensure that you have the following fields: 26 | # App Type: Native app 27 | # Redirect URL: urn:ietf:wg:oauth:2.0:oob 28 | # Level of access: all dataset APIs 29 | $clientId = " FILL ME IN " 30 | 31 | # End Parameters ======================================= 32 | 33 | # Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD 34 | # Install-Module AzureAD 35 | function GetAuthToken 36 | { 37 | if(-not (Get-Module AzureRm.Profile)) { 38 | Import-Module AzureRm.Profile 39 | } 40 | 41 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 42 | 43 | $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" 44 | 45 | $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; 46 | 47 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 48 | 49 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") 50 | 51 | return $authResult 52 | } 53 | 54 | # Get the auth token from AAD 55 | $token = GetAuthToken 56 | 57 | # Building Rest API header with authorization token 58 | $authHeader = @{ 59 | 'Content-Type'='application/json' 60 | 'Authorization'=$token.CreateAuthorizationHeader() 61 | } 62 | 63 | # properly format groups path 64 | $sourceGroupsPath = "" 65 | if ($groupId -eq "me") { 66 | $sourceGroupsPath = "myorg" 67 | } else { 68 | $sourceGroupsPath = "myorg/groups/$groupId" 69 | } 70 | 71 | # POST body 72 | $postParams = @{ 73 | "gatewayObjectId" = "$newGatewayId" 74 | } 75 | 76 | $jsonPostBody = $postParams | ConvertTo-JSON 77 | 78 | # Make the request to bind to a gateway 79 | $uri = "https://api.powerbi.com/v1.0/$sourceGroupsPath/datasets/$datasetId/BindToGateway" 80 | 81 | # Try to bind to a new gateway 82 | try { 83 | Invoke-RestMethod -Uri $uri -Headers $authHeader -Method POST -Body $jsonPostBody -Verbose 84 | } catch { 85 | 86 | $result = $_.Exception.Response.GetResponseStream() 87 | $reader = New-Object System.IO.StreamReader($result) 88 | $reader.BaseStream.Position = 0 89 | $reader.DiscardBufferedData() 90 | $responseBody = $reader.ReadToEnd(); 91 | 92 | # DMTS_CanNotFindMatchingDatasourceInGatewayError means that there is no datasource available in a gateway to bind to. 93 | # we can ignore DMTS_CanNotFindMatchingDatasourceInGatewayError 94 | If(($responseBody).Contains("DMTS_CanNotFindMatchingDatasourceInGatewayError")) 95 | { 96 | Write-Host "Error: No data source available in gateway." 97 | } 98 | elseif($_.Exception.Response.StatusCode.value__ -eq "401") 99 | { 100 | Write-Host "Error: No access to app workspace." 101 | } 102 | elseif($_.Exception.Response.StatusCode.value__ -eq "404") 103 | { 104 | Write-Host "Error: Dataset may be owned by someone else. Call take over API to assume ownership and try again. For more information, see https://msdn.microsoft.com/en-us/library/mt784651.aspx." 105 | } 106 | else 107 | { 108 | Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 109 | Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription 110 | Write-Host "StatusBody:" $responseBody 111 | } 112 | } -------------------------------------------------------------------------------- /copyWorkspace.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API to programmatically duplicate the workspace and all 2 | # its dashboards, reports and datasets. 3 | 4 | # For more information, see the accompanying blog post: 5 | # https://powerbi.microsoft.com/en-us/blog/duplicate-workspaces-using-the-power-bi-rest-apis-a-step-by-step-tutorial/ 6 | 7 | # Instructions: 8 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) 9 | # and the Azure PowerShell cmdlets (Install-Module AzureRM) 10 | # 2. Run PowerShell as an administrator 11 | # 3. Follow the instructions below to fill in the client ID 12 | # 4. Change PowerShell directory to where this script is saved 13 | # 5. > ./copyworkspace.ps1 14 | 15 | # Parameters - fill these in before running the script! 16 | # ====================================================== 17 | 18 | # AAD Client ID 19 | # To get this, go to the following page and follow the steps to provision an app 20 | # https://dev.powerbi.com/apps 21 | # To get the sample to work, ensure that you have the following fields: 22 | # App Type: Native app 23 | # Redirect URL: urn:ietf:wg:oauth:2.0:oob 24 | # Level of access: check all boxes 25 | 26 | $clientId = " FILL ME IN " 27 | 28 | # End Parameters ======================================= 29 | 30 | # TODO: move helper functions into a separate file 31 | # Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD 32 | function GetAuthToken 33 | { 34 | if(-not (Get-Module AzureRm.Profile)) { 35 | Import-Module AzureRm.Profile 36 | } 37 | 38 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 39 | 40 | $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" 41 | 42 | $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; 43 | 44 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 45 | 46 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") 47 | 48 | return $authResult 49 | } 50 | 51 | function get_groups_path($group_id) { 52 | if ($group_id -eq "me") { 53 | return "myorg" 54 | } else { 55 | return "myorg/groups/$group_ID" 56 | } 57 | } 58 | 59 | # PART 1: Authentication 60 | # ================================================================== 61 | $token = GetAuthToken 62 | 63 | Add-Type -AssemblyName System.Net.Http 64 | $temp_path_root = "$PSScriptRoot\pbi-copy-workspace-temp-storage" 65 | 66 | # Building Rest API header with authorization token 67 | $auth_header = @{ 68 | 'Content-Type'='application/json' 69 | 'Authorization'=$token.CreateAuthorizationHeader() 70 | } 71 | 72 | # Prompt for user input 73 | # ================================================================== 74 | # Get the list of groups that the user is a member of 75 | $uri = "https://api.powerbi.com/v1.0/myorg/groups/" 76 | $all_groups = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value 77 | 78 | # Ask for the source workspace name 79 | $source_group_ID = "" 80 | while (!$source_group_ID) { 81 | $source_group_name = Read-Host -Prompt "Enter the name of the workspace you'd like to copy from" 82 | 83 | if($source_group_name -eq "My Workspace") { 84 | $source_group_ID = "me" 85 | break 86 | } 87 | 88 | Foreach ($group in $all_groups) { 89 | if ($group.name -eq $source_group_name) { 90 | if ($group.isReadOnly -eq "True") { 91 | "Invalid choice: you must have edit access to the group" 92 | break 93 | } else { 94 | $source_group_ID = $group.id 95 | break 96 | } 97 | } 98 | } 99 | 100 | if(!$source_group_id) { 101 | "Please try again, making sure to type the exact name of the group" 102 | } 103 | } 104 | 105 | # Ask for the target workspace name 106 | $target_group_ID = "" 107 | while (!$target_group_id) { 108 | try { 109 | $target_group_name = Read-Host -Prompt "Enter the name of the new workspace to be created" 110 | $uri = " https://api.powerbi.com/v1.0/myorg/groups" 111 | $body = "{`"name`":`"$target_group_name`"}" 112 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $body 113 | $target_group_id = $response.id 114 | } catch { 115 | "Could not create a group with that name. Please try again and make sure the name is not already taken" 116 | "More details: " 117 | Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 118 | Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription 119 | continue 120 | } 121 | } 122 | 123 | # PART 3: Copying reports and datasets using Export/Import PBIX APIs 124 | # ================================================================== 125 | $report_ID_mapping = @{} # mapping of old report ID to new report ID 126 | $dataset_ID_mapping = @{} # mapping of old model ID to new model ID 127 | $failure_log = @() 128 | $import_jobs = @() 129 | $source_group_path = get_groups_path($source_group_ID) 130 | $target_group_path = get_groups_path($target_group_ID) 131 | 132 | $uri = "https://api.powerbi.com/v1.0/$source_group_path/reports/" 133 | $reports_json = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET 134 | $reports = $reports_json.value 135 | 136 | # For My Workspace, filter out reports that I don't own - e.g. those shared with me 137 | if ($source_group_ID -eq "me") { 138 | $reports_temp = @() 139 | Foreach($report in $reports) { 140 | if ($report.isOwnedByMe -eq "True") { 141 | $reports_temp += $report 142 | } 143 | } 144 | $reports = $reports_temp 145 | } 146 | 147 | # == Export/import the reports that are built on PBIXes (this step creates the datasets) 148 | # for each report, try exporting and importing the PBIX 149 | New-Item -Path $temp_path_root -ItemType Directory 150 | "=== Exporting PBIX files to copy datasets..." 151 | Foreach($report in $reports) { 152 | 153 | $report_id = $report.id 154 | $dataset_id = $report.datasetId 155 | $report_name = $report.name 156 | $temp_path = "$temp_path_root\$report_name.pbix" 157 | 158 | # only export if this dataset hasn't already been seen 159 | if ($dataset_ID_mapping[$dataset_id]) { 160 | continue 161 | } 162 | 163 | "== Exporting $report_name with id: $report_id to $temp_path" 164 | $uri = "https://api.powerbi.com/v1.0/$source_group_path/reports/$report_id/Export" 165 | try { 166 | Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET -OutFile "$temp_path" 167 | } catch { 168 | Write-Host "= This report and dataset cannot be copied, skipping. This is expected for most workspaces." 169 | continue 170 | } 171 | 172 | try { 173 | "== Importing $report_name to target workspace" 174 | $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/?datasetDisplayName=$report_name.pbix&nameConflict=Abort" 175 | 176 | # Here we switch to HttpClient class to help POST the form data for importing PBIX 177 | $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler 178 | $httpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $token.AccessToken); 179 | $packageFileStream = New-Object System.IO.FileStream @($temp_path, [System.IO.FileMode]::Open) 180 | 181 | $contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data" 182 | $contentDispositionHeaderValue.Name = "file0" 183 | $contentDispositionHeaderValue.FileName = $file_name 184 | 185 | $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream 186 | $streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue 187 | 188 | $content = New-Object System.Net.Http.MultipartFormDataContent 189 | $content.Add($streamContent) 190 | 191 | $response = $httpClient.PostAsync($Uri, $content).Result 192 | 193 | if (!$response.IsSuccessStatusCode) { 194 | $responseBody = $response.Content.ReadAsStringAsync().Result 195 | "= This report cannot be imported to target workspace. Skipping..." 196 | $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody 197 | throw [System.Net.Http.HttpRequestException] $errorMessage 198 | } 199 | 200 | # save the import IDs 201 | $import_job_id = (ConvertFrom-JSON($response.Content.ReadAsStringAsync().Result)).id 202 | 203 | # wait for import to complete 204 | $upload_in_progress = $true 205 | while($upload_in_progress) { 206 | $uri = "https://api.powerbi.com/v1.0/$target_group_path/imports/$import_job_id" 207 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET 208 | 209 | if ($response.importState -eq "Succeeded") { 210 | "Publish succeeded!" 211 | # update the report and dataset mappings 212 | $report_id_mapping[$report_id] = $response.reports[0].id 213 | $dataset_id_mapping[$dataset_id] = $response.datasets[0].id 214 | break 215 | } 216 | 217 | if ($response.importState -ne "Publishing") { 218 | "Error: publishing failed, skipping this. More details: " 219 | $response 220 | break 221 | } 222 | 223 | Write-Host -NoNewLine "." 224 | Start-Sleep -s 5 225 | } 226 | 227 | 228 | } catch [Exception] { 229 | Write-Host $_.Exception 230 | Write-Host "== Error: failed to import PBIX" 231 | Write-Host "= HTTP Status Code:" $_.Exception.Response.StatusCode.value__ 232 | Write-Host "= HTTP Status Description:" $_.Exception.Response.StatusDescription 233 | continue 234 | } 235 | } 236 | 237 | 238 | # PART 4: Clone the remainder of the reports 239 | # ================================================================== 240 | "=== Cloning reports" 241 | Foreach($report in $reports) { 242 | $report_name = $report.name 243 | $report_id = $report.id 244 | 245 | # Clone report if the underlying dataset already exists in the target workspace, but we haven't moved the report itself yet 246 | $target_dataset_Id = $dataset_id_mapping[$report.datasetId] 247 | if ($target_dataset_Id -and !$report_ID_mapping[$report.id]) { 248 | "== Cloning report $report_name" 249 | $uri = " https://api.powerbi.com/v1.0/$source_group_path/reports/$report_id/Clone" 250 | $body = "{`"name`":`"$report_name`",`"targetWorkspaceId`": `"$target_group_id`", `"targetModelId`": `"$target_dataset_Id`"}" 251 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $body 252 | $report_ID_mapping[$report_id] = $response.id 253 | } else { 254 | $failure_log += $report 255 | } 256 | } 257 | 258 | 259 | # PART 5: Copy dashboards 260 | # ================================================================== 261 | "=== Cloning dashboards" 262 | # get all dashboards in a workspace 263 | $uri = "https://api.powerbi.com/v1.0/$source_group_path/dashboards/" 264 | $dashboards = (Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET).value 265 | 266 | # For My Workspace, filter out dashboards that I don't own - e.g. those shared with me 267 | if ($source_group_ID -eq "me") { 268 | $dashboards_temp = @() 269 | Foreach($dashboard in $dashboards) { 270 | if ($dashboard.isReadOnly -ne "True") { 271 | $dashboards_temp += $dashboard 272 | } 273 | } 274 | $dashboards = $dashboards_temp 275 | } 276 | 277 | Foreach ($dashboard in $dashboards) { 278 | $dashboard_id = $dashboard.id 279 | $dashboard_name = $dashboard.displayName 280 | 281 | "== Cloning dashboard: $dashboard_name" 282 | 283 | # create new dashboard in the target workspace 284 | $uri = "https://api.powerbi.com/v1.0/$target_group_path/dashboards" 285 | $body = "{`"name`":`"$dashboard_name`"}" 286 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $body 287 | $target_dashboard_id = $response.id 288 | 289 | " = Cloning individual tiles..." 290 | # copy over tiles: 291 | $uri = "https://api.powerbi.com/v1.0/$source_group_path/dashboards/$dashboard_id/tiles" 292 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method GET 293 | $tiles = $response.value 294 | Foreach ($tile in $tiles) { 295 | try { 296 | $tile_id = $tile.id 297 | $tile_report_Id = $tile.reportId 298 | $tile_dataset_Id = $tile.datasetId 299 | if ($tile_report_id) { $tile_target_report_id = $report_id_mapping[$tile_report_id] } 300 | if ($tile_dataset_id) { $tile_target_dataset_id = $dataset_id_mapping[$tile_dataset_id] } 301 | 302 | # clone the tile only if a) it is not built on a dataset or b) if it is built on a report and/or dataset that we've moved 303 | if (!$tile_report_id -Or $dataset_id_mapping[$tile_dataset_id]) { 304 | $uri = " https://api.powerbi.com/v1.0/$source_group_path/dashboards/$dashboard_id/tiles/$tile_id/Clone" 305 | $body = @{} 306 | $body["TargetDashboardId"] = $target_dashboard_id 307 | $body["TargetWorkspaceId"] = $target_group_id 308 | if ($tile_report_id) { $body["TargetReportId"] = $tile_target_report_id } 309 | if ($tile_dataset_id) { $body["TargetModelId"] = $tile_target_dataset_id } 310 | $jsonBody = ConvertTo-JSON($body) 311 | $response = Invoke-RestMethod -Uri $uri –Headers $auth_header –Method POST -Body $jsonBody 312 | Write-Host -NoNewLine "." 313 | } else { 314 | $failure_log += $tile 315 | } 316 | 317 | } catch [Exception] { 318 | "Error: skipping tile..." 319 | Write-Host $_.Exception 320 | } 321 | } 322 | "Done!" 323 | } 324 | 325 | "Cleaning up temporary files" 326 | Remove-Item -path $temp_path_root -Recurse -------------------------------------------------------------------------------- /manageRefresh.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API to progammtically trigger a refresh for the dataset 2 | # It then calls the Power BI API to progammatically to get the refresh history for that dataset 3 | # For full documentation on the REST APIs, see: 4 | # https://msdn.microsoft.com/en-us/library/mt203551.aspx 5 | 6 | # Instructions: 7 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) and the Azure PowerShell cmdlets (https://aka.ms/webpi-azps) 8 | # 2. Set up a dataset for refresh in the Power BI service - make sure that the dataset can be 9 | # updated successfully 10 | # 3. Fill in the parameters below 11 | # 4. Run the PowerShell script 12 | 13 | # Parameters - fill these in before running the script! 14 | # ===================================================== 15 | 16 | # An easy way to get group and dataset ID is to go to dataset settings and click on the dataset 17 | # that you'd like to refresh. Once you do, the URL in the address bar will show the group ID and 18 | # dataset ID, in the format: 19 | # app.powerbi.com/groups/{groupID}/settings/datasets/{datasetID} 20 | 21 | $groupID = " FILL ME IN " # the ID of the group that hosts the dataset. Use "me" if this is your My Workspace 22 | $datasetID = " FILL ME IN " # the ID of the dataset that hosts the dataset 23 | 24 | # AAD Client ID 25 | # To get this, go to the following page and follow the steps to provision an app 26 | # https://dev.powerbi.com/apps 27 | # To get the sample to work, ensure that you have the following fields: 28 | # App Type: Native app 29 | # Redirect URL: urn:ietf:wg:oauth:2.0:oob 30 | # Level of access: all dataset APIs 31 | $clientId = " FILL ME IN " 32 | 33 | # End Parameters ======================================= 34 | 35 | # Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD 36 | function GetAuthToken 37 | { 38 | if(-not (Get-Module AzureRm.Profile)) { 39 | Import-Module AzureRm.Profile 40 | } 41 | 42 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 43 | 44 | $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" 45 | 46 | $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; 47 | 48 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 49 | 50 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") 51 | 52 | return $authResult 53 | } 54 | 55 | # Get the auth token from AAD 56 | $token = GetAuthToken 57 | 58 | # Building Rest API header with authorization token 59 | $authHeader = @{ 60 | 'Content-Type'='application/json' 61 | 'Authorization'=$token.CreateAuthorizationHeader() 62 | } 63 | 64 | # properly format groups path 65 | $groupsPath = "" 66 | if ($groupID -eq "me") { 67 | $groupsPath = "myorg" 68 | } else { 69 | $groupsPath = "myorg/groups/$groupID" 70 | } 71 | 72 | # Refresh the dataset 73 | $uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes" 74 | Invoke-RestMethod -Uri $uri –Headers $authHeader –Method POST –Verbose 75 | 76 | # Check the refresh history 77 | $uri = "https://api.powerbi.com/v1.0/$groupsPath/datasets/$datasetID/refreshes" 78 | Invoke-RestMethod -Uri $uri –Headers $authHeader –Method GET –Verbose -------------------------------------------------------------------------------- /rebindReport.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API to progammatically clone a SOURCE report to a 2 | # TARGET report in the Power BI service. The clone can either be based off of the same 3 | # dataset or a new dataset 4 | 5 | # For documentation, please see: 6 | # https://msdn.microsoft.com/en-us/library/mt784674.aspx 7 | 8 | # Instructions: 9 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) 10 | # and the Azure PowerShell cmdlets (Install-Module AzureRM) 11 | # 2. Run PowerShell as an administrator 12 | # 3. Follow the instructions below to fill in the client ID 13 | # 4. Change PowerShell directory to where this script is saved 14 | # 5. > ./rebindReport.ps1 15 | 16 | # Parameters - fill these in before running the script! 17 | # ===================================================== 18 | 19 | # SOURCE report info 20 | # An easy way to get this is to navigate to the report in the Power BI service 21 | # The URL will contain the group and report IDs with the following format: 22 | # app.powerbi.com/groups/{groupID}/report/{reportID} 23 | 24 | $sourceReportGroupId = " FILL ME IN " # the ID of the group (workspace) that hosts the source report. Use "me" if this is your My Workspace 25 | $sourceReportId = " FILL ME IN " # the ID of the source report 26 | 27 | # TARGET report info 28 | # An easy way to get group and dataset ID is to go to dataset settings and click on the dataset 29 | # that you'd like to refresh. Once you do, the URL in the address bar will show the group ID and 30 | # dataset ID, in the format: 31 | # app.powerbi.com/groups/{groupID}/settings/datasets/{datasetID} 32 | 33 | $targetReportName = " FILL ME IN " # what you'd like to name the target report 34 | $targetGroupId = " FILL ME IN " # the ID of the group (workspace) that you'd like to move the report to. Leave this blank if you'd like to clone to the same workspace. Use "me" if this is your My Workspace 35 | $targetDatasetId = " FILL ME IN " # the ID of the dataset that you'd like to rebind the target report to. Leave this blank to have the target report use the same dataset 36 | 37 | # AAD Client ID 38 | # To get this, go to the following page and follow the steps to provision an app 39 | # https://dev.powerbi.com/apps 40 | # To get the sample to work, ensure that you have the following fields: 41 | # App Type: Native app 42 | # Redirect URL: urn:ietf:wg:oauth:2.0:oob 43 | # Level of access: all dataset APIs 44 | $clientId = " FILL ME IN " 45 | 46 | # End Parameters ======================================= 47 | 48 | # Calls the Active Directory Authentication Library (ADAL) to authenticate against AAD 49 | function GetAuthToken 50 | { 51 | if(-not (Get-Module AzureRm.Profile)) { 52 | Import-Module AzureRm.Profile 53 | } 54 | 55 | $redirectUri = "urn:ietf:wg:oauth:2.0:oob" 56 | 57 | $resourceAppIdURI = "https://analysis.windows.net/powerbi/api" 58 | 59 | $authority = "https://login.microsoftonline.com/common/oauth2/authorize"; 60 | 61 | $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority 62 | 63 | $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") 64 | 65 | return $authResult 66 | } 67 | 68 | # Get the auth token from AAD 69 | $token = GetAuthToken 70 | 71 | # Building Rest API header with authorization token 72 | $authHeader = @{ 73 | 'Content-Type'='application/json' 74 | 'Authorization'=$token.CreateAuthorizationHeader() 75 | } 76 | 77 | # properly format groups path 78 | $sourceGroupsPath = "" 79 | if ($sourceReportGroupId -eq "me") { 80 | $sourceGroupsPath = "myorg" 81 | } else { 82 | $sourceGroupsPath = "myorg/groups/$sourceReportGroupId" 83 | } 84 | 85 | # POST body 86 | $postParams = @{ 87 | "Name" = "$targetReportName" 88 | "TargetWorkspaceId" = "$targetGroupId" 89 | "TargetModelId" = "$targetDatasetId" 90 | } 91 | 92 | $jsonPostBody = $postParams | ConvertTo-JSON 93 | 94 | # Make the request to clone the report 95 | $uri = "https://api.powerbi.com/v1.0/$sourceGroupsPath/reports/$sourceReportId/clone" 96 | Invoke-RestMethod -Uri $uri –Headers $authHeader –Method POST -Body $jsonPostBody –Verbose -------------------------------------------------------------------------------- /takeover-dataset.ps1: -------------------------------------------------------------------------------- 1 | # This sample script calls the Power BI API to progammatically take over a dataset. 2 | 3 | # For documentation, please see: 4 | # https://docs.microsoft.com/rest/api/power-bi/datasets/takeoveringroup 5 | 6 | # Instructions: 7 | # 1. Install PowerShell (https://msdn.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell) 8 | # and the Power BI PowerShell cmdlets (Install-Module MicrosoftPowerBIMgmt) 9 | # https://docs.microsoft.com/en-us/powershell/power-bi/overview?view=powerbi-ps 10 | # 2. Run PowerShell as an administrator 11 | # 3. Fill in the parameters below 12 | # 4. Change PowerShell directory to where this script is saved 13 | # 5. > ./takeover-dataaset.ps1 14 | 15 | # Parameters - fill these in before running the script! 16 | # ===================================================== 17 | 18 | $groupId = " FILL ME IN " # the ID of the group (workspace) that hosts the dataset. 19 | $datasetId = " FILL ME IN " # the ID of dataset to rebind 20 | 21 | # End Parameters ======================================= 22 | 23 | # Login to the Power BI service with your Power BI credentials 24 | Login-PowerBI 25 | 26 | # Make the request to bind to a gateway 27 | $uri = "groups/$groupId/datasets/$datasetId/Default.TakeOver" 28 | 29 | # Try to bind to a new gateway 30 | try { 31 | Invoke-PowerBIRestMethod -Url $uri -Method Post 32 | 33 | # Show error if we had a non-terminating error which catch won't catch 34 | if (-Not $?) 35 | { 36 | $errmsg = Resolve-PowerBIError -Last 37 | $errmsg.Message 38 | } 39 | } catch { 40 | 41 | $errmsg = Resolve-PowerBIError -Last 42 | $errmsg.Message 43 | } --------------------------------------------------------------------------------