Microsoft Fabric API + PowerShell: Automatiza la creación de tu arquitectura Medallion
En cada proyecto, siempre hay tareas repetitivas. Automatizarlas no solo optimiza el tiempo, sino que también simplifica el trabajo y mejora la eficiencia.
En proyectos con Microsoft Fabric y siguiendo las buenas prácticas con la famosa arquitectura medallion, lo primero que hacemos es crear las áreas de trabajo y lakehouses de cada capa. El siguiente código realiza estas tareas de forma automática y además, tiene la opción de guardar los secretos en Azure Key Vault.
El código necesita que las siguientes variables estén definidas para que se ejecute con éxito, en caso contrario, aparecerá un mensaje de error comentando la variable que se necesita configurar.
$tenantId
$subscriptionId
$projectName → Nombre que se asignará a las áreas de trabajo
$layers → Definición de las distintas capas que tendrá nuestro proyecto. Los valores se añadirán al nombre de las áreas de trabajo (projectName_layer)
Las variables tenantId y subscriptionId son necesarias porque de momento la conexión se realiza con usuario y no como service principal.
También existen unas variables que se pueden configurar dependiendo de lo siguiente:
$medallionInOneWorkspace: por defecto, su valor es false. Esta variable especifica si la arquitectura medallion se crea en distintas áreas de trabajo o en uno solo. Crear todo en una área de trabajo puede tener sentido para pruebas, donde el área de trabajo se llamará con el nombre de la variable $projectName y se crearán tantos lakehouses como capas definidas en la variable $layers
$azureKeyVault: por defecto, su valor es false. Si quieres almacenar los secretos en Azure Key Vault, debes configurar el valor a true y establecer el nombre del key vault donde se van a almacenar.
La variable $capacityId es “opcional”, si no sabes el id de la capacidad puedes dejarla en blanco y se listarán las capacidades disponibles para que selecciones la deseada

Ejemplo de resultado
Ejecución para crear una arquitectura medallion de 3 capas almacenando los secretos en Azure Key Vault.



Código
######################################################################################################################################
## Asegúrese de que los módulos Az están instalados en su sistema ejecutando 'Install-Module Az'
######################################################################################################################################
$tenantId = "tenantId"
$subscriptionId = "subscriptionId"
$capacityId = ""
$projectName = "projectName"
$layers = @("01_Bronze","02_Silver","03_Gold") # Cambiar nombre de las capas y añadir o quitar según necesidad
$medallionInOneWorkspace = $false
$azureKeyVault = $false
$azureKeyVaultName = "azureKeyVaultName"
if (-not $tenantId) {
Write-Error "El parámetro 'tenantId' es obligatorio. Por favor, configúralo en el script antes de ejecutarlo."
exit 1
}
elseif (-not $subscriptionId){
Write-Error "El parámetro 'subscriptionId' es obligatorio. Por favor, configúralo en el script antes de ejecutarlo."
exit 1
}
elseif (-not $projectName){
Write-Error "El parámetro 'projectName' es obligatorio. Por favor, configúralo en el script antes de ejecutarlo."
exit 1
}
elseif (-not $layers -or $layers.Count -eq 0){
Write-Error "El parámetro 'layers' es obligatorio y debe contener al menos un elemento."
exit 1
}
if($azureKeyVault -and -not $azureKeyVaultName)
{
Write-Error "Error: Se requiere el parámetro 'azureKeyVaultName' cuando 'azureKeyVault' está habilitado (true). Configure 'azureKeyVaultName' y vuelva a ejecutar el script."
exit 1
}
# URL base de la api de Microsoft Fabric
$baseFabricUrl = "https://api.fabric.microsoft.com"
# Inicio de sesión en Fabric
Connect-AzAccount -TenantId $tenantId -Subscription $subscriptionId | Out-Null
# Obtenemos el token
$fabricToken = (Get-AzAccessToken -ResourceUrl $baseFabricUrl).Token
# Crear cabeceras para las llamadas a la API
$headerParams = @{'Authorization'="Bearer {0}" -f $fabricToken}
$contentType = @{'Content-Type' = "application/json"}
$seleccionCapacidad = $false
$opcionesCapacidades = @()
if (-not $capacityId) {
Write-Host "Es necesario especificar el id de la capacidad que se va a utilizar. A continuación se muestran las capacidades disponibles, selecciona cual quieres utilizar:"
Write-Host ""
$capacitiesUri = "{0}/v1/capacities" -f $baseFabricUrl
$capacitiesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $capacitiesUri
foreach ($capacity in $capacitiesList.value) {
Write-Host "ID de la capacidad: $($capacity.id)"
Write-Host "Nombre de la capacidad: $($capacity.displayName)"
Write-Host "SKU: $($capacity.sku)"
Write-Host "Region: $($capacity.region)"
Write-Host "Estado: $($capacity.state)"
Write-Host ""
$opcionesCapacidades += $capacity.displayName
}
$opcionesCapacidades += "Salir"
$valorSeleccionado = $null
while (-not $seleccionCapacidad) {
# Mostramos las opciones
Write-Host "Por favor, escribe el nombre de la capacidad que quieres utilizar:"
$opcionesCapacidades | ForEach-Object { Write-Host "- $_" }
# Pedimos seleccionar la capacidad
$valorSeleccionado = Read-Host "Ingrese su elección"
# Validar la selección
if ($opcionesCapacidades -contains $valorSeleccionado) {
if ($valorSeleccionado -eq "Salir") {
Write-Host "Has decidido finalizar la ejecución. Saliendo..." -ForegroundColor Red
Exit
} else {
Write-Host "Has seleccionado: $valorSeleccionado" -ForegroundColor Green
foreach ($capacity in $capacitiesList.value){
if($capacity.displayName -eq $valorSeleccionado){
$capacityId = $capacity.id
Write-Host "El ID de la capacidad seleccionada es: $($capacity.id)" -ForegroundColor Green
}
}
$seleccionCapacidad = $true
}
} else {
Write-Host "Selección no válida. Inténtalo de nuevo." -ForegroundColor Yellow
}
}
}
Write-Host ""
$workspacesDisponibles = @()
$workspaceId = ""
# Si la variable es true, generamos todo en un área de trabajo
if ($medallionInOneWorkspace)
{
######################################################################################################################################
## ÁREA DE TRABAJO
##
## Se comprueba si existe el área de trabajo. Si existe, obtenemos el workspaceId, sino, creamos el área de trabajo
## y obtenemos el workspaceId.
##
######################################################################################################################################
Write-Host "El script está configurado para crear todo en una área de trabajo"
Write-Host "Inicializando la creación del área de trabajo..."
Write-Host ""
# Listamos las áreas de trabajo
$workspacesUri = "{0}/v1/workspaces" -f $baseFabricUrl
$workspacesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $workspacesUri
foreach ($workspace in $workspacesList.value)
{
$workspacesDisponibles += $workspace.displayName
}
if ($workspacesDisponibles -contains $projectName)
{
Write-Host "El workspace $($projectName) ya existe. Se crearán los objetos sobre esta área de trabajo."
foreach ($workspace in $workspacesList.value)
{
if($workspace.displayName -eq $projectName)
{
$workspaceId = $workspace.id
Write-Host "Workspace Name: $($workspace.displayName)" -ForegroundColor Cyan
Write-Host "Workspace ID: $($workspace.id)" -ForegroundColor Cyan
Write-Host "Capacity ID: $($workspace.capacityId)" -ForegroundColor Cyan
Write-Host ""
}
}
if($azureKeyVault)
{
# Establecer los valores de los secretos del Workspace al KeyVault
$body = @{
"value" = $workspace.id
} | ConvertTo-Json -Depth 1
try{
#Invoke-RestMethod -Headers $headerParams -Method Put -Uri "$($vaultUri)/secrets/fabric-workspace-id" -Body $body
$secureStringValue = ConvertTo-SecureString -String $workspaceId -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$($projectName)-workspace-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
}
else
{
Write-Host "Creando área de trabajo $($projectName)..."
$body = @{
"displayName" = $projectName;
"capacityId" = $capacityId
} | ConvertTo-Json -Depth 10
try {
$response = Invoke-RestMethod -Headers $headerParams -Method POST -Uri $workspacesUri -Body $body -ContentType "application/json"
Write-Host "Área de trabajo creada con éxito:" -ForegroundColor Green
Write-Host "ID del área de trabajo: $($response.id)" -ForegroundColor Green
Write-Host ""
$workspaceId = $response.id
if($azureKeyVault)
{
# Establecer los valores de los secretos del Workspace al KeyVault
$body = @{
"value" = $response.id
} | ConvertTo-Json -Depth 1
try{
#Invoke-RestMethod -Headers $headerParams -Method Put -Uri "$($vaultUri)/secrets/fabric-workspace-id" -Body $body
$secureStringValue = ConvertTo-SecureString -String $response.id -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$($projectName)-workspace-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
}
catch {
Write-Host "Error al crear el área de trabajo: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
######################################################################################################################################
## LAKEHOUSE
##
## Se crean tantos lakehouse como capas se hayan definido con la nomenclatura (projectName)_(layer)
##
######################################################################################################################################
Write-Host "Inicializando la creación de los lakehouses..."
Write-Host ""
$lakehousesUri = "{0}/v1/workspaces/{1}/lakehouses" -f $baseFabricUrl, $workspaceId
$lakehousesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $lakehousesUri
$lakehousesExistentes = @()
try {
$lakehousesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $lakehousesUri
if (-not $lakehousesList)
{
Write-Host "La API no devolvió ningún lakehouse." -ForegroundColor Yellow
}
else
{
foreach ($lakehouse in $lakehousesList.value) {
$lakehousesExistentes += $lakehouse.displayName
}
}
}
catch {
Write-Host "Error al obtener los lakehouses: $($_.Exception.Message)" -ForegroundColor Red
}
foreach ($layer in $layers)
{
$lakehouseName = "$projectName`_$layer`_lh"
if($lakehousesExistentes -notcontains $lakehouseName)
{
Write-Host "Creando lakehouse $($lakehouseName)..."
$body = @{
"displayName" = $lakehouseName
} | ConvertTo-Json -Depth 10
try {
$response = Invoke-RestMethod -Headers $headerParams -Method POST -Uri $lakehousesUri -Body $body -ContentType "application/json"
Write-Host "Lakehouse $($lakehouseName) creado con éxito:" -ForegroundColor Green
Write-Host "ID del lakehouse: $($response.id)" -ForegroundColor Green
if($azureKeyVault)
{
$body = @{
"value" = $response.id
} | ConvertTo-Json -Depth 1
try{
$secureStringValue = ConvertTo-SecureString -String $response.id -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$projectName-$layer-lh-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
}
catch {
Write-Host "Error al crear el lakehouse: $($_.Exception.Message)" -ForegroundColor Red
}
}
else{
Write-Host "El lakehouse $($lakehouseName) ya existe." -ForegroundColor Yellow
}
Write-Host ""
}
}
# Si la variable es false, generamos cada capa en un área de trabajo distinta
else
{
######################################################################################################################################
## ÁREA DE TRABAJO
##
## Se comprueba si existe el área de trabajo. Si existe, obtenemos el workspaceId, sino, creamos el área de trabajo
## y obtenemos el workspaceId.
##
######################################################################################################################################
Write-Host "El script está configurado para crear un área de trabajo para cada capa"
Write-Host "Inicializando la creación del área de trabajo..."
Write-Host ""
# Listamos las áreas de trabajo
$workspacesUri = "{0}/v1/workspaces" -f $baseFabricUrl
$workspacesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $workspacesUri
foreach ($workspace in $workspacesList.value)
{
$workspacesDisponibles += $workspace.displayName
}
foreach ($layer in $layers) {
$WorkspaceName = "$projectName`_$layer"
if ($workspacesDisponibles -contains $WorkspaceName) {
Write-Host "El workspace $($WorkspaceName) ya existe. Se crearán los objetos sobre esta área de trabajo."
foreach ($workspace in $workspacesList.value)
{
if($workspace.displayName -eq $WorkspaceName)
{
$workspaceId = $workspace.id
Write-Host "Workspace Name: $($workspace.displayName)" -ForegroundColor Cyan
Write-Host "Workspace ID: $($workspace.id)" -ForegroundColor Cyan
Write-Host "Capacity ID: $($workspace.capacityId)" -ForegroundColor Cyan
Write-Host ""
}
}
if($azureKeyVault)
{
# Establecer los valores de los secretos del Workspace al KeyVault
$body = @{
"value" = $workspace.id
} | ConvertTo-Json -Depth 1
try{
$secureStringValue = ConvertTo-SecureString -String $workspaceId -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$($projectName)-$($layer)-workspace-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
} else {
Write-Host "Creando área de trabajo $($WorkspaceName)..."
$body = @{
"displayName" = $WorkspaceName;
"capacityId" = $capacityId
} | ConvertTo-Json -Depth 10
try {
$response = Invoke-RestMethod -Headers $headerParams -Method POST -Uri $workspacesUri -Body $body -ContentType "application/json"
Write-Host "Área de trabajo creada con éxito:" -ForegroundColor Green
Write-Host "ID del área de trabajo: $($response.id)" -ForegroundColor Green
Write-Host ""
$workspaceId = $response.id
if($azureKeyVault)
{
# Establecer los valores de los secretos del Workspace al KeyVault
$body = @{
"value" = $response.id
} | ConvertTo-Json -Depth 1
try{
#Invoke-RestMethod -Headers $headerParams -Method Put -Uri "$($vaultUri)/secrets/fabric-workspace-id" -Body $body
$secureStringValue = ConvertTo-SecureString -String $response.id -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$($projectName)-$($layer)-workspace-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
}
catch {
Write-Host "Error al crear el área de trabajo: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
######################################################################################################################################
## LAKEHOUSE
##
## Se crea el lakehouse correspondiente de la capa
##
######################################################################################################################################
Write-Host "Inicializando la creación del lakehouse..."
Write-Host ""
$lakehousesUri = "{0}/v1/workspaces/{1}/lakehouses" -f $baseFabricUrl, $workspaceId
$lakehousesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $lakehousesUri
$lakehousesExistentes = @()
try {
$lakehousesList = Invoke-RestMethod -Headers $headerParams -ContentType $contentType -Method GET -Uri $lakehousesUri
if (-not $lakehousesList)
{
Write-Host "La API no devolvió ningún lakehouse." -ForegroundColor Yellow
}
else
{
foreach ($lakehouse in $lakehousesList.value) {
$lakehousesExistentes += $lakehouse.displayName
}
}
}
catch {
Write-Host "Error al obtener los lakehouses: $($_.Exception.Message)" -ForegroundColor Red
}
$lakehouseName = "$projectName`_$layer`_lh"
if($lakehousesExistentes -notcontains $lakehouseName)
{
Write-Host "Creando lakehouse $($lakehouseName)..."
$body = @{
"displayName" = $lakehouseName
} | ConvertTo-Json -Depth 10
try {
$response = Invoke-RestMethod -Headers $headerParams -Method POST -Uri $lakehousesUri -Body $body -ContentType "application/json"
Write-Host "Lakehouse $($lakehouseName) creado con éxito:" -ForegroundColor Green
Write-Host "ID del lakehouse: $($response.id)" -ForegroundColor Green
if($azureKeyVault)
{
$body = @{
"value" = $response.id
} | ConvertTo-Json -Depth 1
try{
$secureStringValue = ConvertTo-SecureString -String $response.id -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $azureKeyVaultName -Name "$($projectName)-$($layer)-lh-id".ToLower().Replace("_", "-") -SecretValue $secureStringValue
}
catch {
Write-Host "Error al establecer el valor del secreto: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
}
catch {
Write-Host "Error al crear el lakehouse: $($_.Exception.Message)" -ForegroundColor Red
}
}
else{
Write-Host "El lakehouse $($lakehouseName) ya existe." -ForegroundColor Yellow
}
Write-Host ""
}
}



