As part of the incoming deprecations of ADAL and the good old MSOnline and AzureAD/AzureADPreview PowerShell modules, Microsoft was quick to announce that parity with the old methods and cmdlets is available as part of the Graph API and the corresponding SDK for PowerShell. Sadly, this wasn’t really the case, as few specific scenarios were initially unaddressed. Likely due to increased customer complaints with the approach of the (now postponed) enddate of June 30th, Microsoft did recently release few small, but important updates. Let’s go over them.
Let’s start with the most recent addition, namely the /directory/subscriptions Graph API endpoint, which brings parity with the old Get-MsolSubscription cmdlet. This was in fact one of the most glaring omissions on Microsoft’s side, and to date the documentation still shows an incorrect replacement (admittedly a step in the right direction compared to the initial suggestion of using Get-MgSubscription!?). Anyway, the newly introduced /directory/subscriptions endpoint, only available under /beta for the time being, offers a 1:1 replacement with the Get-MsolSubscription cmdlet, including the important NextLifecycleDate property (folks actually care about the subscription expiration data, go figure!) and OcpSubscriptionId.
To query this information via the Graph API, issue a GET request against the aforementioned /directory/subscriptions endpoint. Both delegate and application permissions are required, and you will need the Organization.Read.All scope or anything above it (i.e. Directory.Read.All). Here’s an example output via the Graph Explorer tool:
Continuing on the licensing front, Microsoft has also addressed an issue with some missing details from the “sister” endpoint, /subscribedSkus. Compared to the good old Get-MsolAccountSku cmdlet, this endpoint initially did not expose the full AccountSkuId value, or more precisely, the AccountName part of it. This is important for some scenarios where the licenses used by the tenant are purchased from another party, and has now been addressed in both in /beta and /v1.0 flavors of the Graph API. In addition, the number of LockedOut units is now shown as part of the prepaidUnits property. Here’s how it all looks like via the Graph explorer tool:
Next, we have the isLicenseReconciliationNeeded property, which was added to the user resource and can now be queried via the Graph API. This property is important for Exchange-related scenarios, as it signals an improperly licensed user object. This change is also only available under /beta currently, and as far as permissions go, no changes should be required. Here are few examples:
#List all users with the isLicenseReconciliationNeeded property GET https://graph.microsoft.com/beta/users?$select=id,isLicenseReconciliationNeeded #Filter all users for which isLicenseReconciliationNeeded is set to True GET https://graph.microsoft.com/beta/users?$filter=isLicenseReconciliationNeeded eq true
Unfortunately, there seem to be some issues with the current implementation and the $select operator. For example, doing any of the below will result in an Internal Server Error exception:
GET https://graph.microsoft.com/beta/users?$select=id,isLicenseReconciliationNeeded,displayName GET https://graph.microsoft.com/beta/users?$select=id,isLicenseReconciliationNeeded,userPrincipalName
Hopefully, this will be fixed as the property makes its way to /v1.0.
Another glaring omission was the ErrorDetail object, which exposed some (mostly Exchange-related) provisioning issues. Those were addressed by introducing the serviceProvisioningErrors property for the User resource, which we covered in detail in this article. For the time being, said property is also only available under the /beta endpoint. Combine that with the onPremisesProvisioningErrors property to get the full picture, and parity with the good old Get-MsolUser -HasErrorsOnly approach.
The per-user MFA controls are probably the most common question, but Microsoft is unlikely to provide a 1:1 replacement for these, as they steer away from the old Azure MFA implementation in favor of Conditional Access policies, and the poor man’s equivalent, Security defaults. Still, a combination of the /authentication/methods properties and methods, combined with the recently introduced user’s default MFA method should address some common scenarios.