The Experts Conference (TEC) takes place virtually on September 1-2, 2021. It’s a free event dedicated to sharing practical information about running Microsoft cloud and on-premises services. We’ve asked each of the TEC speakers to write about a topic close to what they’ll be speaking about during this conference. This is the first article in the series. Join us at TEC to hear even more valuable information!

Public Preview of New Graph API Available

As noted in June, Microsoft is moving the focus for Azure AD to the Microsoft Graph API away from the Azure AD Graph API. This is an example of consolidating older first-generation REST APIs built for Microsoft Cloud Services into the Microsoft Graph. Another example is the transition of the Office 365 Service Communications API to the Graph (MC257688, updated June 24). A beta version of the Graph-based API for Service Communications is now available in public preview (Microsoft 365 Roadmap item 67820). Eventually, the Graph-based API will take over from the earlier version and tenants will have to upgrade scripts and other tools constructed using the older API.

Update August 4: In MC275573. Microsoft moved the Graph-based Service Communications API to Generally Available status and announced their intention to retire the older API from December 17, 2021.

What the Service Communications API Does

The Office 365 Service Communications API gives access to data such as:

  • Service health information – the kind of data you see in the tenant Service Health Dashboard (SHD).
  • Service incidents – details of an incident (outage) for a service like Exchange Online, SharePoint Online, or Teams. When an incident finishes, the API can also fetch the post-incident report (PIR).
  • Service update messages – the message center posts which appear in the Microsoft 365 admin center to advise tenants about new, updated, or deprecated features.

An example of using PowerShell and the older Service Communications API to retrieve details of service incidents is described in this post. I set out to create a Graph-based version of the script and here are my notes.

Upgrading to the Graph

First, I created a new registered application in Azure AD and an app secret for the app.

Graph apps need permissions to access data. In this case, the necessary permissions are:

  • ServiceMessage.Read.All: Access information about service updates.
  • ServiceHealth.Read.All: Access information about service incidents.

After assigning the permission(s) to the app and granting administrative consent, we can move to the code.

Assigning Graph permissions to an app registered in Azure AD
Figure 1: Assigning Graph permissions to an app registered in Azure AD

The code to acquire an access token is different because the endpoint changes from https://manage.office.com to the endpoint used for all Graph APIs (https://graph.microsoft.com/.default). If you have other scripts which interact with Graph APIs like those for users and groups, you can use the same code to get an access token.

Querying the Graph

The older API has a generic message object. Things are more specific with the Graph and you can retrieve three different collections of service information: messages, issues, and service health overviews. In this instance, I want to discover information about current service issues.

Incidents tend to be short lived. You can fetch all available incidents if you want or restrict the information returned by the Graph by using filters. Just for interest, I went back 180 days in my tenant and found that 270 incidents were available. I sorted the data to see what features caused most incidents and found the following were the top 10:

$Issues | Group FeatureGroup | Sort Count -Descending | Format-Table name, count

Name                          Count
----                          -----
Teams Components                 61
Portal                           39
Microsoft Intune                 31
Administration                   25
E-Mail and calendar access       18
SharePoint Features              16
Management and Provisioning      15
Yammer Components                 8
OneDrive for Business             7
E-Mail timely delivery            7

Of course, this data needs to be probed to fully understand its meaning. Because Microsoft tailors the incident data available to a tenant, your mileage may vary and Teams might not show up as responsible for 22.6% of all incidents logged in the last 180 days.

Processing Information Retrieved from the Graph

Returning to a more focused view, the code below creates a URI to fetch service issues over the last seven days. Including a Z at the end of the date (in PowerShell sortable format) is important because the Graph insists on terminating a sortable date with Z. At least, any attempt to use a simple date fails.

# Get Service incidents - the filter clause sets the number of days to look back
$DaysRange = (Get-Date).AddDays(-7)
$DaysRangeZ = Get-Date($DaysRange) -format s
$Uri = "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=startDateTime ge $DaysRangeZ" + "Z"

To retrieve the data, call the Invoke-RestMethod cmdlet to return the results in an array:

[array]$Issues = Invoke-RestMethod -Headers $Headers -Uri $Uri -UseBasicParsing -Method "GET" -ContentType "application/json"

By default, the Graph uses pagination to return data. In the case of the Service Information API, it returns 100 objects at a time, so if you want to fetch all possible data, you must check if an Odata.Nextlink is available to tell the Graph where the next page of data is waiting (here’s an example of using the Nextlink to fetch large quantities of Teams objects).

After everything is fetched, the useful data is in the Values property for each object, so you can extract the information to make it easier to work with by doing:

$Issues = $Issues.Value

To make things easier, I use a function to execute Graph queries, handle pagination, and return cleaned up results. You can see an example of the function in the Teams and Groups activity report script available in GitHub.

Interpreting Results

Queries for service issues return information incidents in different states:

  • serviceRestored: The incident is over, and service is now at normal levels.
  • serviceDegradation: The incident is current and is affecting the quality of service delivered to end users.
  • postIncidentReviewPublished: A post incident report is published and available for administrators to download. This is the root cause analysis of the problem which caused an incident.
  • investigationSuspended: Microsoft is waiting for further information to proceed).
  • falsePositive: A reported incident turned out to be a false positive.

You can filter the objects in the returned array to extract the incidents you’re interested in or ask the Graph to return just objects of a certain type. For example, to have the Graph return information about currently unresolved problems (isResolved is False and status is serviceDegradation), we use:

$Uri = "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=startDateTime ge $DaysRangeZ" + "Z and IsResolved eq false and status eq 'serviceDegradation'"

An object for an incident in the array returned by the Graph looks like this:

startDateTime        : 2021-06-30T00:00:00Z
endDateTime          :
lastModifiedDateTime : 2021-07-05T06:01:51.013Z
title                : Admins may see Microsoft 365 app usage and productivity score reports data delayed after June 30, 2021
id                   : MO266326
impactDescription    : Admins may see Microsoft 365 app usage and productivity score reports data delayed after June 30, 2021.
classification       : advisory
origin               : microsoft
status               : serviceDegradation
service              : Microsoft 365 suite
feature              : Company or User Administration
featureGroup         : Administration
isResolved           : False
highImpact           :
details              : {}
posts                : {@{createdDateTime=2021-07-02T05:54:00.587Z; postType=regular; description=},@{createdDateTime=2021-07-03T06:03:25.05Z; postType=regular; description=},
@{createdDateTime=2021-07-04T05:52:23.413Z; postType=regular; description=},
@{createdDateTime=2021-07-05T05:47:56.107Z; postType=regular; description=}}

Displaying Results

The information about an issue retrieved from the Graph is exactly what is shown in the Microsoft 365 SHD (Figure 2). Everything is available to format and report details as you would like.

An incident as viewed in the Microsoft 365 SHD
Figure 2: An incident as viewed in the Microsoft 365 SHD

For instance, the Posts property holds the set of updates issued by Microsoft about the incident shown under All updates in the SHD. Four updates are available for this incident. To see the latest details, we can use code like this:

$LastPostIndex = $Issue.Posts.Count -1
$PostInfo = $Issue.Posts[$LastPostIndex].Description.Content
$PostDate = Get-Date ($Issue.Posts[$LastPostIndex].CreatedDateTime) -format g
Write-Host (“Incident date: {0}: {1}” -f $PostDate, $PostInfo)

Incident date: 05/07/2021 06:47: Title: Admins may see Microsoft 365 app usage and productivity score reports data delayed after June 30, 2021

User Impact: Admins may see Microsoft 365 app usage and productivity score reports data delayed after June 30, 2021.

Current status: We've determined that the reports are still delayed. We're continuing our efforts to replay the delayed reporting data which we anticipate will mitigate impact.

Scope of impact: This issue may affect any admin attempting to view Microsoft 365 app usage and productivity score reports after June 30, 2021.

Start time: Wednesday, June 30, 2021, at 12:00 AM UTC

Root cause: A recent service update introduced a code regression in a service component responsible for tracking user activity throughout multiple Microsoft 365 apps, resulting in impact.

Next update by: Wednesday, July 7, 2021, at 7:00 AM UTC

Obviously, you can choose to present incident information in whatever way you choose. It’s only a matter of coding.

Summarizing the Conversion

Conversion from the older Office 365 Service Communications API to the Graph-based version isn’t difficult. If you’re used to working with the Graph APIs, you’ll find it second nature to get an access code, fetch information, apply filters, and interpret the data. The advantage of the Graph is that the same approach is used for different kinds of data, and that’s exactly what’s seen here. Happy coding!

Microsoft Is Moving the Office 365 Service Communications API to the Graph

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Comments

  1. Avatar photo
    Sanjeev

    Hello Everyone,
    Can someone help me with GraphAPI ps1 script?
    Thanks in advance!

  2. Avatar photo
    Claudiu

    Hello Tony,

    I am using Graph API to extract the incidents (advisory and incidents) using a power flow.

    But I have an issue with https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/issues because is extracting only some old incidents and the new ones are not present in my output.

    Do you have an idea why is not getting all the incidents?

    1. Avatar photo
      Tony Redmond

      I obviously don’t have access to your code and can’t say what might be going on. What do you see in the Graph Explorer? I pasted the link into it and see recent advisories (example shown below).

      {
      “createdDateTime”: “2022-02-23T18:59:36.417Z”,
      “postType”: “regular”,
      “description”: {
      “contentType”: “html”,
      “content”: “Title: Admins may be unable to use the \”Get-EXOMailbox\” PowerShell cmdlet in tenants hosted across multiple geo-locationsUser Impact: Admins may be unable to use \”Get-EXOMailbox\” in tenants that are hosted across multiple geo-locations.Current status: Our deployment to the affected infrastructure is ongoing and is expected to take some time to complete. We anticipate completion of the fix deployment by our next update on Wednesday, March 2, 2022.Scope of impact: This issue may impact any admin attempting to use the Get-EXOMailbox cmdlet in tenants hosted across multiple geo-locations.Estimated time to resolve: We anticipate completion of the fix deployment by our next update on Wednesday, March 2, 2022.Root cause: ACLs on database copy objects are mismatched, leading to validation failing and ADLookup not completing.Next update by: Wednesday, March 2, 2022, at 8:30 PM UTC”
      }
      }
      ]

      1. Avatar photo
        Ashish Jaiswal

        Hi Tony,
        I am expeirencing the same issue. I am using graph explorer. I only see the old message and not the new ones.
        Below is my query
        https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages

        I thought I would be a paging issue hence I used the below query and still no new message
        https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages?`$top=100

        To my surprise when I search with the message ID it shows the new message
        https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages/MC408531

        Could you please guide me what am I doing wrong here and why can’t I see the new messages?

        Regards,
        Ashish Jaiswal

        1. Avatar photo
          Tony Redmond

          I suspect you have a permissions issue. I tried the queries and the first two worked like a charm. The last didn’t because MC408531 doesn’t exist in my tenant.

          1. Avatar photo
            Jaiswal Ashish

            I have the exact same permission as you mentioned in this article, Please advise if more permissions are required? I am unable to share screen capture to you via this message.

            Also, this spam protection on your page/article is horrendous this is 105th time I am trying to add my reply
            SPAM Message
            SPAM ID
            Duplicate Message
            Try after sometime
            Not happy being a genuine guy to ask a question

          2. Avatar photo
            Tony Redmond

            When in doubt, always consult the documentation: https://docs.microsoft.com/en-us/office/office-365-management-api/get-started-with-office-365-management-apis

            This says that ServiceHealth.Read and User.Read is necessary. I use ServiceHealth.Read.All and ServiceMessage.Read.All (I just checked the Azure AD app). I forget why I selected these permissions, but it might have been through trial and error. It’s over a year since I wrote this article.

            Make sure that they are application permissions, not delegated permissions.

            As to spam, the site is plagued by a large amount of incoming spam that insists that people want to read about various pills and other body enhancements. No one wants to see that kind of crap.

  3. Avatar photo
    Frank Hanser

    Hi Tony

    I tried out your code in my tenant and always get an error:

    It is not possible to apply an index to a NULL array.
    In line: 35 characters: 1
    + $ PostInfo = $ Issues.Posts [$ LastPostIndex] .Description.Content
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~
    + CategoryInfo: InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId: NullArray

    Next problem I have is to post the data to a teams channel like Einar Asting did http://thingsinthe.cloud/Teams-message-cards-Office-365-Health-status/

    I am relativ new to O365 and powershell and it makes me a great headache.

    I subscribed Office 365 for IT Pros and it is very helpful. But it is a long learning path for me.

    Thanks for your great blog.

    Greetings from Germany.

    Kindly regards

    Frank

    1. Avatar photo
      Tony Redmond

      Hi Frank,

      The error means that you don’t have any data in the array ($Issues) you’re trying to use. Maybe the parameters you used for the Graph API call aren’t correct?

Leave a Reply