Checks/EntraID/ARG.ENT.006.ps1
|
Register-ArgusCheck @{ Id = 'ARG.ENT.006' Title = 'Guests without a sponsor' Area = 'EntraID' Category = 'External identities' Severity = 'Medium' Description = 'Enabled guest users with no sponsor (`GET /users?$expand=sponsors`). Sponsors are the users or groups responsible for the guest''s access and information; Microsoft Entra sets the inviter as sponsor for new invitations, so guests without one were usually invited before sponsors existed, lost a sponsor that left, or were invited by sharing a SharePoint file (a known case where no sponsor is set). Skipped when the account cannot read sponsors.' Rationale = 'Without a sponsor nobody is accountable for the guest: access reviews have no reviewer, and the guest stays after the collaboration ends. A sponsor (a person or, better, a group) makes guest lifecycle decisions possible.' Remediation = @{ Steps = "1. For each guest, find the team or project that collaborates with them (group memberships, the inviter in the audit log).`n2. Add a sponsor in the Microsoft Entra admin center (Users > guest > Sponsors), preferably a group.`n3. Remove guests that nobody wants to sponsor, and use sponsors as reviewers in guest access reviews." PowerShell = "# Sample only - review before running.`nConnect-MgGraph -Scopes 'User.ReadWrite.All'`nNew-MgUserSponsorByRef -UserId '<guest id>' -BodyParameter @{ '@odata.id' = 'https://graph.microsoft.com/v1.0/users/<sponsor id>' }" PortalUrl = 'https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserManagementMenuBlade/~/AllUsers' } References = @( @{ Title = 'Add sponsors to a guest user'; Url = 'https://learn.microsoft.com/en-us/entra/external-id/b2b-sponsors' } @{ Title = 'List sponsors'; Url = 'https://learn.microsoft.com/en-us/graph/api/user-list-sponsors' } ) Requires = @{ Services = @('Graph') GraphScopes = @('User.Read.All') DataSets = @('Users', 'GuestSponsors') } Tags = @('Guests', 'Ownership') Test = { param($Context) $sponsors = $Context.Data['GuestSponsors'] $unavailable = Get-ArgusProperty $sponsors 'ArgusUnavailable' if ($unavailable) { return New-ArgusResult -Status Skipped -SkipReason $unavailable } $guests = @($Context.Data['Users'] | Where-Object { (Get-ArgusProperty $_ 'userType' '') -eq 'Guest' -and (Get-ArgusProperty $_ 'accountEnabled') -eq $true }) $findings = @($guests | Where-Object { $id = [string](Get-ArgusProperty $_ 'id' '') -not ($sponsors -and $sponsors.Contains($id) -and @($sponsors[$id]).Count -gt 0) } | ForEach-Object { [pscustomobject]@{ DisplayName = Get-ArgusProperty $_ 'displayName' '' UserPrincipalName = Get-ArgusProperty $_ 'userPrincipalName' '' Mail = Get-ArgusProperty $_ 'mail' '' Created = Format-ArgusDate (Get-ArgusProperty $_ 'createdDateTime' '') ObjectId = Get-ArgusProperty $_ 'id' '' } } | Sort-Object Created, UserPrincipalName) $status = if ($findings.Count -gt 0) { 'Failed' } else { 'Passed' } New-ArgusResult -Status $status -Findings $findings -EvaluatedCount $guests.Count ` -Summary '{AffectedCount} of {EvaluatedCount} enabled guests have no sponsor.' } } |