Public/Deploy-SemanticModelProject.ps1
Function Deploy-SemanticModelProject { <# .SYNOPSIS Imports items using the Power BI Project format (PBIP) into a Fabric workspace from a specified file system source. .DESCRIPTION Deploy-SemanticModelProject function uploads a semantic model project from a local file system location to a specified Fabric workspace. It supports overwriting existing items and customizing item properties during deployment. .PARAMETER path The file system path where the semantic model project is located. .PARAMETER workspaceId The ID of the Fabric workspace where the semantic model should be deployed. .PARAMETER itemProperties Optional. A hashtable that lets you override item properties like type and displayName. Example: @{"type" = "SemanticModel"; "displayName"="My Semantic Model"} .PARAMETER overWrite Optional. A switch parameter that, when specified, allows overwriting existing items with the same name in the workspace. .EXAMPLE Deploy-SemanticModelProject -path "C:\Projects\MySemanticModel" -workspaceId "12345678-abcd-1234-abcd-1234567890ab" .EXAMPLE Deploy-SemanticModelProject -path "C:\Projects\MySemanticModel" -workspaceId "12345678-abcd-1234-abcd-1234567890ab" -itemProperties @{"displayName"="Sales Analysis Model"} -overWrite .NOTES Requires appropriate permissions to the target workspace. #> [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$path , [Parameter(Mandatory)] [string]$workspaceId , [hashtable]$itemProperties , [switch]$overWrite ) # Search for folders with .pbir and .pbism in it $itemsInFolder = Get-ChildItem -LiteralPath $path -Depth 1 | Where-Object { @(".pbism") -contains $_.Extension } if ($itemsInFolder.Count -eq 0) { Write-Log "Cannot find valid item definitions ( *.pbism) in the '$path'" return } if ($itemsInFolder | ? { $_.Extension -ieq ".pbism" }) { $itemType = "SemanticModel" } else { throw "Cannot determine the itemType for the path '$path'. Ensure the folder contains a .pbism file." } # Get existing semantic models of the workspace $items = Invoke-FabricAPIRequest -Uri "workspaces/$workspaceId/semanticModels" -Method Get $files = Get-ChildItem -LiteralPath $path -Recurse -Attributes !Directory # Filter out files not required for the API: item.*.json; cache.abf; .pbi folder $files = $files | ? { $_.Name -notlike "item.*.json" -and $_.Name -notlike "*.abf" -and $_.Directory.Name -notlike ".pbi" } # Prioritizes reading the displayName and type from itemProperties parameter $displayName = $null if ($itemProperties -ne $null) { $displayName = $itemProperties.displayName } # Try to read the item properties from the .platform file if not found in itemProperties if ((!$itemType -or !$displayName) -and (Test-Path -LiteralPath "$path\.platform")) { $itemMetadataStr = Get-Content -LiteralPath "$path\.platform" try { $itemMetadata = $itemMetadataStr | ConvertFrom-Json } catch { throw "Failed to parse JSON from .platform file: $_" } $itemType = $itemMetadata.metadata.type $displayName = $itemMetadata.metadata.displayName } if (!$itemType -or !$displayName) { throw "Cannot import item if any of the following properties is missing: itemType, displayName" } $itemPathAbs = Resolve-Path -LiteralPath $path $parts = $files |% { $filePath = $_.FullName $fileContent = Get-Content -LiteralPath $filePath -AsByteStream -Raw $partPath = if ([System.Environment]::OSVersion.Platform -eq 'Unix') { $filePath.Replace($itemPathAbs, "").TrimStart("/").Replace("\", "/") } else { $filePath.Replace($itemPathAbs, "").TrimStart("\").Replace("\", "/") } $fileEncodedContent = ($fileContent) ? [Convert]::ToBase64String($fileContent) : "" Write-Output @{ Path = $partPath Payload = $fileEncodedContent PayloadType = "InlineBase64" } } $itemId = $null # Check if there is already an item with same displayName and type $foundItem = $items | ? { $_.type -ieq $itemType -and $_.displayName -ieq $displayName } # If there is more than one item with the same displayName and type, throw an error if ($foundItem) { if ($foundItem.Count -gt 1) { throw "Found more than one item for displayName '$displayName'" } $itemId = $foundItem.id } # Prepare the request $itemRequest = @{ displayName = $displayName definition = @{ Parts = $parts } } | ConvertTo-Json -Depth 3 # Create the item if ($itemId -eq $null) { Write-Log "Creating a new item" $createItemResult = Invoke-FabricAPIRequest -uri "workspaces/$workspaceId/semanticModels" -method Post -body $itemRequest $itemId = $createItemResult.id Write-Log "Created a new item with ID '$itemId'" -ForegroundColor Green Write-Output @{ "id" = $itemId "displayName" = $displayName "type" = $itemType } }else # Update the item definition { if (!$overWrite) { Write-Log "Item '$displayName' of type '$itemType' already exists. Skipping." -ForegroundColor Yellow } else { Write-Log "Updating item definition" Invoke-FabricAPIRequest -Uri "workspaces/$workspaceId/semanticModels/$itemId/updateDefinition" -Method Post -Body $itemRequest Write-Log "Updated item with ID '$itemId'" -ForegroundColor Green } Write-Output @{ "id" = $itemId "displayName" = $displayName "type" = $itemType } } } |