├── Demos ├── COVID-US.pbix ├── Copy-Report-to-New-Workspace.ps1 ├── Create-Workspace-Inventory-Report.ps1 ├── Create-Workspace-and-Add-Workspace-Users.ps1 ├── Create-Workspace.ps1 ├── Data-Gateway-Demos │ ├── Add-Service-Principal-as-Gateway-Admin.ps1 │ ├── Get-Data-Gateways.ps1 │ └── Get-Gateway-Datasources-and-Datasource-Users.ps1 ├── Delete-Dataset.ps1 ├── Export-Activity-Events.ps1 ├── Get-All-Workspaces-in-Tenant.ps1 ├── Import-Dataflow.ps1 ├── Import-PBIX-File.ps1 ├── Login-User-Interactively.ps1 ├── Login-User-Unattended.ps1 ├── Patch-ADLS-Datasource-Credentials-and-Refresh.ps1 ├── Patch-Anonymous-Datasource-Credentials-and-Refresh.ps1 ├── Patch-OAuth-Datasource-Credentials-and-Refresh.ps1 ├── Patch-Sql-Datasource-Credentials-and-Refresh.ps1 ├── Programming-PowerShell-Arrays.ps1 ├── Programming-PowerShell-Dictionaries.ps1 ├── Programming-PowerShell-Text-Files.ps1 ├── SalesByState.pbix ├── Service-Principal-Demos │ ├── Add-Service-Principal-As-Workspace-Admin.ps1 │ ├── Login-As-Service-Principal-With-Certificate.ps1 │ ├── Login-As-Service-Principal.ps1 │ ├── Takeover-Dataset-as-Service-Principal-and-Refresh-Sql-Datasource.ps1 │ └── Takeover-Gateway-Dataset-and-Refresh.ps1 ├── Update-Connection-Details-for-Sql-Datasource.ps1 ├── Update-Dataset-Parameters.ps1 └── model.json ├── README.md ├── Scripts ├── COVID-US.pbix ├── ReadMe.txt └── SalesByState.pbix ├── Solution ├── Exercise01-Final.ps1 ├── Exercise01-Part01.ps1 ├── Exercise01-Part02.ps1 ├── Exercise02-Final.ps1 ├── Exercise02-Part01.ps1 ├── Exercise02-Part02.ps1 ├── Exercise03-Final.ps1 ├── Exercise03-Part01.ps1 ├── Exercise04-Final.ps1 ├── Exercise05-Final.ps1 ├── Exercise05-Part01.ps1 ├── Exercise05-Part02.ps1 ├── Exercise05-Part03.ps1 ├── Exercise06-Final.ps1 ├── Exercise06-Part1.ps1 ├── Exercise06-Part2.ps1 ├── Exercise06-Part3.ps1 ├── Exercise07-Final.ps1 ├── Exercise07-Part01.ps1 ├── Exercise07-Part02.ps1 └── Exercise08-Final.ps1 ├── Tutorial.docx └── Tutorial.pdf /Demos/COVID-US.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Demos/COVID-US.pbix -------------------------------------------------------------------------------- /Demos/Copy-Report-to-New-Workspace.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $sourceWorkspaceName = "Dev Camp Labs" 6 | $reportName = "COVID-US" 7 | 8 | $targetWorkspaceName = "Dev Camp Demos" 9 | 10 | $sourceWorkspace = Get-PowerBIWorkspace -Name $sourceWorkspaceName 11 | $targetWorkspace = Get-PowerBIWorkspace -Name $targetWorkspaceName 12 | 13 | 14 | Write-Host "Getting metadata for report $reportName..." 15 | $report = Get-PowerBIReport -WorkspaceId $sourceWorkspace.Id -Name $reportName 16 | $reportId = $report.Id 17 | 18 | Write-Host "Exporting report from source workspace to temp PBIX file..." 19 | New-Item -ItemType Directory -Force -Path "$PSScriptRoot/temp" | Out-Null 20 | $reportTempFilePath = "$PSScriptRoot/temp/$reportName.pbix" 21 | Export-PowerBIReport -WorkspaceId $sourceWorkspace.Id -Id $reportId -OutFile $reportTempFilePath 22 | 23 | Write-Host "Importing report from PBIX file into target workspace..." 24 | New-PowerBIReport -Path $reportTempFilePath -WorkspaceId $targetWorkspace.Id -Name $reportName -ConflictAction CreateOrOverwrite | Out-Null 25 | 26 | Write-Host "Deleting temp file...." 27 | Remove-Item -Path $reportTempFilePath 28 | 29 | Write-Host 30 | Write-Host "Report copy operation complete" 31 | -------------------------------------------------------------------------------- /Demos/Create-Workspace-Inventory-Report.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName -Scope Organization -Include All 8 | $workspaceId = $workspace.Id 9 | 10 | $outputFile = "$PSScriptRoot/WorkspaceReport.txt" 11 | "Inventory Report for $workspaceName ($workspaceId)" | Out-File $outputFile 12 | 13 | "`n- Users:" | Out-File $outputFile -Append 14 | foreach($user in $workspace.Users){ 15 | $userId = $user.Identifier 16 | $userAccessRight = $user.AccessRight 17 | " - $userId ($userAccessRight)" | Out-File $outputFile -Append 18 | } 19 | 20 | "`n- Datasets:" | Out-File $outputFile -Append 21 | foreach($dataset in $workspace.Datasets){ 22 | $dataset | select * 23 | $datasetName = $dataset.Name 24 | $datasetId = $dataset.Id 25 | $ConfiguredBy = $dataset.ConfiguredBy 26 | $ContentProviderType = $dataset.ContentProviderType 27 | " - $datasetName ($datasetId) - $ContentProviderType - Configured by $ConfiguredBy " | Out-File $outputFile -Append 28 | } 29 | 30 | "`n- Reports:" | Out-File $outputFile -Append 31 | foreach($report in $workspace.Reports){ 32 | $reportName = $report.Name 33 | $reportId = $report.Id 34 | $datasetId = $report.DatasetId 35 | " - $reportName (ReportId:$reportId - DatasetId:$datasetId) " | Out-File $outputFile -Append 36 | } 37 | 38 | notepad.exe $outputFile -------------------------------------------------------------------------------- /Demos/Create-Workspace-and-Add-Workspace-Users.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Demos" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | if($workspace) { 10 | Write-Host "The workspace named $workspaceName already exists" 11 | } 12 | else { 13 | Write-Host "Creating new workspace named $workspaceName" 14 | $workspace = New-PowerBIGroup -Name $workspaceName 15 | } 16 | 17 | # add user as workspace member 18 | $userEmail = "JamesB@pbidev0924.onMicrosoft.com" 19 | 20 | Add-PowerBIWorkspaceUser -Id $workspace.Id -UserEmailAddress $userEmail -AccessRight Contributor 21 | -------------------------------------------------------------------------------- /Demos/Create-Workspace.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = New-PowerBIGroup -Name $workspaceName 8 | 9 | $workspace | select * -------------------------------------------------------------------------------- /Demos/Data-Gateway-Demos/Add-Service-Principal-as-Gateway-Admin.ps1: -------------------------------------------------------------------------------- 1 | # requires PowerShell Core - this script will not work on PowerShell 5 2 | # requires installiing DataGateway PowerShell module: Install-Module -Name DataGateway 3 | 4 | # login as user with admn permissions on gateway 5 | Connect-DataGatewayServiceAccount -Environment Public 6 | 7 | # determine service principal ID of application - this is not application ID 8 | $servicePrincipalObjectId = "d26f4381-438a-469e-900e-129c75f2ed60" 9 | 10 | # this script assumes tenant has single gateway (aka gateway cluster) 11 | $gateway = Get-DataGatewayCluster 12 | 13 | Add-DataGatewayClusterUser -GatewayClusterId $gateway.Id -PrincipalObjectId $servicePrincipalObjectId -Role Admin -------------------------------------------------------------------------------- /Demos/Data-Gateway-Demos/Get-Data-Gateways.ps1: -------------------------------------------------------------------------------- 1 | # requires PowerShell Core - this script will not work on PowerShell 5 2 | # requires installiing DataGateway PowerShell module: Install-Module -Name DataGateway 3 | 4 | Connect-DataGatewayServiceAccount 5 | 6 | $dataGateways = Get-DataGatewayCluster 7 | 8 | $dataGateways | select * -------------------------------------------------------------------------------- /Demos/Data-Gateway-Demos/Get-Gateway-Datasources-and-Datasource-Users.ps1: -------------------------------------------------------------------------------- 1 | # requires PowerShell Core - this script will not work on PowerShell 5 2 | # requires installiing DataGateway PowerShell module: Install-Module -Name DataGateway 3 | # this script assume tenant only has a single gateway (aka gateway cluster) 4 | 5 | Connect-DataGatewayServiceAccount 6 | 7 | $gateway = Get-DataGatewayCluster 8 | $gatewayName = $gateway.Name 9 | 10 | Write-Host "Found data gateway named $gatewayName" 11 | Write-Host 12 | 13 | $datasources = Get-DataGatewayClusterDatasource -GatewayClusterId $gateway.Id 14 | 15 | foreach($datasource in $datasources){ 16 | Write-Host "Datasource: "$datasource.DatasourceName 17 | $users = Get-DataGatewayClusterDatasourceUser -GatewayClusterId $gateway.Id -GatewayClusterDatasourceId $datasource.Id 18 | $users | Format-Table DatasourceUserAccessRight, PrincipalType, DisplayName, Identifier 19 | Write-Host 20 | } -------------------------------------------------------------------------------- /Demos/Delete-Dataset.ps1: -------------------------------------------------------------------------------- 1 | Connect-PowerBIServiceAccount | Out-Null 2 | 3 | $workspaceName = "Dev Camp Demos" 4 | $datasetName = "COVID-US" 5 | 6 | # get object for target workspace 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | # get object for new dataset 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | # determine workspace Id and Dataset Id 13 | $workspaceId = $workspace.Id 14 | $datasetId = $dataset.Id 15 | 16 | # parse REST Url for Power BI Service to delete dataset 17 | $restUrl = "groups/$workspaceId/datasets/$datasetId" 18 | 19 | # execute HTTP DELETE operation to delete dataset 20 | Invoke-PowerBIRestMethod -Method Delete -Url $restUrl 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demos/Export-Activity-Events.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host 3 | 4 | Connect-PowerBIServiceAccount | Out-Null 5 | 6 | function ExportDailyActivity($date) { 7 | 8 | $start = (Get-Date -Date ($date) -Format yyyy-MM-ddTHH:mm:ss) 9 | $end = (Get-Date -Date ((($date).AddDays(1)).AddSeconds(-1)) -Format yyyy-MM-ddTHH:mm:ss) 10 | 11 | New-Item -ItemType Directory -Force -Path "$PSScriptRoot/logs" | Out-Null 12 | 13 | $dateString = (Get-Date -Date ($date) -Format yyyy-MM-dd) 14 | $outputFile = "$PSScriptRoot/logs/ActivityEventsLog-$dateString.csv" 15 | 16 | Write-Host "Getting actvities for $dateString" 17 | $events = Get-PowerBIActivityEvent -StartDateTime $start -EndDateTime $end ` 18 | -ResultType JsonString | ConvertFrom-Json 19 | 20 | if($events){ 21 | Write-Host " - Exporting events to $outputFile" 22 | $events | Export-Csv -Path $outputFile -NoTypeInformation 23 | } 24 | else { 25 | Write-Host " - There was no activity on $dateString" 26 | } 27 | } 28 | 29 | $DaysBack = 3 30 | $DateRange = $DaysBack..0 31 | 32 | foreach($dayOffset in $DateRange) { 33 | $day = (((Get-Date).Date).AddDays(-$dayOffset)) 34 | ExportDailyActivity $day 35 | } 36 | -------------------------------------------------------------------------------- /Demos/Get-All-Workspaces-in-Tenant.ps1: -------------------------------------------------------------------------------- 1 |  2 | Connect-PowerBIServiceAccount | Out-Null 3 | 4 | Get-PowerBIWorkspace -Scope Organization -Filter "state eq 'Active'" | Format-Table Name, Type, Id -------------------------------------------------------------------------------- /Demos/Import-Dataflow.ps1: -------------------------------------------------------------------------------- 1 | Connect-PowerBIServiceAccount | Out-Null 2 | 3 | # modify name of target workspace if needed 4 | $workspaceName = "Dev Camp Labs" 5 | 6 | # modify name and path of model.json file if needed 7 | $DataflowImportFileName = "$PSScriptRoot\model.json" 8 | 9 | # read JSON from model.json into locale variable 10 | $DataflowDefinition = [IO.File]::ReadAllText($DataflowImportFileName) 11 | 12 | Connect-PowerBIServiceAccount 13 | $UserAccessToken = Get-PowerBIAccessToken 14 | $bearer = $UserAccessToken.Authorization.ToString() 15 | 16 | # get workspace ID from workspace name 17 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 18 | $workspaceId = $workspace.Id 19 | 20 | # construct URL to import model.json - Note datasetDisplayName must be hard-coded to "model.json" 21 | $importsUrl = "https://api.powerbi.com/v1.0/myorg/groups/$workspaceId/imports?datasetDisplayName=model.json" 22 | 23 | $boundary = [System.Guid]::NewGuid().ToString("N") 24 | $LF = [System.Environment]::NewLine 25 | 26 | $contentType = "multipart/form-data; boundary=""$boundary""" 27 | 28 | $body = ( 29 | "--$boundary", 30 | "Content-Disposition: form-data $LF", 31 | $DataflowDefinition, 32 | "--$boundary--$LF" 33 | ) -join $LF 34 | 35 | $headers = @{ 36 | 'Authorization' = "$bearer" 37 | 'Content-Type' = "$contentType" 38 | } 39 | 40 | Invoke-RestMethod -Uri $importsUrl -ContentType $contentType -Method POST -Headers $headers -Body $body -------------------------------------------------------------------------------- /Demos/Import-PBIX-File.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Demos" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | if($workspace) { 10 | Write-Host "The workspace named $workspaceName already exists" 11 | } 12 | else { 13 | Write-Host "Creating new workspace named $workspaceName" 14 | $workspace = New-PowerBIGroup -Name $workspaceName 15 | } 16 | 17 | $pbixFilePath = "$PSScriptRoot\COVID-US.pbix" 18 | 19 | $import = New-PowerBIReport -Path $pbixFilePath -Workspace $workspace -ConflictAction CreateOrOverwrite 20 | 21 | $import | select * -------------------------------------------------------------------------------- /Demos/Login-User-Interactively.ps1: -------------------------------------------------------------------------------- 1 | # log into Power BI interactively as script begins to run 2 | $user = Connect-PowerBIServiceAccount 3 | 4 | $userName = $user.UserName 5 | 6 | Write-Host 7 | Write-Host "Now logged in as $userName" 8 | 9 | Get-PowerBIWorkspace | Format-Table Name, Id -------------------------------------------------------------------------------- /Demos/Login-User-Unattended.ps1: -------------------------------------------------------------------------------- 1 | # log into Azure AD user account with hard-code user name and password 2 | $userName = "user1@tenant1.onMicrosoft.com" 3 | $password = "myCat$rightLeg" 4 | 5 | # convert password to secure string 6 | $securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force 7 | 8 | # create PSCredential object to serve as login credentials 9 | $credential = New-Object -TypeName System.Management.Automation.PSCredential ` 10 | -ArgumentList $userName, $securePassword 11 | 12 | # log into Power BI unattended without any user interaction 13 | 14 | $user = Connect-PowerBIServiceAccount -Credential $credential 15 | 16 | $userName = $user.UserName 17 | 18 | Write-Host 19 | Write-Host "Now logged in as $userName" 20 | 21 | Get-PowerBIWorkspace | Format-Table Name, Id -------------------------------------------------------------------------------- /Demos/Patch-ADLS-Datasource-Credentials-and-Refresh.ps1: -------------------------------------------------------------------------------- 1 | $workspaceName = "Dev Camp Demos" 2 | $datasetName = "Wingtip Sales Analysis" 3 | 4 | # add credentials for SQL datasource 5 | $accesskey = "YOUR_KEY_HERE" 6 | 7 | # get object for target workspace 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | # get object for new dataset 11 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 12 | 13 | # get object for new SQL datasource 14 | $datasource = Get-PowerBIDatasource -WorkspaceId $workspace.Id -DatasetId $dataset.Id 15 | 16 | # parse REST to determine gateway Id and datasource Id 17 | $workspaceId = $workspace.Id 18 | $datasetId = $dataset.Id 19 | $datasourceUrl = "groups/$workspaceId/datasets/$datasetId/datasources" 20 | 21 | # execute REST call to determine gateway Id and datasource Id 22 | $datasourcesResult = Invoke-PowerBIRestMethod -Method Get -Url $datasourceUrl | ConvertFrom-Json 23 | 24 | # parse REST URL used to patch datasource credentials 25 | $datasource = $datasourcesResult.value[0] 26 | $gatewayId = $datasource.gatewayId 27 | $datasourceId = $datasource.datasourceId 28 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 29 | 30 | # create HTTP request body to patch datasource credentials 31 | $patchBody = @{ 32 | "credentialDetails" = @{ 33 | "credentials" = "{""credentialData"":[{""name"":""key"",""value"":""$accesskey""}}]}" 34 | "credentialType" = "Key" 35 | "encryptedConnection" = "NotEncrypted" 36 | "encryptionAlgorithm" = "None" 37 | "privacyLevel" = "Organizational" 38 | } 39 | } 40 | 41 | # convert body contents to JSON 42 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 43 | 44 | # execute PATCH request to set datasource credentials 45 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 46 | 47 | # parse REST URL for dataset refresh 48 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 49 | 50 | # execute POST to begin dataset refresh 51 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 52 | -------------------------------------------------------------------------------- /Demos/Patch-Anonymous-Datasource-Credentials-and-Refresh.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | $datasetName = "COVID-US" 7 | 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | $workspaceId = $workspace.Id 13 | $datasetId = $dataset.Id 14 | 15 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 16 | 17 | foreach($datasource in $datasources) { 18 | 19 | # parse together REST URL to reference datasource to be patched 20 | $gatewayId = $datasource.gatewayId 21 | $datasourceId = $datasource.datasourceId 22 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 23 | 24 | Write-Host "Patching credentials for $datasourceId" 25 | 26 | # create HTTP request body to patch datasource credentials 27 | $patchBody = @{ 28 | "credentialDetails" = @{ 29 | "credentials" = "{""credentialData"":""""}" 30 | "credentialType" = "Anonymous" 31 | "encryptedConnection" = "NotEncrypted" 32 | "encryptionAlgorithm" = "None" 33 | "privacyLevel" = "Public" 34 | } 35 | } 36 | 37 | # convert body contents to JSON 38 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 39 | 40 | # execute PATCH operation to set datasource credentials 41 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 42 | } 43 | 44 | # parse REST URL for dataset refresh 45 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 46 | 47 | Write-Host "Starting refresh operation" 48 | 49 | # execute POST to begin dataset refresh 50 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore -------------------------------------------------------------------------------- /Demos/Patch-OAuth-Datasource-Credentials-and-Refresh.ps1: -------------------------------------------------------------------------------- 1 | $workspaceName = "Dev Camp Demos" 2 | $datasetName = "Wingtip Sales Analysis" 3 | 4 | # add credentials for SQL datasource 5 | $sqlUserName = "CptStudent" 6 | $sqlUserPassword = "pass@word1" 7 | 8 | # get object for target workspace 9 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 10 | 11 | # get object for new dataset 12 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 13 | 14 | # get object for new SQL datasource 15 | $datasource = Get-PowerBIDatasource -WorkspaceId $workspace.Id -DatasetId $dataset.Id 16 | 17 | # parse REST to determine gateway Id and datasource Id 18 | $workspaceId = $workspace.Id 19 | $datasetId = $dataset.Id 20 | $datasourceUrl = "groups/$workspaceId/datasets/$datasetId/datasources" 21 | 22 | # execute REST call to determine gateway Id and datasource Id 23 | $datasourcesResult = Invoke-PowerBIRestMethod -Method Get -Url $datasourceUrl | ConvertFrom-Json 24 | 25 | # parse REST URL used to patch datasource credentials 26 | $datasource = $datasourcesResult.value[0] 27 | $gatewayId = $datasource.gatewayId 28 | $datasourceId = $datasource.datasourceId 29 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 30 | 31 | # create HTTP request body to patch datasource credentials 32 | $patchBody = @{ 33 | "credentialDetails" = @{ 34 | "credentials" = "{""credentialData"":[{""name"":""username"",""value"":""$sqlUserName""},{""name"":""password"",""value"":""$sqlUserPassword""}]}" 35 | "credentialType" = "Basic" 36 | "encryptedConnection" = "NotEncrypted" 37 | "encryptionAlgorithm" = "None" 38 | "privacyLevel" = "Organizational" 39 | } 40 | } 41 | 42 | # convert body contents to JSON 43 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 44 | 45 | # execute PATCH request to set datasource credentials 46 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 47 | 48 | # parse REST URL for dataset refresh 49 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 50 | 51 | # execute POST to begin dataset refresh 52 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 53 | -------------------------------------------------------------------------------- /Demos/Patch-Sql-Datasource-Credentials-and-Refresh.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for California" 12 | 13 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 14 | -Name $importName -ConflictAction CreateOrOverwrite 15 | 16 | # get object for new dataset 17 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 18 | 19 | $workspaceId = $workspace.Id 20 | $datasetId = $dataset.Id 21 | 22 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 23 | 24 | foreach($datasource in $datasources) { 25 | 26 | $gatewayId = $datasource.gatewayId 27 | $datasourceId = $datasource.datasourceId 28 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 29 | 30 | Write-Host "Patching credentials for $datasourceId" 31 | 32 | # add credentials for SQL datasource 33 | $sqlUserName = "CptStudent" 34 | $sqlUserPassword = "pass@word1" 35 | 36 | # create HTTP request body to patch datasource credentials 37 | $userNameJson = "{""name"":""username"",""value"":""$sqlUserName""}" 38 | $passwordJson = "{""name"":""password"",""value"":""$sqlUserPassword""}" 39 | 40 | $patchBody = @{ 41 | "credentialDetails" = @{ 42 | "credentials" = "{""credentialData"":[ $userNameJson, $passwordJson ]}" 43 | "credentialType" = "Basic" 44 | "encryptedConnection" = "NotEncrypted" 45 | "encryptionAlgorithm" = "None" 46 | "privacyLevel" = "Organizational" 47 | } 48 | } 49 | 50 | # convert body contents to JSON 51 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 52 | 53 | # execute PATCH operation to set datasource credentials 54 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 55 | } 56 | 57 | # parse REST URL for dataset refresh 58 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 59 | 60 | Write-Host "Starting refresh operation" 61 | 62 | # execute POST to begin dataset refresh 63 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 64 | -------------------------------------------------------------------------------- /Demos/Programming-PowerShell-Arrays.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $hobbies = @("Pilates", "Kick boxing", "Power BI Embedding") 4 | 5 | Write-Host 6 | Write-Host "My Hobbies" 7 | 8 | foreach($hobby in $hobbies) { 9 | Write-Host " - $hobby" 10 | } 11 | 12 | Write-Host 13 | -------------------------------------------------------------------------------- /Demos/Programming-PowerShell-Dictionaries.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $pets = @( 4 | @{ Name="Bob"; Type="Cat" } 5 | @{ Name="Diggity"; Type="Dog" } 6 | @{ Name="Larry"; Type="Lizard" } 7 | @{ Name="Penny"; Type="Porcupine" } 8 | ) 9 | 10 | Write-Host 11 | Write-Host "My Pets" 12 | 13 | foreach($pet in $pets) { 14 | $name = $pet.Name 15 | $type = $pet.Type 16 | Write-Host " - $name the $type" 17 | } 18 | 19 | Write-Host -------------------------------------------------------------------------------- /Demos/Programming-PowerShell-Text-Files.ps1: -------------------------------------------------------------------------------- 1 | $outputFilePath = "$PSScriptRoot/Pets.txt" 2 | 3 | $pets = @( 4 | @{ Name="Bob"; Type="Cat" } 5 | @{ Name="Diggity"; Type="Dog" } 6 | @{ Name="Larry"; Type="Lizard" } 7 | @{ Name="Penny"; Type="Porcupine" } 8 | ) 9 | 10 | "My Pets" | Out-File $outputFilePath 11 | 12 | foreach($pet in $pets) { 13 | $name = $pet.Name 14 | $type = $pet.Type 15 | " - $name the $type" | Out-File $outputFilePath -Append 16 | } 17 | 18 | notepad.exe $outputFilePath 19 | -------------------------------------------------------------------------------- /Demos/SalesByState.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Demos/SalesByState.pbix -------------------------------------------------------------------------------- /Demos/Service-Principal-Demos/Add-Service-Principal-As-Workspace-Admin.ps1: -------------------------------------------------------------------------------- 1 | Connect-PowerBIServiceAccount | Out-Null 2 | 3 | $workspaceName = "Dev Camp Labs" 4 | 5 | $servicePrincipalId = "c4143c3d-e853-42c5-a0ee-3eceac680305" 6 | 7 | # get target workspace 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | Add-PowerBIWorkspaceUser -Scope Organization ` 11 | -Id $workspace.Id ` 12 | -AccessRight Admin ` 13 | -Identifier $servicePrincipalId ` 14 | -PrincipalType App -------------------------------------------------------------------------------- /Demos/Service-Principal-Demos/Login-As-Service-Principal-With-Certificate.ps1: -------------------------------------------------------------------------------- 1 | cls 2 | # log into Azure AD as service principal 3 | $tenantId = "ADD_TENANT_ID" 4 | $applictionId = "ADD_APPLICATION_ID" 5 | $certificateThumbprint = "ADD_APPLICATION_CERTIFICATE_THUMBPRINT" 6 | 7 | $sp = Connect-PowerBIServiceAccount -ServicePrincipal -Tenant $tenantId -ApplicationId $applictionId -CertificateThumbprint $certificateThumbprint 8 | 9 | $AppId = $sp.UserName 10 | 11 | Write-Host 12 | Write-Host "Logged on as service principal with AppID of $AppId" 13 | Write-Host 14 | -------------------------------------------------------------------------------- /Demos/Service-Principal-Demos/Login-As-Service-Principal.ps1: -------------------------------------------------------------------------------- 1 | 2 | # log into Azure AD as service principal 3 | $tenantId = "ADD_TENANT_ID" 4 | $applictionId = "ADD_APPLICATION_ID" 5 | $applicationSecret = "ADD_APPLICATION_SECRET" 6 | 7 | $SecuredApplicationSecret = ConvertTo-SecureString -String $applicationSecret -AsPlainText -Force 8 | $credential = New-Object -TypeName System.Management.Automation.PSCredential ` 9 | -ArgumentList $applictionId, $SecuredApplicationSecret 10 | 11 | $sp = Connect-PowerBIServiceAccount -ServicePrincipal -Tenant $tenantId -Credential $credential 12 | 13 | $AppId = $sp.UserName 14 | 15 | Write-Host 16 | Write-Host "Logged on as service principal with AppID of $AppId" 17 | Write-Host 18 | 19 | -------------------------------------------------------------------------------- /Demos/Service-Principal-Demos/Takeover-Dataset-as-Service-Principal-and-Refresh-Sql-Datasource.ps1: -------------------------------------------------------------------------------- 1 | 2 | $workspaceName = "Wingtip Sales" 3 | $datasetName = "WingtipSales" 4 | 5 | # add credentials for SQL datasource 6 | $sqlUserName = "CptStudent" 7 | $sqlUserPassword = "pass@word1" 8 | 9 | # get object for target workspace 10 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 11 | 12 | if(!$workspace){ 13 | throw "Workspace cannot be found" 14 | } 15 | 16 | # get object for new dataset 17 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 18 | 19 | if(!$dataset){ 20 | throw "Dataset cannot be found" 21 | } 22 | 23 | $dataset 24 | 25 | # parse REST URL to take over dataset 26 | $datasetTakeover = "groups/$workspaceId/datasets/$datasetId/Default.Takeover" 27 | 28 | # execute POST to take over dataset 29 | Invoke-PowerBIRestMethod -Method Post -Url $datasetTakeover -WarningAction Ignore 30 | 31 | # get object for new SQL datasource 32 | $datasource = Get-PowerBIDatasource -WorkspaceId $workspace.Id -DatasetId $dataset.Id 33 | 34 | # parse REST to determine gateway Id and datasource Id 35 | $workspaceId = $workspace.Id 36 | $datasetId = $dataset.Id 37 | $datasourceUrl = "groups/$workspaceId/datasets/$datasetId/datasources" 38 | 39 | # execute REST call to determine gateway Id and datasource Id 40 | $datasourcesResult = Invoke-PowerBIRestMethod -Method Get -Url $datasourceUrl | ConvertFrom-Json 41 | 42 | # parse REST URL used to patch datasource credentials 43 | $datasource = $datasourcesResult.value[0] 44 | $gatewayId = $datasource.gatewayId 45 | $datasourceId = $datasource.datasourceId 46 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 47 | 48 | # create HTTP request body to patch datasource credentials 49 | $patchBody = @{ 50 | "credentialDetails" = @{ 51 | "credentials" = "{""credentialData"":[{""name"":""username"",""value"":""$sqlUserName""},{""name"":""password"",""value"":""$sqlUserPassword""}]}" 52 | "credentialType" = "Basic" 53 | "encryptedConnection" = "NotEncrypted" 54 | "encryptionAlgorithm" = "None" 55 | "privacyLevel" = "Organizational" 56 | } 57 | } 58 | 59 | # convert body contents to JSON 60 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 61 | 62 | # execute PATCH request to set datasource credentials 63 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 64 | 65 | # parse REST URL for dataset refresh 66 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 67 | 68 | # execute POST to begin dataset refresh 69 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 70 | -------------------------------------------------------------------------------- /Demos/Service-Principal-Demos/Takeover-Gateway-Dataset-and-Refresh.ps1: -------------------------------------------------------------------------------- 1 | 2 | $workspaceName = "Wingtip Sales" 3 | $datasetName = "Gateway Test" 4 | 5 | 6 | # get object for target workspace 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | if(!$workspace){ 10 | throw "Workspace cannot be found" 11 | } 12 | # get workspace ID 13 | $workspaceId = $workspace.Id 14 | 15 | # get object for new dataset 16 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 17 | 18 | if(!$dataset){ 19 | throw "Dataset cannot be found" 20 | } 21 | 22 | # determine dataset ID 23 | $datasetId = $dataset.Id 24 | 25 | # parse REST URL to take over dataset 26 | $datasetTakeover = "groups/$workspaceId/datasets/$datasetId/Default.Takeover" 27 | 28 | # execute POST to take over dataset 29 | Invoke-PowerBIRestMethod -Method Post -Url $datasetTakeover -WarningAction Ignore 30 | 31 | 32 | # parse REST URL for dataset refresh 33 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 34 | 35 | # execute POST to begin dataset refresh 36 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 37 | -------------------------------------------------------------------------------- /Demos/Update-Connection-Details-for-Sql-Datasource.ps1: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | $workspaceName = "Wingtip Sales" 4 | $datasetName = "Wingtip Sales" 5 | 6 | # add new connection details for SQL datasource 7 | $sqlDatabaseServer = "cpt.database.windows.net" 8 | $sqlDatabaseName = "WingtipSalesDb" 9 | 10 | # get object for target workspace 11 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 12 | 13 | # get object for new dataset 14 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 15 | 16 | # get object for new SQL datasource 17 | $datasource = Get-PowerBIDatasource -WorkspaceId $workspace.Id -DatasetId $dataset.Id 18 | 19 | # parse REST to determine gateway Id and datasource Id 20 | $workspaceId = $workspace.Id 21 | $datasetId = $dataset.Id 22 | $datasourceUrl = "groups/$workspaceId/datasets/$datasetId/datasources" 23 | 24 | # execute REST call to determine gateway Id, datasource Id and current connection details 25 | $datasourcesResult = Invoke-PowerBIRestMethod -Method Get -Url $datasourceUrl | ConvertFrom-Json 26 | 27 | # parse REST URL used to patch datasource credentials 28 | $datasource = $datasourcesResult.value[0] 29 | $gatewayId = $datasource.gatewayId 30 | $datasourceId = $datasource.datasourceId 31 | $sqlDatabaseServerCurrent = $datasource.connectionDetails.server 32 | $sqlDatabaseNameCurrent = $datasource.connectionDetails.database 33 | 34 | # parse together REST Url to update connection details 35 | $datasourePatchUrl = "groups/$workspaceId/datasets/$datasetId/Default.UpdateDatasources" 36 | 37 | # create HTTP request body to update datasource connection details 38 | $postBody = @{ 39 | "updateDetails" = @( 40 | @{ 41 | "connectionDetails" = @{ 42 | "server" = "$sqlDatabaseServer" 43 | "database" = "$sqlDatabaseName" 44 | } 45 | "datasourceSelector" = @{ 46 | "datasourceType" = "Sql" 47 | "connectionDetails" = @{ 48 | "server" = "$sqlDatabaseServerCurrent" 49 | "database" = "$sqlDatabaseNameCurrent" 50 | } 51 | "gatewayId" = "$gatewayId" 52 | "datasourceId" = "$datasourceId" 53 | } 54 | }) 55 | } 56 | 57 | # convert body contents to JSON 58 | $postBodyJson = ConvertTo-Json -InputObject $postBody -Depth 6 -Compress 59 | 60 | # execute POST operation to update datasource connection details 61 | Invoke-PowerBIRestMethod -Method Post -Url $datasourePatchUrl -Body $postBodyJson 62 | 63 | # NOTE: dataset credentials must be reset after updating connection details -------------------------------------------------------------------------------- /Demos/Update-Dataset-Parameters.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for Florida" 12 | $parameterValueState = "FL" 13 | 14 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 15 | -Name $importName -ConflictAction CreateOrOverwrite 16 | 17 | # get object for new dataset 18 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 19 | 20 | $workspaceId = $workspace.Id 21 | $datasetId = $dataset.Id 22 | 23 | # create REST URL to update State parameter for newly-imported dataset 24 | $datasetParametersUrl = "groups/$workspaceId/datasets/$datasetId/Default.UpdateParameters" 25 | 26 | # parse together JSON for POST body to update dataset parameters 27 | $postBody = "{updateDetails:[{name:'State', newValue:'$parameterValueState'}]}" 28 | 29 | # invoke POST operation to update dataset parameters 30 | Invoke-PowerBIRestMethod -Url:$datasetParametersUrl -Method:Post -Body:$postBody ` 31 | -ContentType:'application/json' 32 | 33 | # get object for new SQL datasource 34 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 35 | 36 | Write-Host 37 | 38 | foreach($datasource in $datasources) { 39 | 40 | $gatewayId = $datasource.gatewayId 41 | $datasourceId = $datasource.datasourceId 42 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 43 | 44 | Write-Host "Patching credentials for $datasourceId" 45 | 46 | # add credentials for SQL datasource 47 | $sqlUserName = "CptStudent" 48 | $sqlUserPassword = "pass@word1" 49 | 50 | # create HTTP request body to patch datasource credentials 51 | $userNameJson = "{""name"":""username"",""value"":""$sqlUserName""}" 52 | $passwordJson = "{""name"":""password"",""value"":""$sqlUserPassword""}" 53 | 54 | $patchBody = @{ 55 | "credentialDetails" = @{ 56 | "credentials" = "{""credentialData"":[ $userNameJson, $passwordJson ]}" 57 | "credentialType" = "Basic" 58 | "encryptedConnection" = "NotEncrypted" 59 | "encryptionAlgorithm" = "None" 60 | "privacyLevel" = "Organizational" 61 | } 62 | } 63 | 64 | # convert body contents to JSON 65 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 66 | 67 | # execute PATCH operation to set datasource credentials 68 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 69 | } 70 | 71 | # parse REST URL for dataset refresh 72 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 73 | 74 | Write-Host "Starting refresh operation" 75 | 76 | # execute POST to begin dataset refresh 77 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore -------------------------------------------------------------------------------- /Demos/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wingtip Sales Dataflow", 3 | "description": "", 4 | "version": "1.0", 5 | "culture": "en-US", 6 | "modifiedTime": "2019-10-21T17:54:50.1618626+00:00", 7 | "pbi:mashup": { 8 | "fastCombine": false, 9 | "allowNativeQueries": false, 10 | "queriesMetadata": { 11 | "Customers": { 12 | "queryId": "58d2a7e0-0298-4d94-8285-7af1f3d54b15", 13 | "queryName": "Customers", 14 | "loadEnabled": true 15 | }, 16 | "Products": { 17 | "queryId": "10577951-df4b-407c-b6fb-c923880ba1ed", 18 | "queryName": "Products", 19 | "loadEnabled": true 20 | }, 21 | "Orders": { 22 | "queryId": "ad08816d-be0d-4f6f-b19e-755f23c8fb0f", 23 | "queryName": "Orders", 24 | "loadEnabled": true 25 | }, 26 | "Sales": { 27 | "queryId": "4613190e-da33-4a3a-af5d-a567cbde4dd2", 28 | "queryName": "Sales", 29 | "loadEnabled": true 30 | } 31 | }, 32 | "document": "section Section1;\r\nshared Customers = let\r\n Source = Sql.Database(\"cpt.database.windows.net\", \"WingtipSalesDB\"),\r\n dbo_Customers = Source{[Schema = \"dbo\", Item = \"Customers\"]}[Data],\r\n #\"Removed Other Columns\" = Table.SelectColumns(dbo_Customers, {\"CustomerId\", \"FirstName\", \"LastName\", \"City\", \"State\", \"Zipcode\", \"Gender\", \"BirthDate\", \"FirstPurchaseDate\", \"LastPurchaseDate\"}),\r\n #\"Merged Columns\" = Table.CombineColumns(#\"Removed Other Columns\", {\"FirstName\", \"LastName\"}, Combiner.CombineTextByDelimiter(\" \", QuoteStyle.None), \"Customer\"),\r\n #\"Replaced Female Values\" = Table.ReplaceValue(#\"Merged Columns\", \"F\", \"Female\", Replacer.ReplaceText, {\"Gender\"}),\r\n #\"Replaced Male Values\" = Table.ReplaceValue(#\"Replaced Female Values\", \"M\", \"Male\", Replacer.ReplaceText, {\"Gender\"}),\r\n #\"Changed Type\" = Table.TransformColumnTypes(#\"Replaced Male Values\", {{\"FirstPurchaseDate\", type date}, {\"LastPurchaseDate\", type date}, {\"BirthDate\", type date}}),\r\n #\"Added Conditional Column\" = Table.AddColumn(#\"Changed Type\", \"Customer Type\", each if [FirstPurchaseDate] = [LastPurchaseDate] then \"One-time Customer\" else \"Repeat Customer\"),\r\n #\"Removed Columns\" = Table.RemoveColumns(#\"Added Conditional Column\", {\"FirstPurchaseDate\", \"LastPurchaseDate\"}),\r\n #\"Changed Type1\" = Table.TransformColumnTypes(#\"Removed Columns\", {{\"Customer Type\", type text}}),\r\n #\"Renamed Columns\" = Table.RenameColumns(#\"Changed Type1\", {{\"City\", \"City Name\"}})\r\nin\r\n #\"Renamed Columns\";\r\nshared Products = let\r\n Source = Sql.Database(\"cpt.database.windows.net\", \"WingtipSalesDB\"),\r\n dbo_Products = Source{[Schema = \"dbo\", Item = \"Products\"]}[Data],\r\n #\"Removed Other Columns\" = Table.SelectColumns(dbo_Products, {\"ProductId\", \"Title\", \"Description\", \"ProductCategory\", \"UnitCost\", \"ListPrice\", \"ProductImageUrl\"}),\r\n #\"Renamed Columns\" = Table.RenameColumns(#\"Removed Other Columns\", {{\"Title\", \"Product\"}}),\r\n #\"Split Column by Delimiter\" = Table.SplitColumn(#\"Renamed Columns\", \"ProductCategory\", Splitter.SplitTextByDelimiter(\" > \", QuoteStyle.Csv), {\"ProductCategory.1\", \"ProductCategory.2\"}),\r\n #\"Changed Type\" = Table.TransformColumnTypes(#\"Split Column by Delimiter\", {{\"ProductCategory.1\", type text}, {\"ProductCategory.2\", type text}}),\r\n #\"Renamed Columns1\" = Table.RenameColumns(#\"Changed Type\", {{\"ProductCategory.1\", \"Category\"}, {\"ProductCategory.2\", \"Subcategory\"}}),\r\n #\"Changed Type1\" = Table.TransformColumnTypes(#\"Renamed Columns1\", {{\"UnitCost\", Currency.Type}, {\"ListPrice\", Currency.Type}}),\r\n #\"Renamed Columns2\" = Table.RenameColumns(#\"Changed Type1\", {{\"ProductImageUrl\", \"Product Image\"}})\r\nin\r\n #\"Renamed Columns2\";\r\nshared Orders = let\r\n Source = Sql.Database(\"cpt.database.windows.net\", \"WingtipSalesDB\"),\r\n dbo_Invoices = Source{[Schema = \"dbo\", Item = \"Invoices\"]}[Data],\r\n #\"Removed Other Columns\" = Table.SelectColumns(dbo_Invoices, {\"InvoiceId\", \"InvoiceType\"}),\r\n #\"Replaced Value\" = Table.ReplaceValue(#\"Removed Other Columns\", \"InPerson\", \"Store Purchases\", Replacer.ReplaceText, {\"InvoiceType\"}),\r\n #\"Replaced Value1\" = Table.ReplaceValue(#\"Replaced Value\", \"MailOrder\", \"Mail Order Purchases\", Replacer.ReplaceText, {\"InvoiceType\"}),\r\n #\"Replaced Value2\" = Table.ReplaceValue(#\"Replaced Value1\", \"Online\", \"Online Purchases\", Replacer.ReplaceText, {\"InvoiceType\"}),\r\n #\"Renamed Columns\" = Table.RenameColumns(#\"Replaced Value2\", {{\"InvoiceType\", \"Order Type\"}})\r\nin\r\n #\"Renamed Columns\";\r\nshared Sales = let\r\n Source = Sql.Database(\"cpt.database.windows.net\", \"WingtipSalesDB\"),\r\n dbo_InvoiceDetails = Source{[Schema = \"dbo\", Item = \"InvoiceDetails\"]}[Data],\r\n #\"Changed Type\" = Table.TransformColumnTypes(dbo_InvoiceDetails, {{\"SalesAmount\", Currency.Type}}),\r\n #\"Expanded Invoices\" = Table.ExpandRecordColumn(#\"Changed Type\", \"Invoices\", {\"InvoiceDate\", \"CustomerId\"}, {\"InvoiceDate\", \"CustomerId\"}),\r\n #\"Changed Type1\" = Table.TransformColumnTypes(#\"Expanded Invoices\", {{\"InvoiceDate\", type date}}),\r\n #\"Expanded Products\" = Table.ExpandRecordColumn(#\"Changed Type1\", \"Products\", {\"UnitCost\"}, {\"UnitCost\"}),\r\n #\"Changed Type2\" = Table.TransformColumnTypes(#\"Expanded Products\", {{\"UnitCost\", Currency.Type}}),\r\n #\"Added Custom\" = Table.AddColumn(#\"Changed Type2\", \"ProductCost\", each [Quantity] * [UnitCost]),\r\n #\"Changed Type3\" = Table.TransformColumnTypes(#\"Added Custom\", {{\"ProductCost\", Currency.Type}}),\r\n #\"Removed Columns\" = Table.RemoveColumns(#\"Changed Type3\", {\"UnitCost\"})\r\nin\r\n #\"Removed Columns\";\r\n" 33 | }, 34 | "annotations": [ 35 | { 36 | "name": "pbi:QueryGroups", 37 | "value": "[]" 38 | } 39 | ], 40 | "entities": [ 41 | { 42 | "$type": "LocalEntity", 43 | "name": "Customers", 44 | "description": "", 45 | "pbi:refreshPolicy": { 46 | "$type": "FullRefreshPolicy", 47 | "location": "Customers.csv" 48 | }, 49 | "attributes": [ 50 | { 51 | "name": "CustomerId", 52 | "dataType": "int64" 53 | }, 54 | { 55 | "name": "Customer", 56 | "dataType": "string" 57 | }, 58 | { 59 | "name": "City Name", 60 | "dataType": "string" 61 | }, 62 | { 63 | "name": "State", 64 | "dataType": "string" 65 | }, 66 | { 67 | "name": "Zipcode", 68 | "dataType": "string" 69 | }, 70 | { 71 | "name": "Gender", 72 | "dataType": "string" 73 | }, 74 | { 75 | "name": "BirthDate", 76 | "dataType": "dateTime" 77 | }, 78 | { 79 | "name": "Customer Type", 80 | "dataType": "string" 81 | } 82 | ] 83 | }, 84 | { 85 | "$type": "LocalEntity", 86 | "name": "Products", 87 | "description": "", 88 | "pbi:refreshPolicy": { 89 | "$type": "FullRefreshPolicy", 90 | "location": "Products.csv" 91 | }, 92 | "attributes": [ 93 | { 94 | "name": "ProductId", 95 | "dataType": "int64" 96 | }, 97 | { 98 | "name": "Product", 99 | "dataType": "string" 100 | }, 101 | { 102 | "name": "Description", 103 | "dataType": "string" 104 | }, 105 | { 106 | "name": "Category", 107 | "dataType": "string" 108 | }, 109 | { 110 | "name": "Subcategory", 111 | "dataType": "string" 112 | }, 113 | { 114 | "name": "UnitCost", 115 | "dataType": "decimal" 116 | }, 117 | { 118 | "name": "ListPrice", 119 | "dataType": "decimal" 120 | }, 121 | { 122 | "name": "Product Image", 123 | "dataType": "string" 124 | } 125 | ] 126 | }, 127 | { 128 | "$type": "LocalEntity", 129 | "name": "Orders", 130 | "description": "", 131 | "pbi:refreshPolicy": { 132 | "$type": "FullRefreshPolicy", 133 | "location": "Orders.csv" 134 | }, 135 | "attributes": [ 136 | { 137 | "name": "InvoiceId", 138 | "dataType": "int64" 139 | }, 140 | { 141 | "name": "Order Type", 142 | "dataType": "string" 143 | } 144 | ] 145 | }, 146 | { 147 | "$type": "LocalEntity", 148 | "name": "Sales", 149 | "description": "", 150 | "pbi:refreshPolicy": { 151 | "$type": "FullRefreshPolicy", 152 | "location": "Sales.csv" 153 | }, 154 | "attributes": [ 155 | { 156 | "name": "Id", 157 | "dataType": "int64" 158 | }, 159 | { 160 | "name": "Quantity", 161 | "dataType": "int64" 162 | }, 163 | { 164 | "name": "SalesAmount", 165 | "dataType": "decimal" 166 | }, 167 | { 168 | "name": "InvoiceId", 169 | "dataType": "int64" 170 | }, 171 | { 172 | "name": "ProductId", 173 | "dataType": "int64" 174 | }, 175 | { 176 | "name": "InvoiceDate", 177 | "dataType": "dateTime" 178 | }, 179 | { 180 | "name": "CustomerId", 181 | "dataType": "int64" 182 | }, 183 | { 184 | "name": "ProductCost", 185 | "dataType": "decimal" 186 | } 187 | ] 188 | } 189 | ], 190 | "relationships": [ 191 | { 192 | "$type": "SingleKeyRelationship", 193 | "fromAttribute": { 194 | "entityName": "Customers", 195 | "attributeName": "CustomerId" 196 | }, 197 | "toAttribute": { 198 | "entityName": "Sales", 199 | "attributeName": "CustomerId" 200 | } 201 | }, 202 | { 203 | "$type": "SingleKeyRelationship", 204 | "fromAttribute": { 205 | "entityName": "Products", 206 | "attributeName": "ProductId" 207 | }, 208 | "toAttribute": { 209 | "entityName": "Sales", 210 | "attributeName": "ProductId" 211 | } 212 | }, 213 | { 214 | "$type": "SingleKeyRelationship", 215 | "fromAttribute": { 216 | "entityName": "Orders", 217 | "attributeName": "InvoiceId" 218 | }, 219 | "toAttribute": { 220 | "entityName": "Sales", 221 | "attributeName": "InvoiceId" 222 | } 223 | } 224 | ] 225 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerBI-PowerShell-Tutorial 2 | Students files for the Power BI PowerShell tutorial from Power BI Dev Camp. This tutorial will be ready for the second Power BI Dev Camp session on Thursday, September 24th. 3 | -------------------------------------------------------------------------------- /Scripts/COVID-US.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Scripts/COVID-US.pbix -------------------------------------------------------------------------------- /Scripts/ReadMe.txt: -------------------------------------------------------------------------------- 1 | This is the folder where you should create new scripts as you work through the exercises of this lab. -------------------------------------------------------------------------------- /Scripts/SalesByState.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Scripts/SalesByState.pbix -------------------------------------------------------------------------------- /Solution/Exercise01-Final.ps1: -------------------------------------------------------------------------------- 1 | $outputFilePath = "$PSScriptRoot/Pets.txt" 2 | 3 | $pets = @( 4 | @{ Name="Bob"; Type="Cat" } 5 | @{ Name="Diggity"; Type="Dog" } 6 | @{ Name="Larry"; Type="Lizard" } 7 | @{ Name="Penny"; Type="Porcupine" } 8 | ) 9 | 10 | "My Pets" | Out-File $outputFilePath 11 | 12 | foreach($pet in $pets) { 13 | $name = $pet.Name 14 | $type = $pet.Type 15 | " - $name the $type" | Out-File $outputFilePath -Append 16 | } 17 | 18 | notepad.exe $outputFilePath 19 | -------------------------------------------------------------------------------- /Solution/Exercise01-Part01.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $hobbies = @("Pilates", "Kick boxing", "Power BI Embedding") 4 | 5 | Write-Host 6 | Write-Host "My Hobbies" 7 | 8 | foreach($hobby in $hobbies) { 9 | Write-Host " - $hobby" 10 | } 11 | 12 | Write-Host 13 | -------------------------------------------------------------------------------- /Solution/Exercise01-Part02.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $pets = @( 4 | @{ Name="Bob"; Type="Cat" } 5 | @{ Name="Diggity"; Type="Dog" } 6 | @{ Name="Larry"; Type="Lizard" } 7 | @{ Name="Penny"; Type="Porcupine" } 8 | ) 9 | 10 | Write-Host 11 | Write-Host "My Pets" 12 | 13 | foreach($pet in $pets) { 14 | $name = $pet.Name 15 | $type = $pet.Type 16 | Write-Host " - $name the $type" 17 | } 18 | 19 | Write-Host -------------------------------------------------------------------------------- /Solution/Exercise02-Final.ps1: -------------------------------------------------------------------------------- 1 | # log into Azure AD user account with hard-code user name and password 2 | $userName = "user1@tenant1.onMicrosoft.com" 3 | $password = "myCat$rightLeg" 4 | 5 | # convert password to secure string 6 | $securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force 7 | 8 | # create PSCredential object to serve as login credentials 9 | $credential = New-Object -TypeName System.Management.Automation.PSCredential ` 10 | -ArgumentList $userName, $securePassword 11 | 12 | # log into Power BI unattended without any user interaction 13 | 14 | $user = Connect-PowerBIServiceAccount $credential 15 | 16 | Get-PowerBIWorkspace | Format-Table Name, Id -------------------------------------------------------------------------------- /Solution/Exercise02-Part01.ps1: -------------------------------------------------------------------------------- 1 | 2 | $user = Connect-PowerBIServiceAccount 3 | 4 | $userName = $user.UserName 5 | 6 | Write-Host 7 | Write-Host "Now logged in as $userName" -------------------------------------------------------------------------------- /Solution/Exercise02-Part02.ps1: -------------------------------------------------------------------------------- 1 | # log into Azure AD user account with hard-code user name and password 2 | $userName = "user1@tenant1.onMicrosoft.com" 3 | $password = "myCat$rightLeg" 4 | 5 | # convert password to secure string 6 | $securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force 7 | 8 | # create PSCredential object to serve as login credentials 9 | $credential = New-Object -TypeName System.Management.Automation.PSCredential ` 10 | -ArgumentList $userName, $securePassword 11 | 12 | # log into Power BI unattended without any user interaction 13 | 14 | $user = Connect-PowerBIServiceAccount -Credential $credential 15 | 16 | $userName = $user.UserName 17 | 18 | Write-Host 19 | Write-Host "Now logged in as $userName" -------------------------------------------------------------------------------- /Solution/Exercise03-Final.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | if($workspace) { 10 | Write-Host "The workspace named $workspaceName already exists" 11 | } 12 | else { 13 | Write-Host "Creating new workspace named $workspaceName" 14 | $workspace = New-PowerBIGroup -Name $workspaceName 15 | } 16 | 17 | # add user as workspace member 18 | $userEmail = "JamesB@pbidev0924.onMicrosoft.com" 19 | 20 | Add-PowerBIWorkspaceUser -Id $workspace.Id -UserEmailAddress $userEmail -AccessRight Contributor 21 | -------------------------------------------------------------------------------- /Solution/Exercise03-Part01.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = New-PowerBIGroup -Name $workspaceName 8 | 9 | $workspace | select * -------------------------------------------------------------------------------- /Solution/Exercise04-Final.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | if($workspace) { 10 | Write-Host "The workspace named $workspaceName already exists" 11 | } 12 | else { 13 | Write-Host "Creating new workspace named $workspaceName" 14 | $workspace = New-PowerBIGroup -Name $workspaceName 15 | } 16 | 17 | $pbixFilePath = "$PSScriptRoot\COVID-US.pbix" 18 | 19 | $import = New-PowerBIReport -Path $pbixFilePath -Workspace $workspace -ConflictAction CreateOrOverwrite 20 | 21 | $import | select * -------------------------------------------------------------------------------- /Solution/Exercise05-Final.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | $datasetName = "COVID-US" 7 | 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | $workspaceId = $workspace.Id 13 | $datasetId = $dataset.Id 14 | 15 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 16 | 17 | foreach($datasource in $datasources) { 18 | 19 | # parse together REST URL to reference datasource to be patched 20 | $gatewayId = $datasource.gatewayId 21 | $datasourceId = $datasource.datasourceId 22 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 23 | 24 | Write-Host "Patching credentials for $datasourceId" 25 | 26 | # create HTTP request body to patch datasource credentials 27 | $patchBody = @{ 28 | "credentialDetails" = @{ 29 | "credentials" = "{""credentialData"":""""}" 30 | "credentialType" = "Anonymous" 31 | "encryptedConnection" = "NotEncrypted" 32 | "encryptionAlgorithm" = "None" 33 | "privacyLevel" = "Public" 34 | } 35 | } 36 | 37 | # convert body contents to JSON 38 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 39 | 40 | # execute PATCH operation to set datasource credentials 41 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 42 | } 43 | 44 | # parse REST URL for dataset refresh 45 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 46 | 47 | Write-Host "Starting refresh operation" 48 | 49 | # execute POST to begin dataset refresh 50 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore -------------------------------------------------------------------------------- /Solution/Exercise05-Part01.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | $datasetName = "COVID-US" 7 | 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | $workspaceId = $workspace.Id 13 | $datasetId = $dataset.Id 14 | 15 | Write-Host "The ID for $workspaceName is $workspaceId" 16 | Write-Host "The ID for $datasetName is $datasetId" -------------------------------------------------------------------------------- /Solution/Exercise05-Part02.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | $datasetName = "COVID-US" 7 | 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | $workspaceId = $workspace.Id 13 | $datasetId = $dataset.Id 14 | 15 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 16 | 17 | foreach($datasource in $datasources) { 18 | $datasource | select * 19 | } 20 | -------------------------------------------------------------------------------- /Solution/Exercise05-Part03.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | $datasetName = "COVID-US" 7 | 8 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 9 | 10 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $datasetName 11 | 12 | $workspaceId = $workspace.Id 13 | $datasetId = $dataset.Id 14 | 15 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 16 | 17 | foreach($datasource in $datasources) { 18 | 19 | # parse together REST URL to reference datasource to be patched 20 | $gatewayId = $datasource.gatewayId 21 | $datasourceId = $datasource.datasourceId 22 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 23 | 24 | Write-Host "Patching credentials for $datasourceId" 25 | 26 | # create HTTP request body to patch datasource credentials 27 | $patchBody = @{ 28 | "credentialDetails" = @{ 29 | "credentials" = "{""credentialData"":""""}" 30 | "credentialType" = "Anonymous" 31 | "encryptedConnection" = "NotEncrypted" 32 | "encryptionAlgorithm" = "None" 33 | "privacyLevel" = "Public" 34 | } 35 | } 36 | 37 | # convert body contents to JSON 38 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 39 | 40 | # execute PATCH operation to set datasource credentials 41 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 42 | } 43 | -------------------------------------------------------------------------------- /Solution/Exercise06-Final.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for Florida" 12 | $parameterValueState = "FL" 13 | 14 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 15 | -Name $importName -ConflictAction CreateOrOverwrite 16 | 17 | # get object for new dataset 18 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 19 | 20 | $workspaceId = $workspace.Id 21 | $datasetId = $dataset.Id 22 | 23 | # create REST URL to update State parameter for newly-imported dataset 24 | $datasetParametersUrl = "groups/$workspaceId/datasets/$datasetId/Default.UpdateParameters" 25 | 26 | # parse together JSON for POST body to update dataset parameters 27 | $postBody = "{updateDetails:[{name:'State', newValue:'$parameterValueState'}]}" 28 | 29 | # invoke POST operation to update dataset parameters 30 | Invoke-PowerBIRestMethod -Url:$datasetParametersUrl -Method:Post -Body:$postBody ` 31 | -ContentType:'application/json' 32 | 33 | # get object for new SQL datasource 34 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 35 | 36 | Write-Host 37 | 38 | foreach($datasource in $datasources) { 39 | 40 | $gatewayId = $datasource.gatewayId 41 | $datasourceId = $datasource.datasourceId 42 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 43 | 44 | Write-Host "Patching credentials for $datasourceId" 45 | 46 | # add credentials for SQL datasource 47 | $sqlUserName = "CptStudent" 48 | $sqlUserPassword = "pass@word1" 49 | 50 | # create HTTP request body to patch datasource credentials 51 | $userNameJson = "{""name"":""username"",""value"":""$sqlUserName""}" 52 | $passwordJson = "{""name"":""password"",""value"":""$sqlUserPassword""}" 53 | 54 | $patchBody = @{ 55 | "credentialDetails" = @{ 56 | "credentials" = "{""credentialData"":[ $userNameJson, $passwordJson ]}" 57 | "credentialType" = "Basic" 58 | "encryptedConnection" = "NotEncrypted" 59 | "encryptionAlgorithm" = "None" 60 | "privacyLevel" = "Organizational" 61 | } 62 | } 63 | 64 | # convert body contents to JSON 65 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 66 | 67 | # execute PATCH operation to set datasource credentials 68 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 69 | } 70 | 71 | # parse REST URL for dataset refresh 72 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 73 | 74 | Write-Host "Starting refresh operation" 75 | 76 | # execute POST to begin dataset refresh 77 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore -------------------------------------------------------------------------------- /Solution/Exercise06-Part1.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for California" 12 | 13 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 14 | -Name $importName -ConflictAction CreateOrOverwrite 15 | 16 | # get object for new dataset 17 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 18 | 19 | $workspaceId = $workspace.Id 20 | $datasetId = $dataset.Id -------------------------------------------------------------------------------- /Solution/Exercise06-Part2.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $newWorkspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for California" 12 | 13 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 14 | -Name $importName -ConflictAction CreateOrOverwrite 15 | 16 | # get object for new dataset 17 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 18 | 19 | $workspaceId = $workspace.Id 20 | $datasetId = $dataset.Id 21 | 22 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 23 | 24 | foreach($datasource in $datasources) { 25 | 26 | $gatewayId = $datasource.gatewayId 27 | $datasourceId = $datasource.datasourceId 28 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 29 | 30 | Write-Host "Patching credentials for $datasourceId" 31 | 32 | # add credentials for SQL datasource 33 | $sqlUserName = "CptStudent" 34 | $sqlUserPassword = "pass@word1" 35 | 36 | # create HTTP request body to patch datasource credentials 37 | $userNameJson = "{""name"":""username"",""value"":""$sqlUserName""}" 38 | $passwordJson = "{""name"":""password"",""value"":""$sqlUserPassword""}" 39 | 40 | $patchBody = @{ 41 | "credentialDetails" = @{ 42 | "credentials" = "{""credentialData"":[ $userNameJson, $passwordJson ]}" 43 | "credentialType" = "Basic" 44 | "encryptedConnection" = "NotEncrypted" 45 | "encryptionAlgorithm" = "None" 46 | "privacyLevel" = "Organizational" 47 | } 48 | } 49 | 50 | # convert body contents to JSON 51 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 52 | 53 | # execute PATCH operation to set datasource credentials 54 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 55 | } 56 | -------------------------------------------------------------------------------- /Solution/Exercise06-Part3.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $newWorkspaceName 8 | 9 | $pbixFilePath = "$PSScriptRoot\SalesByState.pbix" 10 | 11 | $importName = "Sales Report for California" 12 | 13 | $import = New-PowerBIReport -Path $pbixFilePath -WorkspaceId $workspace.Id ` 14 | -Name $importName -ConflictAction CreateOrOverwrite 15 | 16 | # get object for new dataset 17 | $dataset = Get-PowerBIDataset -WorkspaceId $workspace.Id | Where-Object Name -eq $import.Name 18 | 19 | $workspaceId = $workspace.Id 20 | $datasetId = $dataset.Id 21 | 22 | $datasources = Get-PowerBIDatasource -WorkspaceId $workspaceId -DatasetId $datasetId 23 | 24 | foreach($datasource in $datasources) { 25 | 26 | $gatewayId = $datasource.gatewayId 27 | $datasourceId = $datasource.datasourceId 28 | $datasourePatchUrl = "gateways/$gatewayId/datasources/$datasourceId" 29 | 30 | Write-Host "Patching credentials for $datasourceId" 31 | 32 | # add credentials for SQL datasource 33 | $sqlUserName = "CptStudent" 34 | $sqlUserPassword = "pass@word1" 35 | 36 | # create HTTP request body to patch datasource credentials 37 | $userNameJson = "{""name"":""username"",""value"":""$sqlUserName""}" 38 | $passwordJson = "{""name"":""password"",""value"":""$sqlUserPassword""}" 39 | 40 | $patchBody = @{ 41 | "credentialDetails" = @{ 42 | "credentials" = "{""credentialData"":[ $userNameJson, $passwordJson ]}" 43 | "credentialType" = "Basic" 44 | "encryptedConnection" = "NotEncrypted" 45 | "encryptionAlgorithm" = "None" 46 | "privacyLevel" = "Organizational" 47 | } 48 | } 49 | 50 | # convert body contents to JSON 51 | $patchBodyJson = ConvertTo-Json -InputObject $patchBody -Depth 6 -Compress 52 | 53 | # execute PATCH operation to set datasource credentials 54 | Invoke-PowerBIRestMethod -Method Patch -Url $datasourePatchUrl -Body $patchBodyJson 55 | } 56 | 57 | # parse REST URL for dataset refresh 58 | $datasetRefreshUrl = "groups/$workspaceId/datasets/$datasetId/refreshes" 59 | 60 | Write-Host "Starting refresh operation" 61 | 62 | # execute POST to begin dataset refresh 63 | Invoke-PowerBIRestMethod -Method Post -Url $datasetRefreshUrl -WarningAction Ignore 64 | -------------------------------------------------------------------------------- /Solution/Exercise07-Final.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName -Scope Organization -Include All 8 | $workspaceId = $workspace.Id 9 | 10 | $outputFile = "$PSScriptRoot/WorkspaceReport.txt" 11 | "Inventory Report for $workspaceName ($workspaceId)" | Out-File $outputFile 12 | 13 | "`n- Users:" | Out-File $outputFile -Append 14 | foreach($user in $workspace.Users){ 15 | $userId = $user.Identifier 16 | $userAccessRight = $user.AccessRight 17 | " - $userId ($userAccessRight)" | Out-File $outputFile -Append 18 | } 19 | 20 | "`n- Datasets:" | Out-File $outputFile -Append 21 | foreach($dataset in $workspace.Datasets){ 22 | $dataset | select * 23 | $datasetName = $dataset.Name 24 | $datasetId = $dataset.Id 25 | $ConfiguredBy = $dataset.ConfiguredBy 26 | $ContentProviderType = $dataset.ContentProviderType 27 | " - $datasetName ($datasetId) - $ContentProviderType - Configured by $ConfiguredBy " | Out-File $outputFile -Append 28 | } 29 | 30 | "`n- Reports:" | Out-File $outputFile -Append 31 | foreach($report in $workspace.Reports){ 32 | $reportName = $report.Name 33 | $reportId = $report.Id 34 | $datasetId = $report.DatasetId 35 | " - $reportName (ReportId:$reportId - DatasetId:$datasetId) " | Out-File $outputFile -Append 36 | } 37 | 38 | notepad.exe $outputFile -------------------------------------------------------------------------------- /Solution/Exercise07-Part01.ps1: -------------------------------------------------------------------------------- 1 |  2 | Connect-PowerBIServiceAccount | Out-Null 3 | 4 | Get-PowerBIWorkspace -Scope Organization -Filter "state eq 'Active'" | Format-Table Name, Type, Id -------------------------------------------------------------------------------- /Solution/Exercise07-Part02.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 2 | 3 | Connect-PowerBIServiceAccount | Out-Null 4 | 5 | $workspaceName = "Dev Camp Labs" 6 | 7 | $workspace = Get-PowerBIWorkspace -Name $workspaceName -Scope Organization -Include All 8 | $workspaceId = $workspace.Id 9 | 10 | $outputFile = "$PSScriptRoot/WorkspaceReport.txt" 11 | "Inventory Report for $workspaceName ($workspaceId)" | Out-File $outputFile 12 | 13 | notepad.exe $outputFile -------------------------------------------------------------------------------- /Solution/Exercise08-Final.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | Write-Host 3 | 4 | Connect-PowerBIServiceAccount | Out-Null 5 | 6 | function ExportDailyActivity($date) { 7 | 8 | $start = (Get-Date -Date ($date) -Format yyyy-MM-ddTHH:mm:ss) 9 | $end = (Get-Date -Date ((($date).AddDays(1)).AddSeconds(-1)) -Format yyyy-MM-ddTHH:mm:ss) 10 | 11 | New-Item -ItemType Directory -Force -Path "$PSScriptRoot/logs" | Out-Null 12 | 13 | $dateString = (Get-Date -Date ($date) -Format yyyy-MM-dd) 14 | $outputFile = "$PSScriptRoot/logs/ActivityEventsLog-$dateString.csv" 15 | 16 | Write-Host "Getting actvities for $dateString" 17 | $events = Get-PowerBIActivityEvent -StartDateTime $start -EndDateTime $end ` 18 | -ResultType JsonString | ConvertFrom-Json 19 | 20 | if($events){ 21 | Write-Host " - Exporting events to $outputFile" 22 | $events | Export-Csv -Path $outputFile -NoTypeInformation 23 | } 24 | else { 25 | Write-Host " - There was no activity on $dateString" 26 | } 27 | } 28 | 29 | $DaysBack = 3 30 | $DateRange = $DaysBack..0 31 | 32 | foreach($dayOffset in $DateRange) { 33 | $day = (((Get-Date).Date).AddDays(-$dayOffset)) 34 | ExportDailyActivity $day 35 | } 36 | -------------------------------------------------------------------------------- /Tutorial.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Tutorial.docx -------------------------------------------------------------------------------- /Tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerBiDevCamp/PowerBI-PowerShell-Tutorial/64b4422ab1a6d7c197c43684ff9f0de01df08928/Tutorial.pdf --------------------------------------------------------------------------------