Public/Permissions/Invoke-365TuneTestTeams.ps1
|
function Invoke-365TuneTestTeams { <# .SYNOPSIS Tests whether Teams Reader Entra ID role is correctly assigned to the 365TUNE Enterprise App. .DESCRIPTION Checks that the 365TUNE Service Principal has the Teams Reader directory role assigned in Entra ID. Read-only - makes no changes. .EXAMPLE Invoke-365TuneTestTeams .NOTES Author : Metawise Consulting LLC Module : 365TUNE Version : 2.2.7 #> [CmdletBinding()] param( [switch]$SkipAuth ) $displayNameProd = "365TUNE - Security and Compliance" $displayNameBeta = "365TUNE - Security and Compliance - Beta" $teamsRoleName = "Teams Reader" Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " 365TUNE - Test Teams Permissions" -ForegroundColor Cyan Write-Host "======================================================`n" -ForegroundColor Cyan # Step 1 - Modules Write-Host "[1/4] Checking required modules..." -ForegroundColor Cyan if (-not (Get-Module -ListAvailable -Name "Az.Accounts")) { Install-Module -Name "Az.Accounts" -Force -Scope CurrentUser } Import-Module Az.Accounts Write-Host " [OK] Modules ready." -ForegroundColor Green # Step 2 - Authenticate Write-Host "`n[2/4] Authenticating..." -ForegroundColor Cyan if (-not $SkipAuth) { $inCloudShell = ($env:ACC_CLOUD -eq "PROD") -or ($env:POWERSHELL_DISTRIBUTION_CHANNEL -like "*CloudShell*") -or ($env:AZUREPS_HOST_ENVIRONMENT -like "*cloud-shell*") if ($inCloudShell) { Connect-AzAccount -Identity -WarningAction SilentlyContinue | Out-Null } else { Disconnect-AzAccount -ErrorAction SilentlyContinue | Out-Null Connect-AzAccount -WarningAction SilentlyContinue | Out-Null } } $context = Get-AzContext if (-not $context) { throw "Not authenticated." } Write-Host " Tenant : $($context.Tenant.Id)" -ForegroundColor Gray Write-Host " Account : $($context.Account.Id)" -ForegroundColor Gray Write-Host " [OK] Authenticated." -ForegroundColor Green # Step 3 - Resolve SP and role via Graph Write-Host "`n[3/4] Resolving IDs via Graph..." -ForegroundColor Cyan $graphTokenObj = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com" if ($graphTokenObj.Token -is [System.Security.SecureString]) { $graphToken = [System.Net.NetworkCredential]::new("", $graphTokenObj.Token).Password } else { $graphToken = $graphTokenObj.Token } $headers = @{ Authorization = "Bearer $graphToken"; "Content-Type" = "application/json" } function Find-365TuneSP ($name) { $encoded = [Uri]::EscapeDataString("displayName eq '$name'") $response = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$filter=$encoded" -Headers $headers -Method GET $response.value | Select-Object -First 1 } $sp = Find-365TuneSP $displayNameProd if (-not $sp) { Write-Host " '$displayNameProd' not found - trying Beta..." -ForegroundColor Yellow $sp = Find-365TuneSP $displayNameBeta } if (-not $sp) { throw "Service Principal not found. Ensure the 365TUNE app has been consented to in this tenant." } $spId = $sp.id Write-Host " Display Name : $($sp.displayName)" Write-Host " Object ID : $spId" $encoded = [Uri]::EscapeDataString("displayName eq '$teamsRoleName'") $roleResponse = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions?`$filter=$encoded" -Headers $headers -Method GET $roleDef = $roleResponse.value | Select-Object -First 1 if (-not $roleDef) { throw "Entra ID role '$teamsRoleName' not found." } $roleDefId = $roleDef.id Write-Host " Role : $($roleDef.displayName)" Write-Host " [OK] IDs resolved." -ForegroundColor Green # Step 4 - Check assignment Write-Host "`n[4/4] Checking Teams role assignment..." -ForegroundColor Cyan $existingFilter = [Uri]::EscapeDataString("principalId eq '$spId' and roleDefinitionId eq '$roleDefId' and directoryScopeId eq '/'") $existingResponse = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?`$filter=$existingFilter" -Headers $headers -Method GET $existing = $existingResponse.value | Select-Object -First 1 Write-Host "" if ($existing) { Write-Host " [OK] Teams Reader role ASSIGNED" -ForegroundColor Green } else { Write-Host " [FAIL] Teams Reader role MISSING" -ForegroundColor Red } Write-Host "" Write-Host "======================================================" -ForegroundColor Cyan if ($existing) { Write-Host " Teams permissions OK. [OK]" -ForegroundColor Green } else { Write-Host " Teams permissions INCOMPLETE. Run Invoke-365TuneConnectTeams." -ForegroundColor Red } Write-Host "======================================================`n" -ForegroundColor Cyan return [bool]$existing } |