Writeback vanuit een Power BI rapport naar je data warehouse

Power BI wordt gebruikt om inzichten in bedrijfsprocessen te krijgen en als ondersteuning voor met maken van bedrijfsprocessen. Dit is een eenrichtingsverkeer van informatie voorziening waarbij een gebruiker out of the box niet zomaar ook informatie terug kan zenden naar bijvoorbeeld een onderliggen datawarehouse.
Blog Gerrit

Power BI wordt gebruikt om inzichten in bedrijfsprocessen te krijgen en als ondersteuning voor met maken van bedrijfsprocessen. Dit is een eenrichtingsverkeer van informatie voorziening waarbij een gebruiker out of the box niet zomaar ook informatie terug kan zenden naar bijvoorbeeld een onderliggen datawarehouse. Dit kan soms wel wenselijk zijn voor een bedrijfsproces.

Binnen het Power Platform is het mogelijk om een Power App te maken die je in een Power BI rapport op het canvas kan zetten en waarmee een gebruiker vervolgens data terug kan sturen. Wanneer je deze data echter terug wilt sturen naar een van de premium connectors, zoals bijvoorbeeld een Azure SQL database, dan heb je hiervoor per gebruiker een premium licentie nodig. Deze licentiekosten komen bovenop de Power BI licentie en kunnen al snel erg hoog worden. 

Binnen het Azure landschap is het is echter ook mogelijk om een terugschrijf optie voor gebruikers te maken zonder Power Apps. Een optie hiervoor is om een Azure Function te gebruiken. Met Consumption hosting betaal je alleen de minimale kosten per keer dat je de Azure Function aanroept, ongeacht het aantal gebruikers. Hierbij kunnen we de Managed Identity van de Azure Function gebruiken als service account voor autorisatie wanneer we als doel locatie een service binnen het Azure landschap hebben, zoals een Azure SQL database of een Azure Analysis Services instantie.

In deze blog zal ik een voorbeeld geven hoe je een Azure Function hiervoor kan gebruiken aan de hand van de volgende use case:

Binnen bedrijf X moeten alle inkoop facturen waarbij het totaalbedrag hoger is dan €1000 gecontroleerd worden door een financial controller. Het datawarehouse draait binnen een Azure SQL database. Het rapport staat in een Power BI workspace en is verbonden met een semantisch model gehost in Azure Analysis Services.

Dit is een voorbeeld usecase, het maakt voor deze oplossing niet uit waar het datawarehouse of het semantisch model gehost wordt, zolang deze maar bereikbaar is voor de Azure Function. Wanneer we volledig binnen het Azure landschap blijven is het voordeel wel dat we voor authenicatie gebruik kunnen maken van de System Managed Identity (SMI), wanneer het data warehouse bijvoorbeeld ergens buiten Azure draait dan zal de toegang ook anders ingeregeld moeten worden. 

Benodigde Componenten

Voor deze use case hebben we de volgende componenten nodig:

  • Azure Function App
  • Azure SQL database 
  • Azure Analysis Services
  • Power BI workspace

Azure Function App

We maken een Azure Function App aan onder het Consumption hosting plan. Dan betalen we alleen wanneer we de functie aanroepen. Als runtime stack gebruiken we PowerShell Core.


Na het aanmaken van de Azure Function App moeten we de SMI aanzetten zodat we deze kunnen gebruiken voor authorisatie. Deze vind je onder Settings -> Identity. Zodra we ons data warehouse verder gaan inrichten zullen we deze nodig hebben.

Azure SQL database

Ons data warehouse is gehost binnen een Azure SQL database. We willen niet dat gebruikers via de Function records in ons data warehouse direct kunnen aanpassen, dus we maken een nieuw schema writeBack aan met een tabel POWriteback. We kunnen onze SMI dan rechten geven op dit specifieke schema en in ons semantisch model kunnen we deze tabel koppelen aan de PO data om deze wijzigingen op te halen.

CREATE SCHEMA [writeBack]
GO
CREATE TABLE [writeBack].[POWriteBack] ([recordKey] varchar(25),[Content] varchar(25))
GO

We willen deze SQL gaan benaderen vanuit de Function, dus we moeten toestaan dat deze elkaar kunnen bereiken. Hiervoor zet je bij de SQL server onder Security -> Networking de optie Allow Azure services and resources to access this server aan.
 

Nu moeten we de SMI toevoegen aan de SQL database en ook de juiste rechten geven. Om een gebruiker toe te voegen vanuit het Entra ID gebruik je de optie FROM EXTERNAL PROVIDER. Als gebruikersnaam geef je dan de naam op zoals bekend in het Entra ID tussen blokhaken. We geven rechten specifiek op het nieuw aangemaakte schema writeBack.

CREATE USER [<SMI>] FROM EXTERNAL PROVIDER
GO
GRANT INSERT, UPDATE ON SCHEMA::[writeBack] TO [<SMI>]
GO

Azure Analysis Services

Ons semantisch model is in dit voorbeeld gehost in AAS. Deze oplossing kan met de nodige configuratie ook gebruikt worden wanneer het model in een andere architectuut gehost wordt, zoals Fabric Capacity of Premium Per User. De relevante stukken in ons model zien er als volgt uit:

  • PurchaseInvoices: Deze tabel bevat de inkoop facturen uit ons bronsysteem.
    • recordKey: de primary key voor een factuur.
  • PurchaseInvoicesWriteback: In deze tabel laden we de statussen die we terugschrijven naar de database. Door ze te scheiden van de PurchaseInvoices tabel kunnen we gebruikers de mogelijkheid geven om alleen de statussen bij te laden in het model wat een stuk sneller is dan de complexe logica van de PurchaseInvoices tabel volledig te laden.
    • recordKey: foreign key naar PurchaseInvoices
    • status: de status die een factuur momenteel heeft
  • PurchaseInvoicesWritebackStatus: Deze tabel bevat de mogelijke statussen die we aan een factuur willen hangen. Deze wordt gebruikt in een slicer om de Azure Function call op te bouwen.
    • status:  een lijst van mogelijke statussen
    • order: de volgorde waarin we status willen sorteren

We willen dat we met onze Function App ook de PurchasesInvoicesWriteback tabel kunnen verversen zodat een gebruiker de mogelijkheid heeft om zelf zijn wijzigingen in de rapporten te updaten. Hiervoor moeten we de SMI toevoegen als admin op de Azure Analysis Services instance. De SMI kan je niet vinden in de GUI van Azure, maar je kan hem wel handmatig toevoegen in de vorm app:<Managed Identity ID>@<Tenant ID>.

Power BI

Een plaats waar je het uiteindelijke rapport naar kan hosten, zoals een Power BI Service Pro workspace, zodat je kan samenwerken met je collegas. Dit is verder niet van invloed op de werking van het script dus zal dit punt ook niet verder toegelicht worden.

Azure Function Powershell script

Nu we alle componenten en de onderliggende rechten hebben ingesteld kunnen we de Function gaan aanmaken om vanuit een Power BI rapport data terug te schrijven naar ons data warehouse. We hebben een Powershell Core stack gekozen voor onze Function App, dus we schrijven de scripts ook in PowerShell. We gebruiken een HTTP trigger om onze Functions aan te roepen.

Writeback naar data warehouse

Input

Gebruikers moeten input door kunnen geven zodat we deze vervolgens kunnen verwerken. Hiervoor willen we een key hebben om een record aan te duiden waar de status bij hoort, en welke status deze moet krijgen. Dit kunnen we met onderstaande code doen.

param($Request, $TriggerMetadata)

# Configuration
$global:server = "<SERVER>"
$global:database = "<DATABASE>"

# Get query parameters
$RecordKey = $Request.Query.RecordKey
$Content = $Request.Query.Content
$sqlParameters = @{
    "@RecordKey"=$RecordKey
    "@Content"=$Content
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = [HttpStatusCode]::OK
    Body       = $body
})

Bij het Configuration blok zetten we de globale variabelen neer voor de server en database zodat we deze gemakkelijk om kunnen zetten. Uit het webrequest halen we een RecordKey welke aangeeft bij welk record de status hoort, en Content is de nieuwe status die we mee willen geven. We combineren deze twee parameters in een hash table sqlParameters zodat we deze verderop in de code gemakkelijk kunnen verwerken en we flexibel blijven in het aantal parameters dat we willen gebruiken.

We willen ook feedback geven aan een gebruiker wanneer de code is afgerond. Dat doen we met Push-OutputBinding. Dit geeft een response die we nog gaan opbouwen zodat een gebruiker weet of de status toekenning gelukt is.

Authenticatie

Om te beginnen moeten we in de code een authorizatie token voor Azure SQL databases ophalen vanuit onze SMI. Hiervoor maken we een API call naar de Azure IMDS. Het is ook mogelijk om de Az modules te gebruiken om een token op te vragen via Connect-AzAccount en Get-AzAccessToken. Het nadeel van de Az module is echter dat deze een redelijk lange opstarttijd heeft, wat ervoor zou zorgen dan een gebruiker lang moet wachten. Door gebruik te maken van IMDS vermijden we deze opstarttijd.

function Get-AccessToken {
    param([string]$resource)
    try{
        $tokenAuthUri = $env:IDENTITY_ENDPOINT + "?resource=$resource&api-version=2019-08-01"
        $tokenResponse = Invoke-RestMethod -Method Get -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } -Uri $tokenAuthUri
        $accessToken = $tokenResponse.access_token
        return $response.access_token
    } catch {
        throw "Failed to aquire managed identity token: $($_.Exception.Message)"
    }
}

param([string]$resource)
Als parameter voor de funtie gebruiken we $resource. Dit is de Azure resource waarvoor je een token wilt aanvragen. Door hier een parameter van te maken kunnen we de functie hergebruiken om een token aan te vragen voor verschillende resources. Een token is 1 uur geldig. We weten al dat de doorlooptijd van onze function erg kort is, waardoor we geen rekening hoeven te houden met deze verlooptijd.

$tokenAuthUri = $env:IDENTITY_ENDPOINT + "?resource=$resource&api-version=2022-09-01"
Een Azure Function App waarbij een System Managed Identity aanstaat heeft een omgevings variabele IDENTITY_ENDPOINT welke het IMDS endpoint bevat. Deze combineren we met de Azure resource waar we een token voor willen opvragen en we geven een geldige versie op van de api om te gebruiken. Dit geeft ons het endpoint dat we gaan aanroepen om een token op te halen.

$tokenResponse = Invoke-RestMethod -Method Get -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } -Uri $tokenAuthUri
Hiermee voeren we de API call uit. Als authorizatie geven we de omgevings variabele IDENTITY_HEADER mee welke Azure automatisch aanmaakt als een SMI actief is. Hiermee geven we aan dat we authentificeren met de SMI. Uit $tokenResponse geven we vervolgens het access_token terug.

Alles zit in een try{ } catch{ } blok om fouten op te vangen en in de Function logging terug te geven.

SQL uitvoeren in het data warehouse

Voor het uitvoeren van de SQL maken we onderstaande functie Execute-SQL aan. Als parameters geven het het access token mee, de SQL die we uit willen voeren en de sql parameters die we mee willen geven. Deze zitten in de eerder aangemaakte hash table sqlParameters. We maken hierbij gebruik van de namespace System.Data.SqlClient om een connectie sqlConnection te maken naar ons data warehouse in Azure SQL via authorizatie met de SMI. De foreach loop gaat over alle parameters in onze hash table sqlParameters en voegt ze per stuk toe aan ons SQL commando als parameter.

function Execute-SQL {
    param(
        [string]$accessToken,
        [string]$sqlCommand,
        [hashtable]$sqlParameters
    )
    $connectionString = "Server=tcp:$($global:server).database.windows.net,1433;Database=$($global:database)"
    $sqlConnection = New-Object System.Data.SqlClient.SqlConnection
    $sqlConnection.ConnectionString = $connectionString
    $sqlConnection.AccessToken = $accessToken

    $sqlConnection.Open()
    $command = $sqlConnection.CreateCommand()
    $command.CommandText = $sqlCommand
    foreach ($key in $sqlParameters.Keys) {
        $value = $sqlParameters[$key]
        if ($value -is [int]) {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, [int]$value)
        } elseif ($value -is [datetime]) {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, [datetime]$value)
        } else {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, $value)
        }
        $command.Parameters.Add($param) | Out-Null
    }

    $command.ExecuteNonQuery() | Out-Null
    $sqlConnection.Close()
}

We willen dat een gebruiker een status aan een record kan toewijzen en ook weer kan updaten. Hiervoor gaan we een merge statement uitvoeren op de eerder aangemaakte data warehouse tabel [writeBack].[POWriteBack]. We gebruiken de parameters van de Function als input. Ons sqlCommand wordt als volgt

merge [writeBack].[POWriteBack] P
USING (SELECT @RecordKey AS [RecordKey],@Content AS [Content]) AS S 
    ON (P.[RecordKey]=S.[RecordKey]) 
WHEN MATCHED THEN
    UPDATE SET [Content]=S.[Content]
WHEN NOT MATCHED THEN
    INSERT ([RecordKey],[Content]) VALUES(S.[RecordKey],S.[Content]);

We mergen de parameters RecordKey en Content die we uit de Function krijgen met de POWriteBack tabel. Als er een match is updaten we de status, en anders voegen we een nieuw record toe.

Powershell code

We voegen alles samen en voegen nog wat extra foutafhandeling toe zodat we dit ook naar een gebruiker terug kunnen sturen. De volledige code ziet er dan als volgt uit:

using namespace System.Data.SqlClient
using namespace System.Net

param($Request, $TriggerMetadata)

# Log the request
Write-Host "PowerShell HTTP trigger function processed a request."

# Configuration
$global:server = "<SERVER>"
$global:database = "<DATABASE>"

# Get query parameters
$RecordKey = $Request.Query.RecordKey
$Content = $Request.Query.Content
$sqlParameters = @{
    "@RecordKey" = $RecordKey
    "@Content" = $Content
}

function Get-AccessToken {
    param([string]$resource)
    try {
        $tokenAuthUri = $env:IDENTITY_ENDPOINT + "?resource=$resource&api-version=2019-08-01"
        $tokenResponse = Invoke-RestMethod -Method Get -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } -Uri $tokenAuthUri
        $accessToken = $tokenResponse.access_token
        return $accessToken
    } catch {
        throw "Failed to aquire managed identity token: $($_.Exception.Message)"
    }
}

function Execute-SQL {
    param(
        [string]$accessToken,
        [string]$sqlCommand,
        [hashtable]$sqlParameters
    )
    $connectionString = "Server=tcp:$($global:server).database.windows.net,1433;Database=$($global:database)"
    $sqlConnection = New-Object System.Data.SqlClient.SqlConnection
    $sqlConnection.ConnectionString = $connectionString
    $sqlConnection.AccessToken = $accessToken

    $sqlConnection.Open()
    $command = $sqlConnection.CreateCommand()
    $command.CommandText = $sqlCommand
    foreach ($key in $sqlParameters.Keys) {
        $value = $sqlParameters[$key]
        if ($value -is [int]) {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, [int]$value)
        } elseif ($value -is [datetime]) {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, [datetime]$value)
        } else {
            $param = New-Object System.Data.SqlClient.SqlParameter($key, $value)
        }
        $command.Parameters.Add($param) | Out-Null
    }

    $command.ExecuteNonQuery() | Out-Null
    $sqlConnection.Close()
}

try {
    $accessToken = Get-AccessToken -resource "https://database.windows.net/"

    $sqlCommand = @"
merge [writeBack].[POWriteBack] P
using (select @RecordKey as [RecordKey],@Content as [Content]) AS S 
    on (P.[RecordKey]=S.[RecordKey]) 
when matched then 
    update set [Content]=S.[Content]
when not matched then 
    insert ([RecordKey],[Content]) values(S.[RecordKey],S.[Content]);
"@
    Execute-SQL -accessToken $accessToken -sqlCommand $sqlCommand -sqlParameters $sqlParameters

    $body = "Data saved successfully: RecordKey=$RecordKey, Content=$Content."
    $statusCode = [HttpStatusCode]::OK
} catch {
    $body = "Error writing to database: $($_.Exception.Message)"
    $statusCode = [HttpStatusCode]::InternalServerError
    Write-Host $_.Exception.Message
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = [HttpStatusCode]::OK
    Body       = $body
})

We kunnen deze Function nu aanroepen vanuit een Power BI rapport door de url van de function aan te roepen. Deze kan je vinden in Get function URL en heeft de volgende vorm.

<Function URL>?code=<Autorisatie code>&recordKey=<Key van factuur>&content=<Nieuwe status>

Omdat je in Power BI geen url body kan meegeven zetten we de factuur key en de nieuwe status als parameters in de url.

Verversen status tabel

We willen gebruikers ook een knop geven waarmee ze zelf de status tabel kunnen updaten. Dit geeft gebruikers de vrijheid om de statussen wat vaker te updaten en ze niet op de standaard model verversing hoeven te wachten. Dit trekken we los van het andere script omdat we niet na elke status wijziging de tabel willen updaten. Hiervoor komt dus een andere Function binnen dezelfde Function App. We hergebruiken de functie Get-AccessToken die we eerder al hadden gedefinieerd. Dan kunnen we het onderstaande script gebruiken om de benodigde tabel te updaten. We gebruiken een parameter voor het model en de tabel die we willen verversen zodat we deze Function kunnen hergebruiken. De Azure Analysis Services instance hebben we nu wel hardcoded in de Function gezet, maar deze zou je ook als parameters kunnen toevoegen.

$refreshUrl = "https://$($global:region).asazure.windows.net/servers/$($global:server)/models/$modelName/refreshes"
$accessToken = Get-AccessToken -resource "https://*.asazure.windows.net/"
$refreshBody = "{""type"": ""Full"",""objects"": [{""database"": ""$modelName"",""table"": ""$tableName""}]}"

$response = Invoke-RestMethod -Method POST -Uri $refreshUrl `
  -Headers @{Authorization = "Bearer $accessToken"} `
  -ContentType "application/json" `
  -Body $refreshBody

$refreshUrl = "https://$($global:region).asazure.windows.net/servers/$($global:server)/models/$modelName/refreshes" is het API endpoint voor verversingen van onze Azure Analysis Services. Dit is een asynchroon endpoint en geeft een operationId terug van de verversing. Deze kan je vervolgens weer gebruiken om de status van de verversing op te vragen en deze kan je voor bijvoorbeeld debugging teruggeven naar de eindgebruiker.

$accessToken = Get-AccessToken -resource "https://*.asazure.windows.net/"

is onze eerder gemaakte functie om een authorisatie token op te halen. Voor een Azure Analysis Services token gebruiken we als resource https://*.asazure.windows.net

in $refreshBody = "{""type"": ""Full"",""objects"": [{""database"": ""$modelName"",""table"": ""$tableName""}]}" bouwen we de API body op voor onze verversing call waarin we aangeven wat er ververst moet worden.

in $response = Invoke-RestMethod -Method POST -Uri $refreshUrl -Headers @{Authorization = "Bearer $accessToken"} -ContentType "application/json" -Body $refreshBody voeren we een POST request uit om de verversing te starten.

We voegen weer wat foutafhandeling toe en feedback voor de eindgebruiker zoals in de vorige functie en dan ziet onze volledige code er als volgt uit.

using namespace System.Data.SqlClient
using namespace System.Net

param($Request, $TriggerMetadata)

# Configuration
$global:region = "REGION"
$global:server = "SERVER"

# Get query parameters
$modelName = $Request.Query.modelName
$tableName = $Request.Query.tableName

# Functions
function Get-AccessToken {
    param([string]$resource)
    try{
        $tokenAuthUri = $env:IDENTITY_ENDPOINT + "?resource=$resource&api-version=2019-08-01"
        $tokenResponse = Invoke-RestMethod -Method Get -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } -Uri $tokenAuthUri
        $accessToken = $tokenResponse.access_token
        return $accessToken
    } catch {
        throw "Failed to aquire managed identity token: $($_.Exception.Message)"
    }
}

try{
    $refreshUrl = "https://$($global:region).asazure.windows.net/servers/$($global:server)/models/$modelName/refreshes"
    $accessToken = Get-AccessToken -resource "https://*.asazure.windows.net/"
    $refreshBody = "{""type"": ""Full"",""objects"": [{""database"": ""$modelName"",""table"": ""$tableName""}]}"

    $response = Invoke-RestMethod -Method POST -Uri $refreshUrl `
        -Headers @{Authorization = "Bearer $accessToken"} `
        -ContentType "application/json" `
        -Body $refreshBody

    $body = "Refresh triggered for model $modelName table $tableName (RefreshID: $($response.operationId))"
    $statusCode = [HttpStatusCode]::OK
}catch{
    $body = "Error starting the refresh: $($_.Exception.Message) $refreshBody || $response || $refreshUrl"
    $statusCode = [HttpStatusCode]::InternalServerError
    Write-Host $_.Exception.Message
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $statusCode
    Body       = $body
})

We kunnen deze functie ook weer aanroepen via de Function url en we geven nu de model naam en de tabel om te verversen mee als parameters.

<Function URL>?code=<Autorisatie code>&modelName=<AAS model naam>&tableName=<Tabel om te verversen>

Opbouw in rapport

Nu is bijna alles gereed voor onze oplossing. We maken een slicer met PurchaseInvoiceWritebackStatus[Status] om de status te kiezen die we aan een factuur willen hangen. En we hebben een tabel waarbij we op regelniveau op een url kunnen klikken om de status te updaten. Om de Function url op te bouwen moeten we dynamisch kijken bij welke factuur we zitten en wat de status moet zijn, dus hier gaan we een meetwaarde voor aanmaken.

[SelectedStatus] = SELECTEDVALUE('PurchaseInvoiceWritebackStatus'[Status])

Deze meetwaarde geeft de geselecteerde status terug. Als er geen of meer dan een status geselecteerd is dan is deze meetwaarde leeg. Op deze manier kan men niet perongeluk meer dan een status tegelijk meegeven.

[WritebackURL] = IF(NOT(ISBLANK([SelectedStatus])),
  MAXX('PurchaseInvoices',
    "{Function URL}?code={Function Authorization Code}"
    & "&RecordKey=" & [recordKey]
    & "&Content=" & [SelectedStatus]
  )
)

Deze meetwaarde maakt de Function url om data terug te schrijven. Als parameters geven we de key van de factuur en de geselecteerde status mee terug. We kijken eerst of er wel een status geselecteerd is. Als dit niet het geval is dan laten we ook geen url icoon zien door NOT(ISBLANK()). Bij de metadata van de meetwaarde zet je de data category op WebUrl, dan weet Power BI dat het om een url gaat en kan je deze met het url logo tonen in je rapport in plaats van de volledige url tekst

[RefreshWritebackTable] = "{Function URL}?code={Function Authorization Code}"
  & "&modelName={Model naam}&tableName={Tabel naam}"

En met deze meetwaarde kunnen we de Function aanroepen om alleen de status tabel PurchaseInvoicesWriteback te verversen

Nu kunnen we alles combineren en de functionaliteit testen. In onze dummy dataset hebben momenteel de facturen INV10001, INV10002 en INV10003 al een status. We willen de status van INV10005 veranderen naar Approved en de status van INV10002 veranderen van Under investigation naar Rejected. Zodra we deze twee wijzigingen hebben gedaan willen we de data in het rapport updaten. Door op de linkjes van de relenvante regels te klikken kunnen we de statussen updaten en krijgen we als gebruiker een popup dat het gelukt is. En daarna kunnen we de data in ons rapport up to date maken met de gele Refresh status table knop.

Afsluitend

In deze blog heb ik een voorbeeld gegeven hoe je een goedkope Azure Function in kan zetten om data terug te schrijven naar een datawarehouse en de wijzigingen vervolgens ook in een rapport beschikbaar te maken.  Door gebruik te maken van beveiligingsrollen in je model kan je deze functionaliteit alleen toegangkelijk maken voor de relevante groep collegas. Afhankelijk van de architectuur van je organisatie zoals de hostingplek van je semantische model en waar je datawarehouse draait zullen de scripts nog aangepast worden om de verbinding met de omgevingen te kunnen leggen. Ook andere architectuur keuzes hebben invloed op de beste keus om deze oplossing te implementeren. Bijvoorbeeld als je Azure omgeving binnen een private network draait en je hebt al een Gateway of Integration Runtime server binnen dit netwerk draaien, dan kan je dezelfde oplossing juist in een Azure Automation Account met Hybrid worker draaien.

Wat is de beste oplossing voor jouw organisatie?

Mocht je interesse gewekt zijn dan denken we graag een keer mee wat de beste oplossing voor jouw organisatie kan zijn.

Lees verder

Waarom IT als strategische partner het verschil maakt richting 2026

Ontdek waarom IT evolueert van ondersteuning naar strategische partner en hoe technologie groei, veerkracht en impact bepaalt richting 2026.

Translytical Task Flow

Microsoft's translytical task flow maakt naadloze data write-back mogelijk in Power BI met Fabric SQL database.

Betaal je te veel voor IT die te weinig oplevert?

Betaal je te veel voor IT die te weinig oplevert?

Hoe kan je de IT-uitgaven terugbrengen én tegelijkertijd de impact van allerlei tools, licenties en infrastructuur vergroten?