Graph API adds support for managing retention labels

As Microsoft is slowly ramping up Graph API’s support across its Compliance stack, at this year’s Ignite we got the announcement of new (/beta) endpoints for management of Retention labels. So as usual, I’ve decided to take a quick look at them, and compare the functionality with the existing PowerShell cmdlets and/or the UI bits, as relevant.

To start with, we need to talk about permissions. No surprises here, as with most other Graph API endpoints, two sets of permissions are available: the read-only RecordsManagement.Read.All as well as the read-write RecordsManagement.ReadWrite.All. Both flavors are supported for either delegate permissions and application permissions model, so you should have some flexibility when deciding your approach here.

Once permissions are taken care of, all you need to do is authenticate and start using the new endpoints. The Graph Explorer tool is a good starting point when running in the delegate permissions model, so here’s how a request to list all retention labels within the tenant looks like therein:

https://graph.microsoft.com/beta/security/labels/retentionLabels

Graph retention labelsOne thing you might notice is that the new endpoints are a bit slow, but in all fairness the corresponding PowerShell cmdlets or the UI aren’t exactly lightning fast either. Another thing to note is that querying the /beta/security/labels/retentionLabels endpoint will return “record” labels as well. This matches the behavior of the PowerShell cmdlets, but depending on where you are looking in the Purview portal, such labels might be “hidden”, so you can expect some mismatch in the results.

Since working with the output is quite limited when using the Graph Explorer tool, we can also use the Microsoft Graph SDK for PowerShell to fetch retention labels and explore their properties. The corresponding cmdlet is Get-MgSecurityLabelRetentionLabel. Yes, it’s a dumb name for a cmdlet, but that’s hardly surprising for a module designed with the devs convenience in mind, not the user’s. And since I always feel the need of taking yet another stab of the lack of touch and polish of the Graph (and the SDK), take a look at the error message it throws in the scenario where we don’t have the required permissions:

Get-MgSecurityLabelRetentionLabel_List: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.

In all fairness, this time it’s not the PowerShell module, but the Graph API endpoint itself generating the message, which doesn’t change the fact of how useless it is. Anyway, just make sure you request the required permissions when connecting, switch to the beta endpoint, and you should be all set:

C:\> Connect-MgGraph -Scopes RecordsManagement.Read.All

C:\> Select-MgProfile beta

C:\> Get-MgSecurityLabelRetentionLabel | select displayName,CreatedDateTime,isInUse,behaviorDuringRetentionPeriod,ActionAfterRetentionPeriod,id | ft -a

DisplayName CreatedDateTime IsInUse BehaviorDuringRetentionPeriod ActionAfterRetentionPeriod Id
----------- --------------- ------- ----------------------------- -------------------------- --
PreservePersonalStuff    28/10/2017 17:46:11    True    retain    none    d8191abc-8c94-4eb9-82e2-26fb9ab4b9a2
Record    16/06/2017 12:00:25    True    retainAsRecord    startDispositionReview    4ee9b3df-1b92-483b-933d-43460d54cb0a
Confidential    21/03/2017 12:40:21    True    retain    none    ff60cca6-830d-4620-b786-71cfdd0878cf
Event-based    13/05/2018 16:55:14    True    retain    delete    6fe5ea8c-a32c-48b3-bf22-89bb8a5db67a

The full list of properties currently supported by the endpoint can be found in the official documentation. Apart from few properties related to “preview” functionalities (such as Power Automate integration) and some documentation inaccuracies (DispositionReviewStages does not seem to be a navigation property, despite what the article above says), you can expect the same set of properties as you’d find via PowerShell or in the UI. Do note that some properties return “default” values when using the LIST method and the “real” value is only shown when getting the individual retention label properties instead:

GET https://graph.microsoft.com/beta/security/labels/retentionLabels/4ee9b3df-1b92-483b-933d-43460d54cb0a?$select=isInUse

Graph retention labels1Or it might be just a bug in the implementation, as the corresponding IsActiveLabel property returns a True value via the SCC PowerShell cmdlets for this particular label. So either the property mapping is wrong or not yet supported. Here is a good place to mention that the Purview UI still seems to still use the PowerShell cmdlets, so you will see the same values as the ones obtained via the SCC PowerShell cmdlets therein.

Also note that the $select operator doesn’t seem to be currently available on the LIST endpoint, but it works on individual GET requests. That’s likely going to be fixed by the time the new endpoints reach GA. Same goes for the $filter operator, $top and so on, with pretty much only $expand currently supported.

To finish up on the properties, everything related to the label’s distribution across the various Microsoft 365 workloads is currently unavailable, as the API endpoints do not yet cover policies. This includes properties such as Workload or Policy, which you can still get from the SCC PowerShell cmdlets. Other properties that are missing include the IsRecordLabel one, which makes it difficult to determine which retention label(s) is a formal record, and less important ones such as Priority. As mentioned above, some of the newer features are also not covered yet, i.e. Power Automate integration. Thus the corresponding FlowId/WebHookUrl properties are not returned via the Graph API endpoints.

Next, let’s look at a Create label operation, which you can execute via a POST request against the /security/labels/retentionLabels endpoint. As usual, a JSON payload needs to be provided with the label settings, and depending on the type of label you want to create, a set of mandatory properties must be included. For a simple test, we can create a “retain” label with set duration of 1 year, and the creation date as a trigger. Five properties are required for such label: a displayName, the action (actionAfterRetentionPeriod and behaviorDuringRetentionPeriod, both are needed), the duration (retentionDuration) and the trigger (retentionTrigger). Refer to the official documentation for additional information on the property types and available values.

POST https://graph.microsoft.com/beta/security/labels/retentionLabels

Graph retention labels2Somewhat more complex example of retention labels is one that uses event-based retention. To help with the creation of such types of retention labels, Microsoft also introduced endpoints for working with Events (/security/triggers/retentionEvents​) and Event Types (/security/triggerTypes/retentionEventTypes​), where the latter are needed as part of the retention label configuration, and the former represent an instance of specific event type used to trigger the retention action. For more details and examples, refer to the official documentation in the links above.

To cover the remaining retention labels events, we can also modify existing labels (PATCH request) or remove them when they are no longer needed (DELETE request). Same old rules apply to both operations, i.e. most retention label properties cannot be modified post creation. Similarly, you cannot delete a label that has been published to one or more retention policies or is auto-applied. And since we don’t currently have access to the corresponding policies endpoints, at this time you cannot “unpublish” a label and can only run the delete operation against newly created or “unused” retention labels.

Graph retention labels3

Another thing that comes to mind is that you can use the value of the behaviorDuringRetentionPeriod property to determine whether a given retention label is a “record” one. For such labels, the property should have a value of retainAsRecord, or retainAsRegulatoryRecord is a “regulatory record” label. Thus, even though we have no access to the old IsRecordLabel property, at least we have a workaround we can use.

Lastly, application permission scenarios are something I’d like to cover too, but I will do so in another article. Likely in the form of “here’s a script you can run to get a report of all your retention labels”, as in something suitable for automation.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.