Dyota's blog

Power BI: Check before you delete

One trap that I seem to repeatedly fall into is deleting a measure, or a column, or a table, with no visibility of the consequences, and doing it anyway.

My main Power BI file has grown into such a monster that I can't fit all of it in my head, and many times in the past, I had deleted something while "pruning" (i.e. I thought that measure was not necessary any longer), only to find out that it there was a report somewhere with a table that referred to it. Nevermind deleting, renaming columns and measures will have the same effect.

I now have a method of checking before deleting. This methods assumes that all of your Power BI files are saved as .pbip files, not as .pbix. This is because it relies on the files report.json that in contained inside the project folder.

I have all of my Power BI projects stored in a single location. The following PowerShell function lets me:

  1. enter some keywords (e.g. the name of a measure I'm about to delete)
  2. scan through all of the projects that I have, and
  3. identify all of the visuals that it appears in
using namespace System.Collections.Generic; # for List
function searchPbi ($keywords) {
    $root = '.\Project Files'
    
    function importPowerBIReport ($filePath){
        # $filePath is the path for report.json

        $report = Get-Content $filePath | ConvertFrom-Json
        
        # set up list for data storage
        [List[pscustomobject]] $data = @()
        
        # one "section" is a page in the PBI report
        $report.sections | 
            ForEach-Object {
                
                $pageName = $_.displayName
                
                # a "visualContainer" is a visual on the page
                $_.visualContainers.config | 
                    ForEach-Object {
                        $config = $_ | ConvertFrom-Json
                        $visual = $config.singleVisual
                        $visualType = $visual.visualType # tableEx, pivotTable, slicer, etc.
                        
                        $visual.projections.Values |
                            ForEach-Object {
                                
                                # queryRefs are in the form of table.column or table.measure
                                $queryRef = $_.queryRef
                                
                                # put it into the data List
                                $data.Add(
                                    [PSCustomobject] @{
                                        pageName = $pageName;
                                        visualType = $visualType;
                                        queryRef = $queryRef
                                    }
                                )
                            }               
                    }
            }
            return $data
    }

    function searchReportForQueryReference ($data, $keywords) {
        
        # take in the data collected from previous function, and
        # filter it according to the keywords
        $refsFound = [pscustomobject] $data |
            Where-Object {
                $keywords = $keywords -join '*'
                $queryRef = ($_.queryRef)
                $queryRef -like "*$keywords*"
            }
        
        # display a count of how many references found
        Write-Host $refsFound.Count references found
        
        # if there are no references, then do nothing
        if ($refsFound.Count -gt 0) {
            $refsFound | Group-Object  -Property 'pageName' |
                ForEach-Object {

                    # for each page...
                    Write-Host "On page " -NoNewline
                    Write-Host -Foregroundcolor Green $($_.Name)
                    $_.Group |
                        ForEach-Object {
                            # list out all of the references found on this page
                            Write-Host "On a " -NoNewline
                            Write-Host -Foregroundcolor Yellow $($_.visualType)  -NoNewline
                            Write-Host " containing "  -NoNewline
                            Write-Host -Foregroundcolor Yellow $($_.queryRef)
                        }
                }
        }
    
    }

    Get-ChildItem $root |
        ForEach-Object {
            
            # run for all project folders
            $projectName = $_.Name
            Write-Host "`n" -NoNewline
            Write-Host "In project " -NoNewline
            Write-Host -ForegroundColor Red $projectName
            $reportFile =  "$root\$projectName\$projectName.Report\report.json"
            $data = importPowerBIReport $reportFile
            searchReportForQueryReference $data $keywords
        }
}

#pbip #powerbi #powershell