Public/Initialize-KritTcmServicePrincipal.ps1

function Initialize-KritTcmServicePrincipal {
    <#
    .SYNOPSIS
        Idempotently provision the TCM + companion M365 Admin Services service principals
        in the connected tenant.

    .DESCRIPTION
        Microsoft Tenant Configuration Management (TCM) APIs require two service principals
        present in the target tenant before any snapshot/monitor call:
          - Tenant Configuration Management (AppId 03b07b79-c5bc-4b5e-9bfa-13acf4a99998)
          - M365 Admin Services (AppId 6b91db1b-f05b-405a-a0b2-e3f60b28d645)

        This function checks for each via Get-MgServicePrincipal and creates only those
        missing. Re-runnable safely — already-present SPs return unchanged.

    .PARAMETER WhatIf
        Standard ShouldProcess — show what would be created without writing.

    .EXAMPLE
        Connect-MgGraph -Scopes Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All
        Initialize-KritTcmServicePrincipal -WhatIf
        Initialize-KritTcmServicePrincipal

    .OUTPUTS
        PSCustomObject with TcmSp, M365AdminSp, AlreadyExisted, Created lists.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')]
    param()

    if (-not (Get-Command Get-MgServicePrincipal -ErrorAction SilentlyContinue)) {
        throw 'Microsoft.Graph.Applications module not imported. Run Import-Module Microsoft.Graph.Applications + Connect-MgGraph first.'
    }
    $ctx = Get-MgContext -ErrorAction SilentlyContinue
    if (-not $ctx) { throw 'Not connected to Microsoft Graph. Run Connect-MgGraph -Scopes Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All' }

    $result = [ordered]@{
        Action        = 'Initialize-KritTcmServicePrincipal'
        Tenant        = $ctx.TenantId
        Timestamp     = (Get-Date).ToUniversalTime().ToString('o')
        TcmSp         = $null
        M365AdminSp   = $null
        AlreadyExisted = @()
        Created       = @()
        Errors        = @()
    }

    foreach ($pair in @(
        @{ Name = 'Tenant Configuration Management';   AppId = (Get-KritTcmConstant -Name TcmServicePrincipalAppId); Key='TcmSp' }
        @{ Name = 'M365 Admin Services';                AppId = (Get-KritTcmConstant -Name M365AdminServicesAppId);   Key='M365AdminSp' }
    )) {
        try {
            $existing = Get-MgServicePrincipal -Filter "AppId eq '$($pair.AppId)'" -ErrorAction Stop
            if ($existing) {
                $result.($pair.Key) = @{ AppId=$pair.AppId; ObjectId=$existing.Id; Existed=$true; DisplayName=$existing.DisplayName }
                $result.AlreadyExisted += $pair.Name
                continue
            }
            if ($PSCmdlet.ShouldProcess($pair.Name, "Create service principal (AppId=$($pair.AppId))")) {
                $sp = New-MgServicePrincipal -AppId $pair.AppId -ErrorAction Stop
                $result.($pair.Key) = @{ AppId=$pair.AppId; ObjectId=$sp.Id; Existed=$false; DisplayName=$sp.DisplayName }
                $result.Created += $pair.Name
            }
        } catch {
            $result.Errors += @{ Sp=$pair.Name; Error=$_.Exception.Message }
        }
    }
    [PSCustomObject]$result
}