Most articles and e.g. az module commands allow you to do an admin consent on an application object.
However, Service Principals have the same option in the Azure Portal:
In my scenario I have control over both the hosting tenant of this multi-tenant app registration, so I could use the requiredResourceAccess property to read all Oauth2permissiongrants and approleAssignments from the source app registration to re-apply it to the service principal in the consuming tenant.
The result is similar to consenting through the admin portal but does not require user interaction / is fully headless, ideal for when you’re adding scopes/roles to an application and don’t want to have to do a manual reconsent in all managed tenants.
It requires DelegatedPermissionGrant.ReadWrite.All and AppRoleAssignment.ReadWrite.All graph permissions for the calling principal (user or application).
If you don’t have access to the source tenant (e.g. multi tenant), you can also simply create a hashtable with the required permissions (manual definition or export from the application manifest).
Teams Room accounts are usually excluded from conditional access. To do so, they have to be in a security group, which of course we don’t want to do manually.
Most companies choose to use a naming standard and simply use that as a rule to create an exclusion group. This is easy to circumvent, I can create a guest user / get invited with the right name et voila zero CA policies!
A better way is to identify the accounts based on their assigned licenses, e.g. Teams Rooms Basic (6af4b3d6-14bb-4a2a-960c-6c902aad34f3). This, however, is not supported as an Azure AD group membership rule as this is stored in the AssignedLicenses property which will throw an “Unsupported Property” error.
The assignedPlans property however does contain the GUID we need.
The following Azure AD Group dynamic membership rule only matches users that have a Teams Room Basic, Teams Room Standard or Teams Room Pro license:
In automation scenarios it is common to use a service principal (app based) to work with the Graph API, or in my example, with PNP PowerShell against SharePoint (but both scenario’s work the same).
First, you’d need a client certificate, e.g. like this:
You’d then upload the .cer file as a certificate on your service principal to let Azure AD recognize your cert as a valid ‘password’ for your app registration.
Next you’d upload your .pfx file into Keyvault.
Finally, you can use Powershell to construct an access token for a given scope:
The token can then be used to used to call Graph. And an example that shows how to use a sharepoint scoped token for the Sharepoint PNP PowerShell moddule:
Azure AD’s sign in logs also only go back 30 days, which makes it highly recommended to stream Azure AD’s sign in logs to a Log Analytics workspace (Azure Monitor). You just need one single P1 license in your tenant to be able to enable this.
My script gets the last sign in data of all guest accounts in your tenant, without any dependencies other than the Az PS module.
If a guest user has never signed in, the creationDate is used to determine inactivity. Otherwise either the last interactive or last non interactive sign in is used (whichever is most recent).
Additionally, the script can also be configured to automatically clean up any guest accounts that have been inactive for a given number of days by using the -removeInactiveGuests switch.
Even in large environments, processing only takes a few minutes at most.
Microsoft started using these properties in april 2020, so accounts active before that will seem like they have never been active.
Scheduling
This script supports running non-interactive as a runbook in Azure Automation if you supply the -nonInteractive switch. Before this will work, you’ll have to enable Managed Identity on your automation account and run a small script to assign graph permissions to the Managed Identity: AuditLog.Read.All and Organization.Read.All
Reports
If you wish, you can also let the script mail you a report in CSV format. Add the Mail.Send graph permissions like you did with device permissions and give the MailFrom and MailTo parameters a value.
Disclaimer
As always this script is provided as-is and should be reviewed and then used at your own risk.