Public/Initialize-KritTcmTenant.ps1
|
function Initialize-KritTcmTenant { <# .SYNOPSIS One-shot end-to-end TCM bootstrap for a tenant: Connect + SP provision + permission grant. Idempotent. .DESCRIPTION Orchestrates the documented 4-step setup from https://learn.microsoft.com/en-us/graph/utcm-authentication-setup into one function with operator-overridable defaults and structured receipt. Steps: 1. Connect-MgGraph with Application.ReadWrite.All + AppRoleAssignment.ReadWrite.All (unless already connected with sufficient scopes) 2. Initialize-KritTcmServicePrincipal — provision TCM + M365 Admin Services SPs 3. Grant-KritTcmGraphPermission — grant the requested Graph perms to TCM SP 4. Emit consolidated receipt JSON (optional -OutDir) .PARAMETER Permissions Graph application permissions to grant to TCM. Defaults to the conservative set in the MS Learn example ('User.ReadWrite.All','Policy.Read.All'). Operator should expand based on which workloads they want to manage. .PARAMETER OutDir Where to write the receipt JSON. If unset, no file is written. .PARAMETER SkipConnect Skip Connect-MgGraph (assume already connected with sufficient scopes). .EXAMPLE # Default conservative permissions, no receipt write Initialize-KritTcmTenant -WhatIf Initialize-KritTcmTenant .EXAMPLE # Customer-grade — wider permission set, receipt to scripts/state/tcm-bootstrap/ Initialize-KritTcmTenant ` -Permissions @('User.ReadWrite.All','Policy.Read.All','Directory.Read.All','RoleManagement.Read.Directory','SecurityActions.Read.All') ` -OutDir 'C:/some/repo/scripts/state/tcm-bootstrap' .NOTES Tenant ID auto-resolved from Get-MgContext. No hardcoded kritical.net / kritical defaults — this function ships safe for any customer tenant. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] param( [string[]]$Permissions = @('User.ReadWrite.All','Policy.Read.All'), [string]$OutDir, [switch]$SkipConnect ) $receipt = [ordered]@{ Action='Initialize-KritTcmTenant'; Timestamp=(Get-Date).ToUniversalTime().ToString('o') Steps=[ordered]@{}; Errors=@{}; PermissionsRequested=$Permissions } # Step 1 — Connect (if needed) if (-not $SkipConnect) { $existing = Get-MgContext -ErrorAction SilentlyContinue $needed = @('Application.ReadWrite.All','AppRoleAssignment.ReadWrite.All') $haveAll = $existing -and ($needed | ForEach-Object { $_ -in $existing.Scopes }).Count -eq $needed.Count if (-not $haveAll) { if ($PSCmdlet.ShouldProcess('Microsoft Graph', "Connect with scopes $($needed -join ',')")) { Connect-MgGraph -Scopes $needed -NoWelcome -ErrorAction Stop $receipt.Steps['1-Connect'] = @{ Scopes=$needed; Connected=$true } } } else { $receipt.Steps['1-Connect'] = @{ Reused=$true; ExistingScopes=$existing.Scopes } } } $ctx = Get-MgContext -ErrorAction Stop $receipt.TenantId = $ctx.TenantId $receipt.Account = $ctx.Account # Step 2 — Provision SPs try { $receipt.Steps['2-ServicePrincipals'] = Initialize-KritTcmServicePrincipal } catch { $receipt.Errors['2-ServicePrincipals'] = $_.Exception.Message } # Step 3 — Grant Graph permissions try { $receipt.Steps['3-Permissions'] = @($Permissions | Grant-KritTcmGraphPermission) } catch { $receipt.Errors['3-Permissions'] = $_.Exception.Message } # Step 4 — Receipt if ($OutDir) { if (-not (Test-Path $OutDir)) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null } $path = Join-Path $OutDir ("{0}-tcm-bootstrap.json" -f (Get-Date -F yyyyMMddHHmmss)) $receipt | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $path -Encoding UTF8 $receipt.ReceiptPath = $path } [PSCustomObject]$receipt } |