Spending Comparisons In Azure Governance: Kosteninzicht Over Abonnementen En Omgevingen

💼 Management Samenvatting

Spending comparisons brengen clouduitgaven gestructureerd in kaart over abonnementen, businessunits en omgevingen heen, zodat bestuurders en financiële teams niet langer hoeven te sturen op losse facturen maar op heldere, reproduceerbare kosteninzichten.

Aanbeveling
IMPLEMENTEER VOOR KOSTENINZICHT EN FINOPS-GOVERNANCE
Risico zonder
Medium
Risk Score
6/10
Implementatie
14u (tech: 8u)
Van toepassing op:
Azure Subscriptions
Management Groups

Zonder systematische spending comparisons ontstaat in veel organisaties een gefragmenteerd beeld van clouduitgaven. Elke afdeling kijkt naar zijn eigen factuur, kosten worden handmatig in Excel bij elkaar gezocht en vergelijkingen tussen productie, test en ontwikkelomgevingen zijn tijdrovend en foutgevoelig. Daardoor vallen structurele kostenlekken niet op: testabonnementen groeien ongemerkt harder dan productie, experimenten worden nooit opgeruimd en identieke workloads blijken in verschillende regio’s of prijsplannen te draaien met forse prijsverschillen. Voor Nederlandse overheidsorganisaties en andere gereguleerde sectoren is dit extra risicovol. De Algemene Rekenkamer en interne controllers verwachten dat publieke middelen aantoonbaar doelmatig worden besteed en dat overschrijdingen vroegtijdig worden gesignaleerd. Wanneer kosten pas zichtbaar worden bij de maand- of jaarafsluiting, is het vaak te laat om nog bij te sturen en resteert vooral verklaren in plaats van voorkomen. Bovendien bemoeilijkt gebrekkig kosteninzicht het gesprek met leveranciers én met het eigen bestuur: men voelt dat de cloud “duur” is, maar kan niet scherp aanwijzen waar onnodige uitgaven precies ontstaan. Dit vergroot de kans op generieke bezuinigingen (bijvoorbeeld een investeringsstop) in plaats van gerichte optimalisatie. Zonder gestructureerde spending comparisons ontbreekt de basis voor volwassen FinOps-praktijken, waardoor clouduitgaven sneller groeien dan de toegevoegde waarde die de cloud oplevert.

PowerShell Modules Vereist
Primary API: Azure API
Connection: Connect-AzAccount
Required Modules: Az.Accounts, Az.CostManagement

Implementatie

Dit artikel beschrijft hoe u in Azure een governance-aanpak voor spending comparisons opzet die zowel financieel inzicht als sturing ondersteunt. We gaan in op de keuze van analyseeenheden (abonnement, management group, costcenter en applicatie), het inrichten van consistente tagging zodat kosten betrouwbaar kunnen worden gegroepeerd, en het opbouwen van dashboards die uitgaven per omgeving (productie, acceptatie, test en ontwikkeling) naast elkaar zetten. Daarbij wordt uitgelegd hoe u Azure Cost Management, budgets en exports inzet om historische kostenreeksen op te bouwen, hoe u pieken en afwijkingen herkent en hoe u scenario’s opstelt zoals “wat als we alle niet-productieomgevingen ’s nachts uitschakelen?”. Vervolgens laten we zien hoe een ondersteunend PowerShell-script, spending-comparisons.ps1, periodiek kerncijfers kan ophalen (bijvoorbeeld kosten per abonnement en per Environment-tag), deze consolideert tot een compact rapport en duidelijke aanbevelingen genereert voor optimalisatie. De nadruk ligt op praktische toepasbaarheid: een aanpak die uitvoerbaar is voor middelgrote organisaties, goed aansluit op bestaande governance-structuren en auditors in één oogopslag laat zien dat kosten actief worden bewaakt.

Vereisten voor betrouwbare spending comparisons

Betrouwbare spending comparisons beginnen niet bij tooling, maar bij heldere afspraken over verantwoordelijkheid, datakwaliteit en analyseeenheden. Een eerste vereiste is dat de organisatiestructuur wordt vertaald naar een consistente Azure-structuur: management groups weerspiegelen bijvoorbeeld hoofdafdelingen of domeinen, individuele abonnementen volgen logische scheidslijnen zoals productie versus niet-productie, en resourcegroepen groeperen samenhangende workloads. Zonder deze basis ontstaat al bij de eerste vergelijking ruis: kosten van één applicatie blijken over meerdere niet-logische abonnementen of resourcegroepen verspreid, waardoor niemand precies weet welke uitgaven bij welke businessfunctie horen. Daarnaast moet een minimale set tags organisatiebreed verplicht zijn, in ieder geval Environment, CostCenter, Application en Owner. Deze tags maken het mogelijk om dezelfde kostenstroom vanuit verschillende invalshoeken te bekijken: per costcenter voor de financiële afdeling, per applicatie voor productowners en per omgevingstype voor het cloud governance team. Wanneer tags optioneel zijn of onvolledig worden toegepast, kloppen totalen misschien nog wel, maar vallen detailanalyses en eerlijk vergelijken uit elkaar.

Een tweede vereiste is dat de databronnen voor spending comparisons stabiel en reproduceerbaar zijn. Azure Cost Management levert standaard dashboards, maar voor governance-doeleinden is het essentieel om ook ruwe kostengegevens periodiek te exporteren naar een centrale locatie, bijvoorbeeld een opslagaccount of Log Analytics-workspace. Alleen dan kunnen historische reeksen worden opgebouwd, kan worden teruggekeken naar eerdere kwartalen en kunnen scenario’s worden doorgerekend. Voor Nederlandse overheidsorganisaties speelt bovendien dat financiële cijfers vaak moeten aansluiten op de reguliere financiële administratie en begrotingscyclus. Dat betekent dat definities – bijvoorbeeld wat precies onder het costcenter “Digitale Werkplek” valt – expliciet moeten worden vastgelegd en afgestemd met de financiële functie. Zonder eenduidige definities ontstaan eindeloze discussies over bedragen in plaats van over optimalisatiemogelijkheden. Het governance-team moet daarom samen met finance en de CISO een begrippenkader ontwikkelen: wat verstaan we onder clouduitgaven, welke posten nemen we wel of niet mee, en welke valuta en periodes gebruiken we standaard in rapportages?

Derde vereiste is eigenaarschap over kosten. Voor elke management group, elk abonnement en elk costcenter moet helder zijn wie aanspreekbaar is op afwijkingen. In de praktijk betekent dit dat abonnementen een formeel aangewezen eigenaar hebben (bij voorkeur vastgelegd via de Owner-tag en in Azure AD-rollen), dat per applicatie een productowner is benoemd die begrijpt welke resources bij zijn of haar dienst horen en dat de financieel verantwoordelijke per kostenplaats structureel meeleest in de rapportages. Spending comparisons zonder gekoppeld eigenaarschap leiden zelden tot actie: iedereen herkent wel dat bepaalde grafieken “hoog” staan, maar niemand voelt zich werkelijk verantwoordelijk om verbetermaatregelen in te zetten. Door eigenaarschap expliciet te koppelen aan dashboards en rapporten – bijvoorbeeld door per businessline een eigen overzicht te tonen – ontstaat een gezonde vorm van interne benchmarking: afdelingen willen niet structureel slechter presteren dan vergelijkbare peers en worden uit zichzelf actiever in het optimaliseren van hun verbruik.

Ten vierde is er een minimale set technische randvoorwaarden nodig. De Az.Accounts- en Az.CostManagement-modules moeten beschikbaar zijn voor de beheerders die kostenrapportages genereren, service principals voor geautomatiseerde scripts moeten ten minste leestoegang hebben op het niveau van de relevante management groups, en netwerkrestricties mogen het ophalen van kosteninformatie niet verhinderen. Voor organisaties die een gescheiden beheer- en productienetwerk hebben, is het raadzaam om kostenrapportages in een dedicated beheerabonnement te draaien waaruit alleen leesrechten naar productieabonnementen worden verleend. Dit beperkt de kans op ongewenste wijzigingen in productieomgevingen terwijl wel volledig kosteninzicht beschikbaar is. Daarnaast is het verstandig om een testtenant of testabonnement te gebruiken om query’s en scripts te valideren voordat ze op de productieomgeving worden toegepast, zodat de kans op foutieve rapportages of onverwachte API-limieten minimaal is.

Tot slot vraagt een volwassen spending-comparisonsproces om organisatorische borging. De analyse van kosten mag geen ad-hoc activiteit zijn die alleen wordt uitgevoerd wanneer een factuur tegenvalt, maar moet onderdeel worden van de reguliere governance- en planning & control-cyclus. Dat betekent dat er vaste overlegmomenten zijn – bijvoorbeeld maandelijkse FinOps- of cloudgovernance-sessies – waarin de belangrijkste grafieken en tabellen worden besproken: welke abonnementen wijken uit de pas, welke omgevingen groeien sneller dan gepland, welke projecten leveren opvallend weinig waarde ten opzichte van hun kosten? De uitkomsten van deze sessies moeten worden vertaald naar concrete acties (zoals het uitfaseren van ongebruikte resources, het herontwerpen van dure architecturen of het aanscherpen van automatische schaling) en deze acties moeten worden opgevolgd. Zonder deze structurele verankering blijft spending comparisons een eenmalige exercitie en verdwijnt het kosteninzicht weer zodra de aandacht verslapt.

Implementatie van spending comparisons in Azure

Gebruik PowerShell-script spending-comparisons.ps1 (functie Invoke-Implementation) – Voert een basisimplementatie uit van kostenvergelijkingen op abonnements- en taggingniveau en genereert een samenvattend rapport..

De implementatie van spending comparisons begint met het expliciet kiezen van de analyseeenheden die voor de organisatie het belangrijkst zijn. In de meeste Nederlandse organisaties gaat het om drie perspectieven: per abonnement (voor technische sturing en licentiebeheer), per costcenter (voor financiële verantwoording) en per omgeving (productie, acceptatie, test en ontwikkeling) voor risicogestuurde besluitvorming. In Azure Cost Management configureert u daarom standaardweergaven waarin kosten per abonnement worden gegroepeerd en gefilterd op de periode die aansluit bij uw rapportagecyclus, bijvoorbeeld maand of kwartaal. Vervolgens bouwt u aangepaste weergaven waarin u niet langer op abonnement maar op CostCenter- of Application-tags groepeert. Hierdoor wordt in één oogopslag zichtbaar welke afdelingen of applicaties de grootste kostenposten vormen, ongeacht in welk abonnement zij draaien. Door deze weergaven als favoriet op te slaan en te delen met relevante stakeholders ontstaat een gemeenschappelijk startpunt voor elke kostenanalyse.

Daarna richt u exports en datasets in waarmee kosten automatisch buiten de portal beschikbaar komen voor diepere analyse. In Azure Cost Management kunt u dag- of maandelijkse exports configureren naar een opslagaccount in de tenant, waarbij u kiest voor een CSV- of Parquet-formaat dat eenvoudig kan worden ingelezen in Power BI of andere rapportagetools. Het is verstandig om ten minste één export op tenantniveau te configureren (voor een totaaloverzicht) en aanvullende exports per management group of grote businessline voor fijnmaziger analyses. Deze exports vormen de basis voor historische spending comparisons: u kunt meerdere kwartalen naast elkaar leggen, groeipercentages berekenen per abonnement of applicatie en inzicht krijgen in seizoenspatronen. Voor overheidsorganisaties kunnen deze datasets bovendien worden gekoppeld aan de reguliere financiële administratie, zodat cloudkosten herkenbaar terugkomen in de jaarrekening en verantwoordingsdocumenten.

Het Power BI- of dashboardlandschap dat hierop wordt gebouwd, vertaalt ruwe kostendata naar bestuurbare informatie. Een goed startpunt is een overzichtspagina met drie hoofdvisualisaties: een staafdiagram met kosten per management group of businessline, een matrix met kosten per Environment-tag en abonnement, en een tijdlijn die de totale clouduitgaven per maand toont met een voortschrijdend gemiddelde. Vanuit deze pagina kan worden doorgeklikt naar detailoverzichten per applicatie of costcenter, waar beheerders en productowners precies zien welke resources de grootste bijdrage leveren aan de kosten. Belangrijk is dat rapporten niet alleen bedragen tonen, maar ook context: bijvoorbeeld het aantal actieve abonnementen, het aantal resources per categorie en indicatoren voor de mate waarin besparingsmaatregelen zijn toegepast (zoals het percentage virtuele machines met autoscaling of het aantal uitgeschakelde niet-productieomgevingen buiten kantoortijden). Zo wordt spending comparisons niet slechts een financiële rapportage, maar een integraal stuurinstrument voor zowel IT als finance.

Het script spending-comparisons.ps1 in deze baseline ondersteunt deze implementatie met een reproduceerbare technische basis. Het script leest, afhankelijk van de ingestelde parameters, de kosten op voor alle of een geselecteerde set abonnementen over een standaardperiode (bijvoorbeeld de afgelopen 30 dagen) en groepeert resultaten per Environment- en CostCenter-tag. Het genereert een samenvattend PowerShell-object en schrijft optioneel een CSV-bestand weg dat direct kan worden gebruikt in rapportages of kan worden gekoppeld aan bestaande FinOps-dashboards. In tegenstelling tot handmatige exports biedt dit script het voordeel dat dezelfde logica keer op keer identiek wordt uitgevoerd; definities van wat precies tot een bepaalde omgeving behoort, liggen vast in code in plaats van in losse Excel-formules. Bovendien kan het script eenvoudig worden geïntegreerd in een geautomatiseerde job, bijvoorbeeld via Azure Automation of een CI/CD-pijplijn, waardoor spending comparisons een vaste cadans krijgen binnen de governance-cyclus.

Bij de implementatie van spending comparisons is het van belang expliciet aandacht te besteden aan datakwaliteit en validatie. Voordat u rapporten breed deelt, moet worden gecontroleerd of de opgetelde kosten overeenkomen met de officiële facturen van de leverancier en of bekende scenario’s – zoals een grote migratie of de uitfasering van een datacenter – zichtbaar en logisch zijn in de grafieken. Een praktische aanpak is om in de eerste fase te werken met een beperkt aantal “pilottargets”: bijvoorbeeld één businessline, één grote applicatie en één generiek productieabonnement. Samen met de betrokken productowner en financieel controller worden deze pilotdashboards grondig doorgenomen: kloppen de bedragen, zijn de gekozen aggregaties logisch en ontbreken er geen belangrijke kostenposten? Pas wanneer deze validatiefase succesvol is afgerond, wordt de methode opgeschaald naar de gehele organisatie. Dit voorkomt dat vertrouwen in het kostenraamwerk vroegtijdig wordt beschadigd door verkeerde cijfers of onduidelijke definities.

Monitoring en sturing op basis van spending comparisons

Gebruik PowerShell-script spending-comparisons.ps1 (functie Invoke-Monitoring) – Voert periodieke kostenvergelijkingen uit en retourneert een compact compliance- en optimalisatieoverzicht..

Wanneer de technische fundamenten eenmaal liggen, verschuift de aandacht naar de vraag hoe spending comparisons structureel worden gebruikt in de dagelijkse aansturing. Een volwassen monitoringaanpak kent meerdere ritmes: wekelijkse operationele checks, maandelijkse FinOps-rapportages en kwartaalreviews met bestuur of directie. Op weekbasis richt u zich vooral op uitzonderingen en plotselinge afwijkingen. Het spending-comparisons-script wordt bijvoorbeeld één keer per week gedraaid en vergelijkt de uitgaven van de afgelopen zeven of dertig dagen met het gemiddelde van de voorgaande periode. Abonnementen of applicaties met een groei boven een vooraf ingestelde drempel (bijvoorbeeld twintig procent) worden in het rapport expliciet uitgelicht. Dit stelt technische beheerders in staat om snel te onderzoeken of de stijging verklaarbaar is – bijvoorbeeld door een geplande uitrol – of dat sprake is van onbedoeld verbruik, vergeten resources of zelfs een mogelijk beveiligingsincident.

Maandelijkse rapportages verschuiven de focus van incidentgedreven ingrijpen naar trendanalyse en optimalisatie. In deze rapporten worden kosten per businessline, omgeving en applicatie naast elkaar gezet, aangevuld met indicatoren zoals het percentage uitgaven dat naar niet-productieomgevingen gaat, de verhouding compute versus opslag, en de kostenontwikkeling per dienstcategorie (zoals virtuele machines, databases en PaaS-diensten). Voor Nederlandse overheidsorganisaties is het zinvol om deze rapporten te koppelen aan de reguliere planning & control-cyclus: dezelfde grafieken worden bijvoorbeeld gebruikt in kwartaalrapportages richting de CIO, de CISO en het lijnmanagement. Door in elke cyclus dezelfde KPI’s te tonen – bijvoorbeeld “percentage kosten in niet-productieomgevingen” of “top vijf duurste applicaties” – ontstaat een herkenbaar verhaal en kunnen verbetermaatregelen over meerdere kwartalen worden gevolgd. Het spending-comparisons-script kan hierbij dienen als bron voor een gestandaardiseerde dataset waarop Power BI-rapporten zijn gebaseerd, waardoor handmatige bewerkingen tot een minimum worden beperkt.

Op kwartaalbasis biedt spending comparisons input voor meer strategische discussies: sluit de verdeling van clouduitgaven nog aan bij de prioriteiten uit de digitale strategie, zijn er diensten die structureel veel kosten maar weinig waarde leveren, en waar liggen de grootste optimalisatiekansen voor het komende jaar? In deze sessies is het waardevol om niet alleen naar absolute bedragen te kijken, maar ook naar kosten per gebruiker, per transactie of per dienst. Voor een digitale werkplekomgeving kan bijvoorbeeld worden berekend wat de gemiddelde maandelijkse cloudkosten per medewerker zijn, terwijl voor een burgerportaal de kosten per duizend transacties inzichtelijk kunnen worden gemaakt. Wanneer zulke ratio’s worden gecombineerd met kwaliteits- en beschikbaarheidsindicatoren, ontstaat een gebalanceerd beeld waarmee bestuurders onderbouwde keuzes kunnen maken: welke diensten mogen iets meer kosten omdat zij cruciaal zijn voor dienstverlening aan burgers, en welke kunnen scherper worden geoptimaliseerd zonder dat de kwaliteit merkbaar daalt?

Een belangrijke succesfactor bij monitoring is dat spending comparisons niet worden gebruikt als instrument om individuele teams ‘af te rekenen’, maar als gezamenlijke basis voor verbetering. Dat betekent dat dashboards zo zijn ingericht dat teams zichzelf kunnen vergelijken met peers en best practices kunnen overnemen. Wanneer één ontwikkelteam er bijvoorbeeld in slaagt om het aandeel niet-productiekosten binnen drie kwartalen met dertig procent te verlagen door agressiever uitzetten van testomgevingen, kan hun werkwijze worden gedocumenteerd en als voorbeeld dienen voor andere teams. Het governance-team faciliteert deze kennisdeling door goede praktijkvoorbeelden uit te lichten in rapportages en overlegstructuren. Het spending-comparisons-script kan hierbij helpen door niet alleen kosten te tonen, maar ook een eenvoudige beoordeling te geven (bijvoorbeeld “boven benchmark”, “in lijn met benchmark” of “onder benchmark”) op basis van vooraf ingestelde drempels per organisatieonderdeel.

Compliance, verantwoording en audit

Spending comparisons spelen een belangrijke rol in de manier waarop organisaties verantwoording afleggen over hun clouduitgaven. Voor Nederlandse overheidsorganisaties sluit dit direct aan op de eisen van de Algemene Rekenkamer, de Baseline Informatiebeveiliging Overheid (BIO) en interne controleraamwerken. Waar traditionele IT-uitgaven vaak via meerjarige contracten en vaste licentieovereenkomsten liepen, kenmerkt de cloud zich door sterk variabele kosten die afhangen van daadwerkelijk verbruik. Auditors verwachten daarom niet alleen inzicht in totale bedragen, maar ook in de achterliggende drivers: welke diensten en omgevingen genereren welke kosten, welke optimalisatiemaatregelen zijn overwogen en welke zijn daadwerkelijk geïmplementeerd. Een goed ingericht spending-comparisonsproces maakt het mogelijk om deze vragen met feiten te beantwoorden. Historische rapporten tonen bijvoorbeeld hoe de verhouding tussen productie- en niet-productiekosten zich heeft ontwikkeld, welke projecten tijdelijk voor pieken zorgden en op welke plekken kosten juist zijn gedaald door gerichte maatregelen.

Voor ISO 27001 en de BIO is vooral de combinatie tussen financiële beheersing en risicomanagement relevant. Cloudkosten zijn immers niet alleen een financieel vraagstuk, maar ook een indicator voor de manier waarop resources worden ingezet en beheerd. Overmatig verbruik in testomgevingen kan bijvoorbeeld duiden op gebrek aan lifecyclemanagement, terwijl extreem lage kosten voor beveiligingscomponenten kunnen wijzen op onderinvestering in security-maatregelen. Door spending comparisons te koppelen aan risicoregisters en beveiligingsbeleid ontstaat een rijker beeld: niet alleen worden kosten zichtbaar, maar ook de implicaties voor beschikbaarheid, integriteit en vertrouwelijkheid. In auditdossiers kan worden vastgelegd hoe kostenanalyses periodiek worden uitgevoerd, welke drempelwaarden voor afwijkingen worden gehanteerd en welke besluitvorming plaatsvindt wanneer bepaalde benchmarks worden overschreden.

De NIS2-richtlijn benadrukt de noodzaak van continu risicogebaseerd management voor essentiële en belangrijke entiteiten. Hoewel NIS2 primair focust op beveiliging en continuïteit, zijn clouduitgaven hier nauw mee verweven: het gebruik van redundante architecturen, back-up- en herstelvoorzieningen en geavanceerde beveiligingsdiensten brengt substantiële kosten met zich mee. Spending comparisons bieden bestuurders het inzicht dat nodig is om te beoordelen of deze kosten in verhouding staan tot de risico’s die worden afgedekt. Bijvoorbeeld door kosten voor disaster-recoveryomgevingen direct te relateren aan de verwachte schade bij een langdurige uitval. In verantwoordingsdocumenten kan zo worden aangetoond dat keuzes rond architectuur en beveiliging niet alleen technisch, maar ook financieel zijn onderbouwd en dat er regelmatig wordt getoetst of de balans tussen kosten en risico’s nog passend is.

Tot slot ondersteunt een gestructureerde spending-comparisonsaanpak de interne beheersing rond budgettering en prognoses. Door historische kostenreeksen en groeipercentages per businessline systematisch vast te leggen, kunnen begrotingen realistischer worden opgesteld en kunnen afwijkingen vroegtijdig worden gesignaleerd. In plaats van eenmalige correcties achteraf, ontstaat een continue dialoog tussen IT, finance en de business over de vraag welke investeringen nodig zijn, welke besparingen haalbaar zijn en hoe deze keuzes zich verhouden tot beleidsdoelstellingen rond digitalisering. Het script spending-comparisons.ps1 levert hiervoor reproduceerbare audit evidence: de uitvoer kan bijvoorbeeld periodiek worden gearchiveerd, zodat auditors kunnen verifiëren dat analyses daadwerkelijk en volgens vaste definities zijn uitgevoerd. Daarmee wordt spending comparisons een aantoonbaar onderdeel van de interne controleketen, in plaats van een incidentele exercitie zonder formele borging.

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# .SYNOPSIS Voert spending comparisons uit over Azure-abonnementen en omgevingen. .DESCRIPTION Dit script is onderdeel van de \"Nederlandse Baseline voor Veilige Cloud\" en ondersteunt het artikel `content/azure/governance/spending-comparisons.json`. Het script leest kosteninformatie uit Azure Cost Management, groepeert deze per abonnement en belangrijke tags (zoals Environment en CostCenter) en genereert een samenvattend rapport. Het doel is om snel inzicht te geven in: - welke abonnementen relatief het meest uitgeven; - hoe kosten zijn verdeeld over omgevingen (productie, acceptatie, test, ontwikkeling); - welke costcenters of applicaties opvallend afwijken. Het script is bewust conservatief opgezet: als de vereiste modules of rechten ontbreken, wordt een duidelijke foutmelding teruggegeven in plaats van halfslachtige resultaten. .NOTES Filename: spending-comparisons.ps1 Author: Nederlandse Baseline voor Veilige Cloud Created: 2025-11-26 Last Modified: 2025-11-26 Version: 1.0 Related JSON: content/azure/governance/spending-comparisons.json .LINK https://github.com/microsoft/m365-tenant-best-practise .EXAMPLE .\spending-comparisons.ps1 Voert een standaardanalyse uit over de afgelopen 30 dagen en toont een beknopt overzicht. .EXAMPLE .\spending-comparisons.ps1 -Monitoring Retourneert een object met kernindicatoren voor gebruik in monitoring of dashboards. .EXAMPLE .\spending-comparisons.ps1 -Remediation -WhatIf Toont aanbevelingen voor kostenoptimalisatie zonder wijzigingen door te voeren. #> #Requires -Version 5.1 #Requires -Modules Az.Accounts, Az.CostManagement # ============================================================================ # PARAMETERS # ============================================================================ [CmdletBinding()] param( [Parameter()] [switch]$WhatIf, [Parameter()] [switch]$Monitoring, [Parameter()] [switch]$Remediation, [Parameter()] [int] $LookbackDays = 30 ) # ============================================================================ # VARIABLES # ============================================================================ $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' $ScriptName = 'spending-comparisons.ps1' # ============================================================================ # FUNCTIONS # ============================================================================ function Test-ModuleAvailability { <# .SYNOPSIS Controleert of vereiste Az-modules aanwezig zijn. .OUTPUTS [bool] #> [CmdletBinding()] param() $requiredModules = @('Az.Accounts', 'Az.CostManagement') $missing = @() foreach ($mod in $requiredModules) { if (-not (Get-Module -ListAvailable -Name $mod)) { $missing += $mod } } if ($missing.Count -gt 0) { Write-Warning ("De volgende modules ontbreken: {0}. Installeer het Az-modulepakket op de beheerwerkplek of in de automatiseringsomgeving voordat u dit script uitvoert." -f ($missing -join ', ')) return $false } return $true } function Connect-RequiredServices { <# .SYNOPSIS Controleert de huidige Azure context en vraagt zo nodig om interactief in te loggen. #> [CmdletBinding()] param() if (-not (Test-ModuleAvailability)) { throw "Vereiste Az-modules ontbreken. Raadpleeg de documentatie van de Nederlandse Baseline voor Veilige Cloud voor installatie-instructies." } $context = Get-AzContext -ErrorAction SilentlyContinue if (-not $context) { Write-Verbose "Geen actieve Azure context gevonden. Gebruik Connect-AzAccount om verbinding te maken." throw "Geen actieve Azure context. Voer eerst Connect-AzAccount uit met een account dat leesrechten heeft op de relevante abonnementen." } Write-Verbose ("Actieve Azure context: {0} / {1}" -f $context.Account.Id, $context.Subscription.Id) } function Get-SpendingData { <# .SYNOPSIS Haalt kosteninformatie op via Azure Cost Management. .OUTPUTS System.Collections.Generic.List[PSCustomObject] #> [CmdletBinding()] param( [Parameter(Mandatory)] [int]$LookbackDays ) $timeframe = if ($LookbackDays -ge 90) { 'LastQuarter' } else { 'Custom' } $endDate = (Get-Date).Date $startDate = $endDate.AddDays(-1 * [Math]::Abs($LookbackDays)) $timePeriod = @{ From = $startDate To = $endDate } Write-Verbose ("Ophalen van kosten over periode {0:yyyy-MM-dd} t/m {1:yyyy-MM-dd}" -f $startDate, $endDate) # Query op tenant-scope; voor organisaties met meerdere tenants kan dit script per tenant worden gedraaid. $queryDefinition = New-AzCostManagementQueryObject -Type Usage -Timeframe $timeframe -TimePeriod $timePeriod $queryDefinition.DataSet = New-Object -TypeName Microsoft.Azure.Commands.CostManagement.Models.PSCostManagementQueryDataset $queryDefinition.DataSet.Granularity = 'Daily' $queryDefinition.DataSet.Aggregation = @{ totalCost = @{ Name = 'PreTaxCost' Function = 'Sum' } } $queryDefinition.DataSet.Grouping = @( (New-AzCostManagementQueryGroupingObject -Type Dimension -Name 'SubscriptionId'), (New-AzCostManagementQueryGroupingObject -Type Tag -Name 'Environment'), (New-AzCostManagementQueryGroupingObject -Type Tag -Name 'CostCenter') ) $scope = "/providers/Microsoft.Billing/billingAccounts/" try { $result = Get-AzCostManagementQuery -Scope $scope -QueryDefinition $queryDefinition } catch { Write-Warning "Het ophalen van kostengegevens via Az.CostManagement is mislukt. Controleer of uw account rechten heeft op tenant- of billing-niveau en of Cost Management beschikbaar is." throw } $data = New-Object System.Collections.Generic.List[PSCustomObject] foreach ($row in $result.Rows) { # Verwachte volgorde: SubscriptionId, Environment, CostCenter, Cost $subscriptionId = $row[0] $environment = if ($row[1]) { [string]$row[1] } else { 'Onbekend' } $costCenter = if ($row[2]) { [string]$row[2] } else { 'Onbekend' } $cost = [decimal]$row[3] $data.Add([PSCustomObject]@{ SubscriptionId = $subscriptionId Environment = $environment CostCenter = $costCenter Cost = [math]::Round($cost, 2) }) } return $data } function Test-Compliance { <# .SYNOPSIS Voert een lichte compliance- en optimalisatiebeoordeling uit op basis van spending data. .OUTPUTS PSCustomObject met compliance resultaten #> [CmdletBinding()] param( [Parameter()] [int]$LookbackDays = 30 ) Write-Verbose "Start spending comparison en compliance-analyse..." Connect-RequiredServices $spending = Get-SpendingData -LookbackDays $LookbackDays if (-not $spending -or $spending.Count -eq 0) { return [PSCustomObject]@{ ScriptName = $ScriptName IsCompliant = $false Timestamp = Get-Date Details = "Er zijn geen kostengegevens gevonden voor de opgegeven periode. Controleer of Cost Management-data beschikbaar is voor deze tenant." Recommendations = @( "Controleer in de Azure Portal onder Cost Management of kosten zichtbaar zijn voor de gekozen periode.", "Controleer of het account of de service principal voldoende rechten heeft om kosten op tenant- of billing-scope op te halen.", "Verifieer dat tagging (Environment en CostCenter) is ingericht voor de belangrijkste resources." ) } } # Analyse: totale kosten, aandeel niet-productie, top costcenters $totalCost = ($spending | Measure-Object -Property Cost -Sum).Sum $prodCost = ($spending | Where-Object { $_.Environment -match 'prod' } | Measure-Object -Property Cost -Sum).Sum $nonProd = $totalCost - $prodCost $nonProdShare = if ($totalCost -gt 0) { [math]::Round(($nonProd / $totalCost) * 100, 1) } else { 0 } $bySubscription = $spending | Group-Object SubscriptionId | Sort-Object { ($_.Group | Measure-Object -Property Cost -Sum).Sum } -Descending | Select-Object -First 5 @{ Name = 'SubscriptionId' Expression = { $_.Name } }, @{ Name = 'TotalCost' Expression = { [math]::Round(( $_.Group | Measure-Object -Property Cost -Sum).Sum, 2) } } $byCostCenter = $spending | Group-Object CostCenter | Sort-Object { ($_.Group | Measure-Object -Property Cost -Sum).Sum } -Descending | Select-Object -First 5 @{ Name = 'CostCenter' Expression = { $_.Name } }, @{ Name = 'TotalCost' Expression = { [math]::Round(( $_.Group | Measure-Object -Property Cost -Sum).Sum, 2) } } $isCompliant = $true $recommendations = New-Object System.Collections.Generic.List[string] if ($nonProdShare -gt 40) { $isCompliant = $false $recommendations.Add("Het aandeel kosten in niet-productieomgevingen is hoog (${nonProdShare}%). Onderzoek mogelijkheden om ontwikkel- en testomgevingen buiten kantoortijd uit te schakelen of kleiner te schalen.") } if ($byCostCenter.Count -eq 1 -and $totalCost -gt 0) { $isCompliant = $false $recommendations.Add("Bijna alle kosten zijn toegewezen aan één CostCenter. Controleer of tagging op andere afdelingen correct is ingericht.") } if ($byCostCenter.Count -eq 0) { $isCompliant = $false $recommendations.Add("Er zijn geen CostCenter-tags aangetroffen in de kostengegevens. Zonder tagging zijn spending comparisons op organisatieniveau beperkt bruikbaar.") } if ($recommendations.Count -eq 0) { $recommendations.Add("Blijf maandelijkse spending comparisons uitvoeren en bespreek de resultaten in het FinOps- of cloudgovernance-overleg.") $recommendations.Add("Documenteer gebruikte drempelwaarden (bijvoorbeeld maximaal 3040% van de kosten in niet-productieomgevingen) in het cloud governancebeleid.") } $detailsLines = @() $detailsLines += ("Totale kosten over de afgelopen {0} dagen: {1:N2}" -f $LookbackDays, $totalCost) $detailsLines += ("Aandeel niet-productieomgevingen (op basis van Environment-tag): {0}%" -f $nonProdShare) $detailsLines += "Top 5 abonnementen naar kosten:" foreach ($s in $bySubscription) { $detailsLines += (" - {0}: {1:N2}" -f $s.SubscriptionId, $s.TotalCost) } $detailsLines += "Top 5 costcenters naar kosten:" foreach ($c in $byCostCenter) { $detailsLines += (" - {0}: {1:N2}" -f $c.CostCenter, $c.TotalCost) } return [PSCustomObject]@{ ScriptName = $ScriptName IsCompliant = $isCompliant Timestamp = Get-Date Details = ($detailsLines -join [Environment]::NewLine) Recommendations = $recommendations.ToArray() } } function Invoke-Remediation { <# .SYNOPSIS Genereert aanbevelingen voor kostenoptimalisatie op basis van spending comparisons. #> [CmdletBinding()] param() $result = Test-Compliance -LookbackDays $LookbackDays Write-Host "`n=== Spending Comparisons – Remediatieoverzicht ===`n" -ForegroundColor Cyan Write-Host $result.Details Write-Host "`nAanbevelingen:" -ForegroundColor Cyan foreach ($rec in $result.Recommendations) { if ($WhatIf) { Write-Host ("[WhatIf] {0}" -f $rec) -ForegroundColor Yellow } else { Write-Host ("- {0}" -f $rec) -ForegroundColor Green } } return $result } function Invoke-Monitoring { <# .SYNOPSIS Voert alleen de monitoring- en rapportagelogica uit voor integratie in dashboards. #> [CmdletBinding()] param() $result = Test-Compliance -LookbackDays $LookbackDays return $result } # ============================================================================ # MAIN EXECUTION # ============================================================================ try { Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "Script: $ScriptName" -ForegroundColor Cyan Write-Host "Nederlandse Baseline voor Veilige Cloud" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { # Standaard: enkel een compliance check en korte samenvatting $result = Test-Compliance -LookbackDays $LookbackDays if ($result.IsCompliant) { Write-Host "`nCOMPLIANCE-STATUS: COMPLIANT" -ForegroundColor Green } else { Write-Host "`nCOMPLIANCE-STATUS: NIET COMPLIANT" -ForegroundColor Red } Write-Host "`nSamenvatting:" -ForegroundColor Cyan Write-Host $result.Details Write-Host "`nBelangrijkste aanbevelingen:" -ForegroundColor Cyan foreach ($rec in $result.Recommendations | Select-Object -First 3) { Write-Host ("- {0}" -f $rec) } return $result } } catch { Write-Error "Er is een fout opgetreden in $ScriptName: $_" throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan }

Risico zonder implementatie

Risico zonder implementatie
Medium: Zonder gestructureerde spending comparisons ontbreekt een betrouwbaar beeld van waar clouduitgaven precies terechtkomen. Kostenlekken in niet-productieomgevingen, vergeten experimenten en inefficiënte architecturen blijven onzichtbaar totdat facturen fors oplopen. Bestuurders en financiële teams sturen dan op gevoel of op losse incidenten, in plaats van op consistente trendinformatie per businessline, abonnement en omgeving. Dit vergroot de kans op generieke bezuinigingen of investeringsstops die ook goed ingerichte diensten raken, terwijl echte verspilling blijft bestaan. Voor Nederlandse overheidsorganisaties leidt gebrekkig kosteninzicht bovendien tot lastige gesprekken met controllers en toezichthouders, omdat onderbouwing van clouduitgaven ontbreekt en doelmatigheid moeilijk kan worden aangetoond.

Management Samenvatting

Richt spending comparisons in door een consistente Azure- en taggingstructuur te combineren met Cost Management-exports, Power BI-dashboards en het PowerShell-script spending-comparisons.ps1. Vergelijk uitgaven per abonnement, costcenter, applicatie en omgeving, valideer cijfers met finance en gebruik de resultaten in maandelijkse FinOps-rapportages en kwartaalreviews. Zo worden kostenlekken zichtbaar, kunnen gerichte optimalisatiemaatregelen worden genomen en ontstaat een aantoonbaar verhaal richting bestuur en auditors over de doelmatige inzet van de cloud.