functions/serviceannouncement/Get-PSEntraIDMessageCenter.ps1
|
function Get-PSEntraIDMessageCenter { <# .SYNOPSIS Retrieves announcements from Microsoft 365 Message Center via Graph API using .NET deserialization. .DESCRIPTION Queries Microsoft Graph API for service announcement messages, deserializes them using .NET and filters them by parameters. Uses Graph API $filter where supported (category, severity) and applies service and datetime filtering locally. Requires delegated Graph permission: ServiceMessage.Read.All. .PARAMETER Service One or more Microsoft 365 services to filter messages by. Use 'All' to return all services (no filtering). .PARAMETER Category Filters messages by category (feature, retire, stayInformed, planForChange). .PARAMETER Severity Filters messages by severity (normal, high, critical). .PARAMETER PublishedAfter Filters messages published after this UTC datetime (evaluated locally). .PARAMETER PublishedBefore Filters messages published before this UTC datetime (evaluated locally). .PARAMETER EnableException Enables throwing terminating exceptions if an error occurs during API call. .EXAMPLE Get-PSEntraIDMessageCenter -Service "Microsoft Teams" -Category feature -PublishedAfter (Get-Date).AddDays(-7) Returns Microsoft Teams feature announcements published in the last 7 days. .EXAMPLE Get-PSEntraIDMessageCenter -Service All -Severity high Returns all high severity Message Center announcements across all services. .OUTPUTS PSMicrosoftEntraID.MessageCenter.Message[] .NOTES Piping into Select-Object -First N logs a warning that is not a failure: WARNING: [<cmdlet>] Failed to: ... | The pipeline has been stopped The results are correct and complete. Select-Object stops the pipeline once it has what it asked for, and the next write throws PipelineStoppedException - normal termination, reported as an error only because the write happens inside a protected block. Materialise first if the warning is in the way: $items = @(<cmdlet> ...) $items | Select-Object -First 3 or filter server-side with -Filter instead of trimming client-side. Not silenced on purpose: the only fix that works is to collect the whole result before emitting any of it, which would cost streaming on every read. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Parameters consumed inside Where-Object script blocks or reserved as part of the public parameter surface.')] [CmdletBinding()] [OutputType('PSMicrosoftEntraID.MessageCenter.Message[]')] param ( [Parameter()] [ValidateSet( "All", "Azure Active Directory", "Bookings", "Copilot for Microsoft 365", "Defender for Endpoint", "Defender for Identity", "Defender for Office 365", "Dynamics 365 Apps", "Exchange Online", "Forms", "Intune", "Loop", "Microsoft 365 for the web", "Microsoft 365 suite", "Microsoft 365 Apps", "Microsoft Defender XDR", "Microsoft Entra", "Microsoft Fabric", "Microsoft Loop", "Microsoft Purview", "Microsoft Stream", "Microsoft Syntex", "Microsoft Teams", "OneDrive for Business", "Planner", "Power Apps", "Power Automate", "Power BI", "Project for the web", "Security & Compliance Center", "SharePoint Online", "Sway", "To Do", "Viva Engage", "Viva Insights", "Viva Learning", "Whiteboard", "Yammer Enterprise" )] [string[]] $Service, [Parameter()] [ValidateSet("feature", "retire", "stayInformed", "planForChange")] [string[]] $Category, [Parameter()] [ValidateSet("normal", "high", "critical")] [string[]] $Severity, [Parameter()] [datetime] $PublishedAfter, [Parameter()] [datetime] $PublishedBefore, [Parameter()] [switch] $EnableException ) begin { [string] $serviceName = Get-PSFConfigValue -FullName ('{0}.Settings.DefaultService' -f $script:ModuleName) Assert-EntraConnection -Service $serviceName -Cmdlet $PSCmdlet [hashtable] $query = @{ '$count' = 'true' '$top' = Get-PSFConfigValue -FullName ('{0}.Settings.GraphApiQuery.MessageCenter.PageSize' -f $script:ModuleName) '$select' = ((Get-PSFConfig -Module $script:ModuleName -Name Settings.GraphApiQuery.Select.ServiceAnnouncement.Message).Value -join ',') } # Build Graph API-supported filters [string[]] $filterParts = @() if ($Category) { $categoryFilter = $Category | ForEach-Object { "category eq '$($_)'" } $filterParts += '(' + ($categoryFilter -join ' or ') + ')' } if ($Severity) { $severityFilter = $Severity | ForEach-Object { "severity eq '$($_)'" } $filterParts += '(' + ($severityFilter -join ' or ') + ')' } if ($filterParts.Count -gt 0) { $query['$filter'] = $filterParts -join ' and ' } [int] $commandRetryCount = Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryCount' -f $script:ModuleName) [timespan] $commandRetryWait = New-TimeSpan -Seconds (Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryWaitInSeconds' -f $script:ModuleName)) } process { Invoke-PSFProtectedCommand -ActionString 'MessageCenter.Get' -Target (Get-PSFLocalizedString -Module $script:ModuleName -Name Office365.Platform) -ScriptBlock { if ($PublishedAfter -and $PublishedBefore -and ($PublishedAfter -gt $PublishedBefore)) { Invoke-TerminatingException -Cmdlet $PSCmdlet -Message ((Get-PSFLocalizedString -Module $script:ModuleName -Name MessageCenter.Get.Validation) -f $PublishedBefore, $PublishedAfter) } [PSMicrosoftEntraID.ServiceAnnouncement.Message[]] $messageList = ConvertFrom-RestMessageCenter -InputObject (Invoke-EntraRequest ` -Service $serviceName ` -Path 'admin/serviceAnnouncement/messages' ` -Query $query ` -Method Get ` -ErrorAction Stop) # Local filter: Service if ($Service -and -not ($Service -contains 'All')) { $messageList = $messageList | Where-Object { $_.Services -and ($_.Services | Where-Object { $_ -in $Service }).Count -gt 0 } } # Local filter: PublishedAfter / PublishedBefore if ($PublishedAfter -or $PublishedBefore) { $messageList = $messageList | Where-Object { try { $published = [datetime]::Parse($_.StartDateTime) ( (-not $PublishedAfter -or $published -ge $PublishedAfter) -and (-not $PublishedBefore -or $published -le $PublishedBefore) ) } catch { $false } } } return $messageList } -EnableException:$EnableException -Continue -PSCmdlet $PSCmdlet -RetryCount $commandRetryCount -RetryWait $commandRetryWait -WhatIf:$false if (Test-PSFFunctionInterrupt) { return } } } |