pbiTools.psm1
# Power BI Tools and Library # (v) Bob, Prodata Sept 2019 # History # 24/09/2019 First Version # # Install-Module MicrosoftPowerBIMgmt function New-pbiReport { param( [Parameter(Mandatory=$True)]$Path, #File OR Folder. Can be Array [Parameter(Mandatory=$True)]$Workspace, #Single Workspace [Parameter(Mandatory=$False)]$Name, #Name of DataSet/Report. If Blank will take from File [Parameter(Mandatory=$False)]$SqlServer, #Name of SQL Servr to Map Model to (If a Model ) [Parameter(Mandatory=$False)]$UserName #Name of Current User. If specified will take over dataset if needed ) ) $ErrorActionPreference = "Stop" $WorkspaceID = Get-PowerBIWorkspace -Name $Workspace $BaseName =$Name foreach ($p in $Path) { Get-ChildItem -Path $p| Where {$_.extension -like ".pbix"}| foreach { Write-Verbose -Message $_ if (!($BaseName)) {$Name=$_.BaseName } else {$Name =$BaseName} $Id= New-PowerBIReport -Path $_.FullName -Name $Name -Workspace $WorkspaceID -ConflictAction:"CreateOrOverwrite" | Select -ExpandProperty "Id" $count =@(Get-PowerBIReport -Workspace $WorkspaceID -Name $_.BaseName ).Count # if ($count -gt 1) { # Invoke-pbiReportBindFix -ReportId $Id # } if ($SqlServer) { Set-pbiSqlServer -Workspace $Workspace -Name $Name -SqlServer $SqlServer -UserName $UserName } else { Set-pbiDatasetGateway -Workspace $Workspace -Dataset $Name } } } } #Check if Linked Report has Duplicate and fix by # # function Invoke-pbiReportBindFix { } function Check-pbiModules { Load-Module "SqlServer" Load-Module "MicrosoftPowerBIMgmt" } function Remove-pbiReport { param( [Parameter(Mandatory=$True)]$Workspace #Single Workspace ) $WorkspaceId=(Get-PowerBIWorkspace -Name $Workspace) | Select -ExpandProperty "Id" Get-PowerBIReport -Workspace (Get-PowerBIWorkspace -Name $Workspace) | foreach { $Id =$_.Id $Url = "groups/$WorkspaceId/reports/$Id" Invoke-PowerBIRestMethod -Url $Url -Method Delete } Get-PowerBIDataSet -Workspace (Get-PowerBIWorkspace -Name $Workspace) | foreach { $Id =$_.Id $Url = "groups/$WorkspaceId/datasets/$Id" Invoke-PowerBIRestMethod -Url $Url -Method Delete } } function Set-pbiRebindReport { param( [Parameter(Mandatory=$True)][object]$Workspace , #Single Workspace [Parameter(Mandatory=$False)][String]$Report="*", #Name of Report. Can be * [Parameter(Mandatory=$False)][String]$ForceDatasetId #DataSetId to force a Bind To ) $ErrorActionPreference = "Stop" $WorkspaceId=(Get-PowerBIWorkspace -Name $Workspace) | Select -ExpandProperty "Id" Get-PowerBIReport -WorkspaceId $WorkspaceId | Where {$_.Name -like $Report} | foreach { $DatasetId=$_.DatasetId $reportId=$_.Id $Url ="groups/$WorkspaceId/datasets/$DatasetId" $Id=Get-PowerBIDataset -WorkspaceId $WorkspaceId -Id $DatasetId | Select -ExpandProperty "Id" if (!$Id) { Write-Verbose -Message ("Rebind Report: " + $_.Name) #Get Name of Dataset in Remote Workspace $Url ="groups/$WorkspaceId/datasets/$DatasetId" $json=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $json $DatasetName =$data.name if ($ForceDatasetId) { $newDatasetId=$ForceDatasetId } else { #Get Dataset ID for Local Workspace Dataset $newDatasetId=Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -eq $DatasetName } | Select -ExpandProperty "Id" } #Rebind Report to Dataset specified $url="groups/$WorkspaceId/reports/$reportId/Rebind" $Body=@" {datasetId: "$newDatasetId"} "@ Invoke-PowerBIRestMethod -Url $Url -Method Post -Body $Body } } } function Set-pbiDatasetTakeOver { param( [Parameter(Mandatory=$True)]$Workspace , #Single Workspace [Parameter(Mandatory=$False)]$Dataset="*", #Name of Dataset. Can by Array [Parameter(Mandatory=$False)]$UserName="" #Username of USer to Change Ownership to ) $ErrorActionPreference = "Stop" $WorkspaceId=(Get-PowerBIWorkspace -Name $Workspace) | Select -ExpandProperty "Id" Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -like $Dataset} |foreach { $Id =$_.Id $Url ="groups/$WorkspaceId/datasets/$Id/Default.TakeOver" Invoke-PowerBIRestMethod -Url $Url -Method Post -Body "" } } function Set-pbiDatasetGateway { param( [Parameter(Mandatory=$True)]$Workspace , #Single Workspace [Parameter(Mandatory=$False)]$Dataset="*" #Name of Dataset. Can by Array ) $ErrorActionPreference = "Stop" $WorkspaceId=(Get-PowerBIWorkspace -Name $Workspace) | Select -ExpandProperty "Id" Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -like $Dataset} |foreach { $Id =$_.Id $DataSet = $_.Name $IsOnPremGatewayRequired =$_.IsOnPremGatewayRequired if ($IsOnPremGatewayRequired) { $Url ="groups/$WorkspaceId/datasets/$Id/DiscoverGateways" $json=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $json $GatewayId=$data.value.Id $Body=@" {"gatewayObjectId": "$GatewayId"} "@ $url="groups/$WorkspaceId/datasets/$Id/BindToGateway" Write-Verbose -Message $url try { Invoke-PowerBIRestMethod -Url $Url -Method Post -Body $Body } catch [System.Net.Http.HttpRequestException],[AggregateException] { write-Error ("Could Not Bind Gateway on DataSet $DataSet . Check SqlServer Name and Gateway Configuration.") write-Error (Resolve-PowerBIError -Last | Out-String) } catch { #write-Error ( $_.Exception) write-Error (Resolve-PowerBIError -Last | Out-String) } } } } function Get-pbiStatus { param( [Parameter(Mandatory=$True)] [object] $Workspace , #WorkSpaces. Can be Array [Parameter(Mandatory=$False)][string] $Dataset="*",#Name of Dataset. Can by WildCard [Parameter(Mandatory=$False)][hashtable] $Errors =@{}, #Hash Table of Errors During Processing to tag them on Status returned [Parameter(Mandatory=$False)][hashtable] $StartTimes =@{} #Hash Table of Start Times if Processing Failures not logged ) # $ErrorActionPreference = "Stop" $DataSetList=@() ForEach ($w in $Workspace ) { $WorkspaceId=(Get-PowerBIWorkspace -Name $w) | Select -ExpandProperty "Id" Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -like $Dataset -and $_.IsRefreshable -eq $True} | Where-Object {$_.Name -NotIn "Usage Metrics Report"}|foreach { $Id=$_.Id $obj=$null $obj = New-Object System.Object $obj | Add-Member -type NoteProperty -Name WorkSpace -Value $w $obj | Add-Member -type NoteProperty -Name DataSetId -Value $_.id $obj | Add-Member -type NoteProperty -Name DataSet -Value $_.Name $obj | Add-Member -type NoteProperty -Name ConfiguredBy $_.ConfiguredBy $obj | Add-Member -type NoteProperty -Name IsOnPremGatewayRequired $_.IsOnPremGatewayRequired #Get last Refresh History $url="groups/$WorkspaceId/datasets/$Id/refreshes?" + '$top=1' $json=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $json $status =(&{if ($data.value.status -eq "Unknown") {"InProgress"} else {$data.value.status}}) if ($Errors.item($Id).length -gt 0) {$status = "Failed" } if ($Errors.item($Id).length -gt 0) { $startTime = $StartTimes.item($Id) $endTime =$startTime } else { if ($data.value.startTime) {$startTime = [datetime]$data.value.startTime} if ($data.value.EndTime){$endTime =[datetime]$data.value.EndTime} } $obj | Add-Member -type NoteProperty -Name refreshStatus $status $obj | Add-Member -type NoteProperty -Name refreshType $data.value.refreshType $obj | Add-Member -type NoteProperty -Name startTime $startTime $obj | Add-Member -type NoteProperty -Name EndTime $endTime $obj | Add-Member -type NoteProperty -Name Error ($Errors.item($Id) + $data.value.serviceExceptionJson ) $DataSetList+=$obj } } $DataSetList } function Invoke-pbiRefresh { param( [Parameter(Mandatory=$True)] [object]$Workspace , #Array of Workspaces [Parameter(Mandatory=$False)] [String]$Dataset="*", #Name of Dataset. Can by Array [parameter(Mandatory=$false)] [switch]$MailOnFailure=$False, #Email on Failure [parameter(Mandatory=$false)] [switch]$Wait=$False, #Wait for Failure (Synchronous) [parameter(Mandatory=$false)] [int]$WaitTime=10, #Time to wait for checking Processing Progress [parameter(Mandatory=$false)] [String]$SqlServer ,#Sql Server to Log Results. Will Log if this is present [parameter(Mandatory=$false)] [String]$SqlDatabaseName , #Sql Server to Log Results to. Will Log if this is present [parameter(Mandatory=$false)] [String]$SqlSchemaName ="dbo" , #Sql Server to Log Schema to. Will Log if this is present [parameter(Mandatory=$false)] [String]$SqlTableName ="ProcessView", #Sql Table to Log Results to [parameter(Mandatory=$false)] [switch]$IgnoreProcessError, #Raise Error if any Process Errors. Default is to Fail on any Error [parameter(Mandatory=$false)] [switch]$NoOutput #Output Status When Finished ) $ErrorActionPreference = "Stop" $errormessage="" #Check-pbiModules $Datasets =@() $Errors =@{} $ProcessKeys =@{} $StartTimes =@{} $Failed =$false ForEach ($w in $Workspace) { $wDatasets=@() $WorkspaceId=(Get-PowerBIWorkspace -Name $w) | Select -ExpandProperty "Id" $wDatasets=Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -like $Dataset -and $_.IsRefreshable -eq $True } | Where-Object {$_.Name -NotIn "Usage Metrics Report"} [Int]$percentComplete=0 [Int]$maxPercent=0 $DatasetCount=$wDatasets.Count $progressTime =$false #Het Ladt Refresh Timing for Progress Bar forEach ($d in $wDatasets) { $id=$d.Id $url="groups/$WorkspaceId/datasets/$Id/refreshes?" + '$top=1' $json=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $json if (($data.value)) { $progressTime =$false $maxPercent=$DatasetCount Break } else { if ($data.value.endTime) {$maxPercent+= (NEW-TIMESPAN –Start $data.value.startTime –End $data.value.endTime ).Seconds} if ($maxPercent -gt 0) {$progressTime=$true} } } if ($maxPercent -eq 0) {$progressTime=$false; $maxPercent=$DatasetCount} forEach ($d in $wDatasets) { $Id =$d.Id $Datasets+=$Id $DatasetName=$d.Name $IsOnPremGatewayRequired =$d.IsOnPremGatewayRequired if ($MailOnFailure.IsPresent) {$notifyOption="MailOnFailure"} else { $notifyOption="NoNotification" } $Body='{"notifyOption": "' + $notifyOption+ '"}' $url="groups/$WorkspaceId/datasets/$Id/refreshes" try { if ($SqlServer) { $Query="INSERT INTO [{0}].[{1}].[{2}] (Workspace,DataSetId,DataSet, IsOnPremGatewayRequired, refreshStatus, refreshType, startTime) VALUES ('{3}','{4}','{5}','{6}','{7}','{8}', getdate()); SELECT SCOPE_IDENTITY()" -f $SqlDatabaseName,$SqlSchemaName, $sqlTableName, $w, $id,$DatasetName, $IsOnPremGatewayRequired, "Starting","ViaApi" Write-Verbose $Query $Key= (invoke-sqlcmd -ServerInstance $SqlServer -Database $SqlDatabaseName -Query $Query)[0] $ProcessKeys.Add($id,$key) } Write-Progress -Activity "PBI Refresh" -CurrentOperation "$DatasetName" -Status "Starting" $res=Invoke-PowerBIRestMethod -Url $Url -Method Post -Body $Body if ($SqlServer) { $Query="UPDATE [{0}].[{1}].[{2}] SET EndTime=getdate(), refreshStatus='InProgress' WHERE ProcessKey={3}" -f $SqlDatabaseName,$SqlSchemaName, $sqlTableName, $key invoke-sqlcmd -ServerInstance $SqlServer -Database $SqlDatabaseName -Query $Query } } catch [AggregateException] { $failed=$True $error=$_.Exception.innerexception.message if ($error.Contains("Bad Request")) {$error ="Refresh Limit Reached" } write-Warning ("`r`nRefresh $w\$DatasetName. $error " ) Write-Verbose -Message $_.Exception $Errors.Add($id,$error) $StartTimes.Add($id,(Get-Date)) if ($SqlServer) { $Query="UPDATE [{0}].[{1}].[{2}] SET EndTime=getdate(), refreshStatus='Failed', Error = '{3}' WHERE ProcessKey={4}" -f $SqlDatabaseName,$SqlSchemaName, $sqlTableName, $error, $key invoke-sqlcmd -ServerInstance $SqlServer -Database $SqlDatabaseName -Query $Query } continue } catch { $failed=$True write-Warning ("`r`nRefresh $w\$DatasetName. $_.Exception.message" ) Write-Verbose -Message $_.Exception $Errors.Add($id,$_.Exception ) $StartTimes.Add($id,(Get-Date)) if ($SqlServer) { $Query="UPDATE [{0}].[{1}].[{2}] SET EndTime=getdate(), refreshStatus='Failed' WHERE ProcessKey={2}" -f $SqlDatabaseName,$SqlSchemaName, $sqlTableName, $_.Exception, $key invoke-sqlcmd -ServerInstance $SqlServer -Database $SqlDatabaseName -Query $Query } continue } } #Synchrous Processing if Required. By Default is Asyncronous $startTime=get-date if ($Wait.IsPresent) { While (!($Complete)) { $InProgress=$false $i=0 $errorCount=$Errors.Count $lastError="" $errorDataset="" ForEach ($d in $wDataSets) { $id=$d.Id if ($Errors.Contains( $id)) { $i+=1 $lastError=$Errors[$id] $errorDataset=$d.Name + ":" } else { $url="groups/$WorkspaceId/datasets/$Id/refreshes?" + '$top=1' $json=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $json $status=$data.value.status if ($status -eq "Failed" -or $status -eq "Completed") {$i+=1 } if ($status -eq "Unknown") {$InProgress=$true } if ($status -eq "InProgress") {$InProgress =$true } if ($status -eq "Failed") {$failed=$true ; $errorCount +=1; $lastError =$data.value.serviceExceptionJson; $errorDataset=$d.Name + ":"} } } $seconds= (new-timespan $startTime (get-date) ).TotalSeconds if ($progressTime) {$percentComplete = $seconds / $maxPercent* 100 } else { $percentComplete = $i/$maxPercent *100} Write-Progress -activity ("PBI Refresh. {0}/{1} Complete. {2} Errors." -f $i, $DatasetCount , $errorCount) -status ("In Progress. $errorDataset$lastError") -PercentComplete $percentComplete if ($i -lt$DatasetCount) { $InProgress = $true; } else {$InProgress =$false ;$Complete=$true } if (!($Complete)) {Start-Sleep -Seconds $WaitTime} } } } #Log Results to Table if ((($SqlServer) -and ($SqlDatabaseName)) -or (!($NoOutput ))) { $status=Get-pbiStatus -Workspace $Workspace -Dataset $Dataset -Errors $Errors -StartTimes $StartTimes } if (!($NoOutput )) { $Status | Select } if (($SqlServer) -and ($SqlDatabaseName)) { Write-Verbose -Message "Logging to $SqlServer.$SqlDatabaseName.$SqlSchemaName.$SqlTableName" $Status | Select-Object -Property * | ForEach-Object { $key=$ProcessKeys[$_.DataSetId] if ($SqlServer -and $_.refresshStatus -ne "Failed") { $Query="UPDATE [{0}].[{1}].[{2}] SET EndTime=getdate(), refreshStatus='{3}' , Error='{4}' WHERE ProcessKey={5}" -f $SqlDatabaseName,$SqlSchemaName, $sqlTableName, $_.refreshStatus, $_.Error , $key invoke-sqlcmd -ServerInstance $SqlServer -Database $SqlDatabaseName -Query $Query } } $Status | ForEach-Object { if (!($_.Error)) { $s="Workspace: " + $_.WorkSpace + ",Dataset:" + $_.DataSet + ",Error:" + $_.Error if ($_.refreshStatus -eq "Failed") { Write-Error -Message $s } } } } if ($failed) { EXIT 1 } } function Set-pbiSqlServer { param( [Parameter(Mandatory=$True)]$Workspace , #Single Workspace [Parameter(Mandatory=$False)]$Name="*", #Name of Dataset. Can by Array [Parameter(Mandatory=$True)]$SqlServer="", #New SqlServer Name [Parameter(Mandatory=$False)]$UserName="" #Username of validated user. If this is set then updaet will TakeOver Dataset if required ) $ErrorActionPreference = "Stop" $WorkspaceId=(Get-PowerBIWorkspace -Name $Workspace) | Select -ExpandProperty "Id" Get-PowerBIDataset -WorkspaceId $WorkspaceId | Where {$_.Name -like $Name} |foreach { $ConfiguredBy=$_.ConfiguredBy $Id =$_.Id $Dataset = $_.Name $Url = "groups/$WorkspaceId/datasets/$Id/datasources" $ds=Invoke-PowerBIRestMethod -Url $Url -Method Get $data = ConvertFrom-Json $ds $datasourceType=$data.value.datasourceType $oldServer =$data.value.connectionDetails.server $Database =$data.value.connectionDetails.database if ($Username) { if ($ConfiguredBy -ne $UserName) { Set-pbiDatasetTakeOver -Workspace $Workspace -Dataset $Dataset $ConfiguredBy=(Get-PowerBIDataset -WorkspaceId $WorkspaceId -Id $Id) | Select -ExpandProperty "ConfiguredBy" if ($ConfiguredBy -ne $UserName) { Write-Error "Cannot Updatedatasource. Owner=$ConfiguredBy,Current UserName=$UserName" } } } if ($datasourceType -eq "sql") { $Url = "groups/$WorkspaceId/datasets/$Id/updatedatasources" $Body=@" {"updateDetails":[ {"connectionDetails": { "server": "$SqlServer", "database": "$Database" }, "datasourceSelector": { "datasourceType": "Sql", "connectionDetails": { "server": "$OldServer", "database": "$Database" } } } ] } "@ Write-Verbose -Message $Url Write-Verbose -Message $Body Write-Host "Updating Datasource for $Workspace\$Dataset. Server $oldServer=>$SqlServer..." try { Invoke-PowerBIRestMethod -Url $Url -Method Post -Body $Body } catch [System.Net.Http.HttpRequestException],[AggregateException] { write-Error ("Update for $Workspace\$Dataset.PBIX Failed. Check PowerQuery has no MERGE operations. See https://docs.microsoft.com/en-us/rest/api/power-bi/datasets/updatedatasources") write-Error (Resolve-PowerBIError -Last | Out-String) } catch { write-Error ( $_.Exception) } } else { Write-Host "datasourceType=$datasourceType. Not Updated as not Sql" } #Set PBI Gateway (not Required as it now Auto Sets) Set-pbiDatasetGateway -Workspace $Workspace -Dataset $Dataset } } function Load-Module ($m) { # If module is imported say that and do nothing if (Get-Module | Where-Object {$_.Name -eq $m}) { return } else { # If module is not imported, but available on disk then import if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m}) { Import-Module $m } else { # If module is not imported, not available on disk, but is in online gallery then install and import if (Find-Module -Name $m | Where-Object {$_.Name -eq $m}) { Install-Module -Name $m -Force -Verbose -Scope CurrentUser -AllowClobber Import-Module $m } else { # If module is not imported, not available and not in online gallery then abort write-host "Module $m not imported, not available and not in online gallery, exiting." Exit 1 } } } } function Remove-pbiBackupBlob { Param( [parameter(Mandatory=$true)] [string]$StorageAccountName, [parameter(Mandatory=$true)] [string]$SAS, [parameter(Mandatory=$false)] [object]$Containers, [parameter(Mandatory=$true)] [int]$Cleanup =7 ) $ctx=New-AzStorageContext -StorageAccountName $StorageAccountName -SasToken $SAS -ErrorAction Stop Write-Host $("Connecting to {0}" -f $StorageAccountName) foreach ($container in $Containers) { $blobs =Get-AzStorageBlob -Context $ctx -Container $Containers | Where-Object {$_.Name -like "*.pbix"} if ($blobs ){ foreach ($blob in $blobs) { $LastModified=$blob.LastModified $DaysOld = ([DateTime]::Now.Date - [DateTime]$LastModified.Date) if ($DaysOld.Days -gt $Cleanup){ Write-Host $("Deleting the blob file {0}" -f $blob.Name) Remove-AzStorageBlob -Context $ctx -Container $container -Blob $blob.Name } } } } } function Download-pbiReport { param( [Parameter(Mandatory=$False)] [object]$Workspace ="" , #Array of Workspaces [Parameter(Mandatory=$False)] [String]$Report="*", #Name of Dataset. Can by Array [Parameter(Mandatory=$False)] [String]$Path="C:\temp\PowerBI", #Path to Export to. Can be a Temp Path if [parameter(Mandatory=$false)] [string]$StorageAccountName="", #Azure StorageAccountName for Upload [parameter(Mandatory=$false)] [string]$Container="powerbi", #Azure $Container eg "PowerBI" [parameter(Mandatory=$false)] [string]$SAS="" #SAS Token for upload ) $ErrorActionPreference = "Stop" if (-Not $workspace) { [System.Collections.ArrayList]$workspace=Get-PowerBIWorkspace | select-Object Name } if ($SAS) { if ((Get-Command "AzCopy.exe" -ErrorAction SilentlyContinue) -eq $null) { Write-Error "Unable to find AzCopy in your PATH. Please download to C:\Windows or in Path" } } New-Item -ItemType Directory -Force -Path $Path | Out-Null Remove-Item -Path $Path -Force -Recurse -Filter "*.pbix" ForEach ($w in $Workspace) { $WorkspaceId=Get-PowerBIWorkspace -Name $w | Select -ExpandProperty "Id" if (-Not $WorkspaceId) { write-Error "Workspace '$w' Not Found. Check Workspaces and Permissions"} Get-PowerBIReport -WorkspaceId $WorkspaceId | Where {$_.Name -like $Report} | ForEach-Object { $ds=Get-PowerBIDataset -Id $_.DataSetId -WorkspaceId $WorkspaceId if ($ds.IsEffectiveIdentityRequired -eq $True) { $pbix=$_.Name + "_"+ (Get-Date -Format "yyyyMMdd") + ".pbix" $file=Join-Path -Path $Path -ChildPath $w New-Item -ItemType Directory -Force -Path $file | Out-Null $file=Join-Path -Path $file -ChildPath ${pbix} if (Test-Path $file) { Remove-Item $file } "Downloading {0}" -f $file $Id =$_.Id $Url = "groups/$WorkspaceId/reports/$Id/Export" Invoke-PowerBIRestMethod -Url $Url -Method get -OutFile $file #Export-PowerBIReport -Id $_.Id -OutFile $file } } } if ($SAS) { $uri = "https://${StorageAccountName}.blob.core.windows.net/${Container}?$SAS" AzCopy cp $Path $uri --recursive=true } } export-modulemember -function New-pbiReport export-modulemember -function Remove-pbiReport export-modulemember -function Set-pbiRebindReport export-modulemember -function Set-pbiDatasetTakeOver export-modulemember -function Set-pbiDatasetGateway export-modulemember -function Get-pbiStatus export-modulemember -function Invoke-pbiRefresh export-modulemember -function Set-pbiSqlServer export-modulemember -function Download-pbiReport export-modulemember -function Remove-pbiBackupBlob |