Moving Beyond Simple Management Tasks
In part II of this series, I looked at how the Microsoft Graph and the Graph PowerShell SDK allow administrators to manage many aspects of Microsoft 365 from a single module. With some PowerShell experience, the SDK makes standard administrative tasks and reporting relatively easy.
While this functionality is nice to have in a single place, managing Microsoft 365 through PowerShell is old news for most admins. Where the Graph SDK has an advantage over other methods is that it can take full advantage of the Graph API, allowing admins to interact with Microsoft 365 services like Exchange Online and SharePoint Online, which previously required the use of dedicated APIs that arguably needed a much larger time investment to learn.
Exchange Web Services (EWS) has been an integral part of Microsoft Exchange since Exchange Server 2007. EWS supports programmatic access to Exchange resources like mailboxes. In 2018, the Exchange Team announced that they would no longer actively invest in EWS for Exchange Online and recommended that application owners and vendors migrate to the Microsoft Graph. This was followed up by API depreciations in 2021, signaling the end is in sight for EWS.
Interacting with Mail Items
A common EWS task is to retrieve and process mail from a mailbox. The Microsoft Graph PowerShell SDK makes this process easy with various message related cmdlets. For example, the command below retrieves all items from a user’s mailbox.
Note: Using Delegated permissions as detailed in part I of this series only allows you to retrieve items that your account has access to, such as your own mailbox. To access other mailboxes and resources you do not have access to, application permissions must be used. By default, the SDK will always use delegated permissions, to learn more about using application permissions, check out part I of this series.
Get-MgUserMessage -UserId <UserID> -All
Returning all items from a mailbox is a nice test but not very practical when building code to complete a task. There are several ways to filter the results to improve the execution time of the cmdlet and return only the relevant objects. First, we can return just the items in a specific folder. The Get-MgUserMailFolder cmdlet returns the top-level folders in a mailbox and the Get-MgUserMailFolderChildFolder cmdlet returns the subfolders of a folder. In Figure 1, we find the unique ID of the Inbox folder and use it to get the ID of the subfolder Mails to be processed. Each mail item and folder has a unique ID assigned by Exchange Online which is stored in the ID property of the item.
The cmdlet Get-MgUserMailFolderMessage returns mail items contained in a specified folder. These results can then be filtered or searched to narrow them down even further using the syntax below.
##Return all messages in a particular folder Get-MgUserMailFolderMessage -MailFolderId AAMkAGI4NjhmMDBjLTcyNTEtNDZkYy1hMmNhLTZjMThjYjQxODIzZgAuAAAAAAAdY2Aq0HOqRqKvhWSGlIAmAQDcQ9TSiMrlRrOhGqycky_7AABCa1F8AAA= -UserId ffcf3b2c-83d0-4e5f-a432-6d6a740a99d1 -All | fl subject,id ##Search messages in a particular folder for the word “PIM” Get-MgUserMailFolderMessage -MailFolderId AAMkAGI4NjhmMDBjLTcyNTEtNDZkYy1hMmNhLTZjMThjYjQxODIzZgAuAAAAAAAdY2Aq0HOqRqKvhWSGlIAmAQDcQ9TSiMrlRrOhGqycky_7AABCa1F8AAA= -UserId ffcf3b2c-83d0-4e5f-a432-6d6a740a99d1 -All -Search "PIM" | fl subject,id,ReceivedDateTime ##Filter messages in a particular folder by receivedDateTime and by subject starting with “Your weekly PIM digest'” Get-MgUserMailFolderMessage -MailFolderId AAMkAGI4NjhmMDBjLTcyNTEtNDZkYy1hMmNhLTZjMThjYjQxODIzZgAuAAAAAAAdY2Aq0HOqRqKvhWSGlIAmAQDcQ9TSiMrlRrOhGqycky_7AABCa1F8AAA= -UserId ffcf3b2c-83d0-4e5f-a432-6d6a740a99d1 -All -Filter "(receivedDateTime gt 2022-10-01T00:00:00Z) and (startswith(Subject,'Your weekly PIM digest'))" | fl subject,id,ReceivedDateTime
As shown in Figure 2, combining filters and search with cmdlets like Get-MgUserMailFolderMessage narrows down the results and allows us to retrieve exactly what we want.
Learn More: To find out more about assessing mailbox items with the Graph SDK, check out this article on Creating a Mailbox Contents Report with PowerShell and the Graph.
Items are returned in JSON format and mail items are returned as a message resource type. A resource type is a predefined format (in JSON) for a particular object, the schema for the message resource type object is detailed in the Graph documentation.
The Graph SDK also supports modifying existing mail items with the Update-MgUserMessage cmdlet. In the code shown below, we update the subject of the message identified with a message identifier:
##Modify the subject of a message Update-MgUserMessage -MessageId AAMkAGI4NjhmMDBjLTcyNTEtNDZkYy1hMmNhLTZjMThjYjQxODIzZgBGAAAAAAAdY2Aq0HOqRqKvhWSGlIAmBwDcQ9TSiMrlRrOhGqycky_7AABCa1F8AADcQ9TSiMrlRrOhGqycky_7AABCa4w1AAA= -UserId ffcf3b2c-83d0-4e5f-a432-6d6a740a99d1 -Subject "Updated message subject"
The cmdlet Move-MgUserMessage will move a mail into a target folder. In Figure 3, we get the ID of an existing mail item, get the ID of the Inbox folder, and move the mail into it.
The use cases for modifying existing mail items are quite limited outside of testing. What is more practical is the ability to send emails directly from PowerShell. This article explaining how to Send Exchange Online Email Using the Microsoft Graph SDK for PowerShell shows how to use the Graph SDK to send mail directly from PowerShell.
Working with SharePoint Online
File and site management and reporting is another key benefit of the Microsoft Graph. Interacting with files and sites across SharePoint Online (and by extension Teams and OneDrive) through PowerShell previously required knowledge of the SharePoint PnP PowerShell module or the SharePoint Client Side Object Model (CSOM), neither of which are particularly intuitive if you aren’t experienced in SharePoint development.
The Microsoft Graph exposes endpoints for interacting with SharePoint Online and while it doesn’t have the depth that PnP or CSOM has (Creating site templates for example), most of the tasks tenant admins need to perform are fully supported.
One example of how the Graph can help admins in SharePoint Online is this article on how to Use Graph APIs to Create a Report of Files in a SharePoint Online Site. The code in this article first fetches the list of drives (Document Libraries) attached to a particular site and filters for the “Documents” library. From here it expands out the files and folders under the root to create a useful report.
This script uses the Invoke-MgGraphRequest cmdlet in the PowerShell SDK to query the Drives endpoint and return all libraries. Invoke-MgGraphRequest is a great way to run queries against endpoints that you know or endpoints that don’t have a native PowerShell SDK cmdlet.
The same results can be obtained using the Get-MgSiteDrive cmdlet, however, there are some nuances to the cmdlet. For example, simply running Get-MgSiteDrive against a particular site will query the /drive endpoint of a site. The /drive endpoint only returns the default Document Library of a site. This is shown in Figure 4 using the debug feature of the SDK as discussed in this article on using the Debug parameter for Microsoft Graph PowerShell SDK Cmdlets to Expose Graph API Requests.
To return all Drives attached to a site, we need to add the -All parameter. This parameter changes the endpoint that is queried from /drive to /drives. This subtle change in the URI (Which is hard to spot when troubleshooting why a script won’t work as expected) changes the result set from the default library to all libraries. The URI with the -All parameter present is shown in Figure 5.
This nuance (or feature, it’s hard to say from the documentation) is relatively small, but it does begin to show some of the rough edges of the PowerShell SDK. The SDK is very much still a work in progress and no doubt will mature over time with improved documentation and more endpoints directly supported with cmdlets. Until then, there is always the Invoke-MgGraphRequest cmdlet to fill in the gaps.
Another example is listing the files in a drive. The Get-MgDriveItem cmdlet seems like it should do what’s needed here, however, this cmdlet uses the /drive/driveid/items endpoint, which is used to return specific items, not list all items. In the script, the URI https://graph.microsoft.com/v1.0/sites/$($Site.Id)/drives/$($DocumentLibrary.Id)/root/children is used with the Invoke-MgGraphRequest cmdlet and this gets the job done perfectly.
The Graph PowerShell SDK is a great tool for admins to interact with Microsoft 365 workloads in ways that weren’t previously practical without the significant time investment. The SDK opens many possibilities to get started with the Microsoft Graph however there are some areas that need improvement.
While it’s not a replacement for learning the intricacies of the Graph API for creating complex solutions, the SDK is a fantastic way to get started and carry out standard tasks without needing to invest too much time.