Checks/Copilot/ARG.COP.012.ps1
|
Register-ArgusCheck @{ Id = 'ARG.COP.012' Title = 'Agent requests pending for more than {PendingDays} days' Area = 'Copilot' Category = 'Agent governance' Severity = 'Low' Description = 'Packages with an open user request (`GET /copilot/admin/catalog/packages?$filter=requestStatus eq ''pending''`: publish, activate, access or update) whose `lastModifiedDateTime` is older than {PendingDays} days. The API exposes the package''s last change, not the request date, so the age is approximate. Requires a Microsoft Agent 365 licence; otherwise the check is Skipped.' Rationale = 'An approval process only works when requests are answered. Requests left open push users to workarounds (personal agents, shadow tools) and leave the catalogue out of date.' Remediation = @{ Steps = "1. In the Microsoft 365 admin center, go to Agents > Requests.`n2. Approve or reject each request, with a reason.`n3. Optionally add the agent management rule that rejects publish requests older than a set number of days (Agents > Settings > Agent management rules)." PortalUrl = 'https://admin.microsoft.com/' } References = @( @{ Title = 'List Copilot packages: filter by request properties'; Url = 'https://learn.microsoft.com/en-us/microsoft-365/copilot/extensibility/api/admin-settings/package/copilotpackages-list' } @{ Title = 'Agent settings: agent management rules'; Url = 'https://learn.microsoft.com/en-us/microsoft-365/admin/manage/agent-settings' } ) Requires = @{ Services = @('Graph') GraphScopes = @('CopilotPackages.Read.All') Licenses = @('AGENT_365') DataSets = @('CopilotPackages') } Parameters = @{ PendingDays = 7 } Tags = @('Copilot', 'Agents', 'Lifecycle') Test = { param($Context) $catalog = $Context.Data['CopilotPackages'] $unavailable = Get-ArgusProperty $catalog 'ArgusUnavailable' if ($unavailable) { return New-ArgusResult -Status Skipped -SkipReason $unavailable } $pending = @(Get-ArgusProperty $catalog 'PendingRequests' @() | Where-Object { $_ }) $cutoff = $Context.Now.AddDays(-[int]$Context.Parameters.PendingDays) $findings = @($pending | ForEach-Object { $modified = ConvertTo-ArgusUtcDate (Get-ArgusProperty $_ 'lastModifiedDateTime' '') if ($modified -and $modified -ge $cutoff) { return } [pscustomobject]@{ DisplayName = Get-ArgusProperty $_ 'displayName' '' RequestType = Get-ArgusProperty $_ 'requestType' '' Type = Get-ArgusProperty $_ 'type' '' Publisher = Get-ArgusProperty $_ 'publisher' '' LastModified = Format-ArgusDate $modified 'Unknown' DaysPending = if ($modified) { [int]($Context.Now - $modified).TotalDays } else { $null } PackageId = Get-ArgusProperty $_ 'id' '' } } | Sort-Object @{ Expression = { if ($null -eq $_.DaysPending) { [int]::MaxValue } else { $_.DaysPending } }; Descending = $true }) $status = if ($findings.Count -gt 0) { 'Failed' } else { 'Passed' } New-ArgusResult -Status $status -Findings $findings -EvaluatedCount $pending.Count ` -Summary '{AffectedCount} of {EvaluatedCount} pending agent requests are older than {PendingDays} days.' } } |