Breakthrough! Edit a model.bim file through PowerShell
Find and replace
I've always wanted to be able to edit a Power BI file through PowerShell. I've never succeeded until today!
Today, I was able to write a script that does a find-and-replace through several Power Query scripts within a model.bim
file, and saves it back. The saving it back has always been point where I fail, but today I succeeded.
Soon, I'll write some functions so that you can edit Power Query and DAX as text files in a folder in VS Code, and make it write back to Power BI. Stay tuned!
$projectName = "project name"
$old = "old text"
$new = "new text"
$modelFilePath = '.\folder\$projectName\$projectName.SemanticModel\model.bim'
$modelFile = (cat "$modelFilePath" | convertfrom-json -depth 100)
$modelFile.model.tables |
% {
# remember that the expression property is an array, where every line is a separate element
[string[]] $expression = $_.partitions.source.expression
# for every line in the array "$expression"...
$newExpression = $expression |
foreach-object {
# the main operation here is replacing some text
$_.replace($old, $new)
}
# save it back in to the object
$_.partitions.source.expression = $newExpression
}
# save the whole thing back in to model.bim
$modelFile | convertto-json -depth 100 > "$modelFilePath"
Extra section: Graffiti
Writing back to every single PQ script programmatically also opens up the ability to tag every script with your name (or whatever else you like). Here, I compose a signature as a multi-line comment, which will be appended to the top of every PQ script to be found in the target data model.
I also have a marker so that I can check if a script has already been tagged - no use in tagging something twice.
# specify the folder where the .pbip lives
$projectFolder = ".\Project Name"
$projectName = $projectFolder.split('\')[-1]
$modelFile = "$projectFolder\$projectName.SemanticModel\model.bim"
$model = (cat $modelFile | convertfrom-json)
# $model
$marker = @("// # SIGNED")
$signature = @(
"/*"
"====================================="
"MADE BY ME"
"$(Get-Date -format "dd-MM-yyyy")"
"====================================="
"*/"
""
)
# unloaded PQ
$model.model.expressions |
% {
# if it hasn't been tagged yet, then tag it
if (([string[]] $_.expression )[0] -ne $marker) {
# put signed marker and signature at the top of the expression
[string[]] $_.expression = $marker + $signature + $_.expression
}
}
# tables
$model.model.tables.partitions |
? {
$_.source.type -eq "m"
} |
% {
# if it hasn't been tagged yet, then tag it
if (([string[]] $_.source.expression )[0] -ne $marker) {
# put signed marker and signature at the top of the expression
[string[]] $_.source.expression = $marker + $signature + $_.source.expression
}
}
# write back into the model file!
$model | convertto-json -depth 100 > $modelfile