Power BI Desktop stores measures and calculated columns in the semantic model. If you need to document or extract these calculations, you can export the Power BI report as a .pbit template and use PowerShell to read its DataModelSchema.
Quick answer: Export the PBIX file as a Power BI template (.pbit), then run the PowerShell script below. The script extracts the template to a temporary folder, reads DataModelSchema, exports measures and calculated columns, and creates a CSV file in the same folder as the PBIT. The original PBIT file is not modified.
What is a Power BI template file?
A Power BI report template uses the .pbit extension. Microsoft documents that a PBIT contains report pages and visuals, the semantic model definition—including schema, relationships and measures—and query definitions, but does not contain the report’s source data. This makes it useful for extracting model metadata without exporting the underlying data.
Export the Power BI file as a PBIT
Open the .pbix file in Power BI Desktop and select File > Export > Power BI template. Save the resulting .pbit file to a folder that you can access from PowerShell.

Run the PowerShell script
Copy the script into PowerShell and set $pbitFolderPath to the folder containing the PBIT file. Set $pbiFileName to the PBIT file name without the .pbit extension.

# Export measures and calculated columns from a Power BI PBIT file
# The original .pbit file is never modified.
# ================================================================
# PARAMETERS
# ================================================================
$pbitFolderPath = "C:\Users\rathikun\Downloads"
$pbiFileName = "Sales and Marketing Sample PBIX"
# ================================================================
# PATHS
# ================================================================
$pbitFilePath = Join-Path $pbitFolderPath ($pbiFileName + ".pbit")
$exportMeasuresFilePath = Join-Path $pbitFolderPath ($pbiFileName + " Calculations.csv")
# Create a unique temporary extraction folder
$exportPath = Join-Path $env:TEMP ("PowerBI_PBIT_Export_" + [guid]::NewGuid().ToString())
# ================================================================
# VALIDATE INPUT
# ================================================================
if (-not (Test-Path -LiteralPath $pbitFilePath -PathType Leaf)) {
throw "PBIT file not found: $pbitFilePath"
}
New-Item -ItemType Directory -Path $exportPath -Force | Out-Null
try {
# ============================================================
# EXTRACT PBIT
# ============================================================
$tempZipPath = Join-Path $exportPath "template.zip"
Copy-Item `
-LiteralPath $pbitFilePath `
-Destination $tempZipPath `
-Force
Expand-Archive `
-LiteralPath $tempZipPath `
-DestinationPath $exportPath `
-Force
# Remove the temporary ZIP copy
Remove-Item `
-LiteralPath $tempZipPath `
-Force
# ============================================================
# LOCATE DATAMODELSCHEMA
# ============================================================
$dataModelSchemaPath = Join-Path $exportPath "DataModelSchema"
if (-not (Test-Path -LiteralPath $dataModelSchemaPath -PathType Leaf)) {
throw "DataModelSchema was not found in the PBIT file."
}
# ============================================================
# READ DATAMODELSCHEMA
# ============================================================
# DataModelSchema in the tested PBIT is UTF-16.
$jsonStr = Get-Content `
-LiteralPath $dataModelSchemaPath `
-Encoding Unicode `
-Raw
if ([string]::IsNullOrWhiteSpace($jsonStr)) {
throw "DataModelSchema is empty."
}
# ============================================================
# PARSE JSON
# ============================================================
$outJson = $jsonStr | ConvertFrom-Json
if ($null -eq $outJson.Model) {
throw "The DataModelSchema does not contain a Model object."
}
if ($null -eq $outJson.Model.tables) {
throw "The DataModelSchema does not contain Model.tables."
}
$outTables = @(
$outJson.Model.tables |
Where-Object { $_.isHidden -ne $true }
)
# ============================================================
# COLLECT CALCULATIONS
# ============================================================
$calculations = New-Object System.Collections.Generic.List[object]
foreach ($outTable in $outTables) {
# --------------------------------------------------------
# MEASURES
# --------------------------------------------------------
if ($null -ne $outTable.measures) {
foreach ($outMeasure in @($outTable.measures)) {
$calculations.Add(
[PSCustomObject]@{
'Table Name' = [string]$outTable.name
'Calculation Type' = 'Measure'
'Calculation Name' = [string]$outMeasure.name
'Value' = [string]$outMeasure.expression
}
)
}
}
# --------------------------------------------------------
# CALCULATED COLUMNS
# --------------------------------------------------------
if ($null -ne $outTable.columns) {
$calculatedColumns = @(
$outTable.columns |
Where-Object { $_.type -eq "calculated" }
)
foreach ($outColumn in $calculatedColumns) {
$calculations.Add(
[PSCustomObject]@{
'Table Name' = [string]$outTable.name
'Calculation Type' = 'Calculated column'
'Calculation Name' = [string]$outColumn.name
'Value' = [string]$outColumn.expression
}
)
}
}
}
# ============================================================
# EXPORT CSV
# ============================================================
if ($calculations.Count -eq 0) {
Write-Warning "No measures or calculated columns were found."
# Still create a CSV with the expected headers.
[PSCustomObject]@{
'Table Name' = ''
'Calculation Type' = ''
'Calculation Name' = ''
'Value' = ''
} |
Export-Csv `
-LiteralPath $exportMeasuresFilePath `
-NoTypeInformation `
-Encoding UTF8
}
else {
$calculations |
Export-Csv `
-LiteralPath $exportMeasuresFilePath `
-NoTypeInformation `
-Encoding UTF8
}
# ================================================================
# RESULT
# ================================================================
Write-Host ""
Write-Host "========================================================"
Write-Host "Power BI calculations export completed successfully."
Write-Host "========================================================"
Write-Host ""
Write-Host "Output file:"
Write-Host $exportMeasuresFilePath
Write-Host ""
Write-Host "Calculations exported: $($calculations.Count)"
Write-Host ""
Write-Host "Original PBIT file was not modified."
Write-Host ""
}
finally {
# ============================================================
# CLEANUP
# ============================================================
if (Test-Path -LiteralPath $exportPath) {
Remove-Item `
-LiteralPath $exportPath `
-Recurse `
-Force `
-ErrorAction SilentlyContinue
}
}
The script creates <Power BI filename> Calculations.csv in the same folder as the PBIT. It uses PowerShell’s Export-Csv so commas, quotes, and multiline DAX expressions are properly represented in the CSV.
What the script exports
The script reads the semantic model tables from DataModelSchema, skips hidden tables, and exports two types of calculations:
- Measures and their DAX expressions.
- Calculated columns and their DAX expressions.
The output CSV contains Table Name, Calculation Type, Calculation Name, and Value.
Important notes
- The script works with a Power BI
.pbittemplate, not directly with a.pbixfile. - The original PBIT is copied to a temporary ZIP file for extraction; the original file is never renamed or modified.
- The extraction directory is created under the Windows temporary directory and removed after execution, including when an error occurs.
- The approach reads Power BI’s
DataModelSchemapackage content, so changes to Power BI’s internal template structure could require script updates.
Microsoft documents that PBIT files contain the semantic model definition, including schema, relationships, measures, and other model definition items. See the Microsoft documentation for Power BI report templates.
Pro tips:
1. The script also exports calculated column expressions.
2. If you use DAX Studio, you can also use it to export measures from a Power BI model.
3. To test Power BI row-level security, see How to Test RLS in Power BI Service.
See more
Kunal Rathi
With over 15 years of experience in data engineering and analytics, I've assisted countless clients in gaining valuable insights from their data. As a dedicated supporter of Data, Cloud and DevOps, I'm excited to connect with individuals who share my passion for this field. If my work resonates with you, we can talk and collaborate.






