Azure Active Directory – Office 365 for IT Pros https://office365itpros.com Mastering Office 365 and Microsoft 365 Fri, 06 Sep 2024 11:41:49 +0000 en-US hourly 1 https://i0.wp.com/office365itpros.com/wp-content/uploads/2024/06/cropped-Office-365-for-IT-Pros-2025-Edition-500-px.jpg?fit=32%2C32&ssl=1 Azure Active Directory – Office 365 for IT Pros https://office365itpros.com 32 32 150103932 How to Create Dynamic Administrative Units with PowerShell https://office365itpros.com/2023/09/25/dynamic-administrative-units-ps/?utm_source=rss&utm_medium=rss&utm_campaign=dynamic-administrative-units-ps https://office365itpros.com/2023/09/25/dynamic-administrative-units-ps/#comments Mon, 25 Sep 2023 01:00:00 +0000 https://office365itpros.com/?p=61642

Creating a Dynamic Administrative Unit Per Department

I wrote about using dynamic Entra ID administrative units earlier this year. Not much has changed since then as the feature remains in preview, but an interesting question asked about creating dynamic administrative units with PowerShell. I could have referred the questioner to Microsoft’s documentation, but its examples feature cmdlets from the soon-to-be-deprecated Azure AD module. An example using the Microsoft Graph PowerShell SDK seems like a better idea, so that’s what I cover here.

The question asked about using a CSV file containing department names with the idea of creating a separate dynamic administrative unit for each department. Using CSV files is an effective way of driving scripts, but if the tenant directory is accurate and maintained, it’s easy to extract a list of departments from user accounts.

Scripting the Creation of Dynamic Administrative Units

The steps in a script to create a dynamic administrative unit per department are as follows:

  • Run the Get-MgUser cmdlet to fetch the set of licensed Entra ID member accounts in the tenant. It’s important to fetch licensed accounts to exclude accounts used with shared mailboxes, room mailboxes, and member accounts created through synchronization for multi-tenant organizations.
  • Create an array of departments from user accounts.
  • Create an array of existing administrative units that we can check against to avoid creating duplicate administrative units.
  • For each department, run the New-MgBetaAdministrativeUnit cmdlet to create a new administrative unit (the beta module of the Microsoft Graph PowerShell SDK is needed because the feature is in preview).
  • Calculate the membership rule to find accounts belonging to the department.
  • Run the Update-MgBetaAdministrativeUnit to transform the administrative unit to use dynamic membership.

Here’s the code used to create a new administrative unit:

$Description = ("Dynamic administrative unit created for the {0} department created {1}" -f $Department, (Get-Date))
    $DisplayName = ("{0} dynamic administrative unit" -f $Department)

    If ($DisplayName -in $CurrentAUs.DisplayName) {
        Write-Host ("Administrative unit already exists for {0}" -f $DisplayName)
    } Else {
    # Create the new AU
    $NewAUParameters = @{
        displayName = $DisplayName
        description = $Description
        isMemberManagementRestricted = $false
       }
       $NewAdminUnit = (New-MgBetaAdministrativeUnit -BodyParameter $NewAUParameters)
    }

And here’s the code to transform it into a dynamic administrative unit:

$MembershipRule = '(user.department -eq "' + $Department + '" -and user.usertype -eq "member")'
       # Create hash table with the parameters
       $UpdateAUParameters = @{
	      membershipType = "Dynamic"
	      membershipRuleProcessingState = "On"
	      membershipRule = $MembershipRule
        }
        Try {
            Update-MgBetaAdministrativeUnit -AdministrativeUnitId $NewAdminUnit.Id -BodyParameter $UpdateAUParameters
        } Catch {
            Write-Host ("Error updating {0} with dynamie properties" -f $NewAdminUnit.DisplayName )
        }
        Write-Host ("Created dynamic administrative unit for the {0} department called {1}" -f $Department, $NewAdminUnit.DisplayName)
        

Figure 1 shows the properties of a dynamic administrative unit created by the script, which you can download from GitHub.

Properties of a dynamic administrative unit
Figure 1: Properties of a dynamic administrative unit

Membership Rules Glitches

The membership rule determines the membership of a dynamic administrative unit. Although you can construct filters to use with the Get-MgUser cmdlet to find licensed user accounts belonging to a department, the same flexibility doesn’t exist for the rules used to interrogate Entra ID to find members for a dynamic administrative unit (or dynamic Microsoft 365 group).

The problem is that membership rules don’t allow you to mix properties of different types. For instance, the rule can find user accounts belonging to a department (a string property), but it can’t combine that clause with a check against the assignedLicenses property to make sure that the account is licensed. That’s because assignedLicenses is a multi-value property and the rule can’t mix checks against strings with checks against multi-value properties. If you try, Entra ID signals a “mixed use of properties from different types of object” error. In effect, because we want to create dynamic administrative units based on department, the membership rule is limited to string properties.

Finding the Right Cmdlet to Do the Job

I bet some folks reading this article ask the question “how do I find out what cmdlets to use to interact with Entra ID objects?” It’s a fair question. The SDK modules contain hundreds of cmdlets, some of which have extraordinarily long and complex names. My answer is to use the Graph X-ray add-on to gain insight into what the Entra ID admin center does to manipulate objects. If a method is good enough for the Entra ID admin center, it’s probably good enough for you.


Learn about using Entra ID, the Microsoft Graph PowerShell SDK, and the rest of Microsoft 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

]]>
https://office365itpros.com/2023/09/25/dynamic-administrative-units-ps/feed/ 4 61642
Managing the Entra ID Registration Campaign for Stronger Authentication https://office365itpros.com/2023/09/18/registration-campaign-starts/?utm_source=rss&utm_medium=rss&utm_campaign=registration-campaign-starts https://office365itpros.com/2023/09/18/registration-campaign-starts/#comments Mon, 18 Sep 2023 01:00:00 +0000 https://office365itpros.com/?p=61620

Registration Campaigns Push for Stronger Authentication Methods

A year ago, Microsoft VP for Identity Security Alex Weinert spoke at the TEC 2022 conference and was critical about the slow adoption of multi-factor authentication (MFA) within Microsoft 365 tenants. At the time, only 26.64% of all Entra ID accounts used MFA (34.15% for accounts holding an administrative role). During his presentation, Alex talked about some of the initiatives Microsoft planned to drive MFA adoption and more secure authentication, including changes to the authenticator app, the introduction of authenticator-lite in Outlook mobile, and differentiation of authentication strengths for conditional access policies.

The changes discussed at TEC 2022 are now in production, but there’s still room for improvement. On July 17, Alex Weinert published a Microsoft Technical Community post titled Advancing Modern Strong Authentication focused on Microsoft’s push to get users off SMS responses to use a stronger method such as the Authenticator app. Alex noted that Microsoft telemetry records SMS and voice phone calls still being used for 44% of responses, He also said that Microsoft research concludes that SMS is 40% less effective at repelling compromise by bad actors compared to the Authenticator app, possibly due to an increase in man-in-the-middle attacks.

Entra ID includes a feature called registration campaigns to help organizations move users to the Authenticator app. Essentially, administrators create a campaign and users start to see prompts to “improve your sign ins.” Users can snooze the prompt for a predefined period of up to 14 days but eventually they’ll need to select the authentication method defined for the campaign (the Authenticator app). Nagging until you do something…

The Mail Announcing the Registration Campaign Arrives

Bringing things back to TEC, as I prepared to travel to Atlanta for the 2023 conference this week, I received a note from Microsoft saying that users in my tenant that use SMS and voice methods for MFA responses would be prompted to switch to the Authenticator app (Figure 1).

Microsoft email announcing the start of a registration campaign
Figure 1: Microsoft email announcing the start of a registration campaign

Good as it is for users to upgrade their authentication method, I didn’t want users to receive an unexpected “Improve Your Sign-in” prompt while I was out of the office. Atlanta isn’t too far away, but the five hours dislocation from my normal working hours would definitely interfere with communications.

Pausing the Campaign

The reason why I received the notification was that the tenant settings for Entra ID had an enabled campaign. I’m not quite sure how the campaign was initiated, but it’s probably due to something I did in the past when checking out new Entra ID features. Microsoft complied and launched the campaign by warning me that it was about to begin.

The short-term solution is simple. I edited the campaign settings to put it into a disabled state (Figure 2).

Settings for an Entra ID authentication registration campaign
Figure 1: Settings for an Entra ID authentication registration campaign

The available settings for a registration campaign are Disabled, Enabled, and Microsoft controlled. The latter allows Microsoft to control a registration campaign, which is fine if everyone’s prepared for the change. For instance, it’s a good idea to help users install the Authenticator app on their mobile devices in advance.

It’s also wise to brief people about why using the Authenticator app is easy. The first time a user sees number matching and the additional context (location) displayed by the app when responding to an MFA challenge, they might conclude that it’s a more complex process than typing in a simple code received by SMS. But when they understand that number matching makes it harder for attackers to compromise MFA and the additional context helps them recognize suspicious activity (like an unexpected app provoking a challenge), it usually leads to a good result.

The Campaign Relaunches Soon

It’s a good idea to get rid of SMS and voice responses to MFA challenges, so I’ll relaunch the registration campaign when I return from TEC 2023. Life should be calmer then. At least, that’s the plan until the next emergency arises.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Entra ID and the rest of the Microsoft 365 ecosystem. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/09/18/registration-campaign-starts/feed/ 4 61620
EntraExporter Tool Exports Details of an Entra ID Tenant https://office365itpros.com/2023/08/24/entraexporter-tool/?utm_source=rss&utm_medium=rss&utm_campaign=entraexporter-tool https://office365itpros.com/2023/08/24/entraexporter-tool/#comments Thu, 24 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61313

I’m always on the lookout for tools that might help tenant administrators understand more about the technology they manage. The EntraExporter tool is an example of the kind of utility that I consider to be both valuable and interesting.

EntraExporter is a community-developed PowerShell module designed to export information about the objects and policies in an Entra ID instance for a tenant to JSON files. It’s a way of capturing information about objects like user accounts, groups, administrative units, organization branding, subscriptions, and policies to record of current settings. This is not a backup product, but it is an excellent way of noting the exact configuration of an Entra ID tenant at a point in time.

Installing EntraExporter

To install EntraExporter, run the Install-Module command (this assumes that the PowerShell gallery is a trusted repository). I used this command rather than the example in the documentation:

Install-Module EntraExporter -Scope Allusers

I always install PowerShell modules with Scope AllUsers to force PowerShell to put the module files in $env:ProgramFiles\PowerShell\Modules. From PowerShell 6 onward, Install-Module installs modules in $HOME\Documents\PowerShell\Modules if no scope is defined. This is fine unless you redirect Windows known folders to OneDrive, in which case you end up with module files in OneDrive. The script I wrote to update PowerShell modules used by Office 365/Microsoft 365 installs and updates modules in $env:ProgramFiles\PowerShell\Modules.

The EntraExporter team recommends that you use PowerShell 7 to run the tool.

Running EntraExporter

EntraExporter uses the Microsoft Graph PowerShell SDK to extract information from Entra ID. As the tool runs interactively, it uses delegate permissions, which is fine because the tool only exports information. However, EntraExporter needs a bunch of permissions to access the different objects and policies it processes, so the connect command is:

Connect-MgGraph -Scopes 'Directory.Read.All', 'Policy.Read.All', 'IdentityProvider.Read.All', 'Organization.Read.All', 'User.Read.All', 'EntitlementManagement.Read.All', 'UserAuthenticationMethod.Read.All', 'IdentityUserFlow.Read.All', 'APIConnectors.Read.All', 'AccessReview.Read.All', 'Agreement.Read.All', 'Policy.Read.PermissionGrant', 'PrivilegedAccess.Read.AzureResources', 'PrivilegedAccess.Read.AzureAD', 'Application.Read.All'

The SDK seeks consent for the permissions when you run the command to connect:

Connect-EntraExporter

The signed in user running EntraExporter must grant consent to the requested permissions to access the data (Figure 1). Again, consenting to the requested set of permissions is fine, if you remember that the service principal for the SDK retains consent to use those permissions in future. I’ve written about the way that the SDK accrues Graph permissions over time and possible solutions.

 Requesting consent for the Graph permissions used by EntraExporter
Figure 1: Requesting consent for the Graph permissions used by EntraExporter

One thing I do not like about the Microsoft Graph PowerShell SDK is the way that its enterprise app proclaims itself to be “unverified.” Any Microsoft app in widespread use should be verified to give tenant administrators more confidence about the app’s provenance.

EntraExporter can run in an Azure Automation runbook. To make this possible, make sure that:

Exporting Entra ID Information

With all the necessary permissions in place, I ran the Export-Entra script with the All parameter to export as much directory information as possible. The documentation notes that “B2C, B2B, Static Groups and group memberships, Applications, Service Principals, Users, Privileged Identity Management (built in roles, default roles settings, non-permanent role assignments)” are not exported by default.

Export-Entra -Path 'C:\EntraID\' -All

Various filters are available to select the exact directory information to export, but I wanted to see everything!

How EntraExporter Works

All the EntraExporter code is available in GitHub for your perusal. A quick review identified that the driving force behind the export is the schema defined in Get-EEDefaultSchema.ps1, which tells the exporter the types of objects to export and how to export them. For instance, here’s the definition for user accounts:

# Users
        @{
            GraphUri = 'users'
            Path = 'Users'
            Filter = $null
            QueryParameters = @{ '$count' = 'true'; expand = "extensions" }
            ApiVersion = 'beta'
            Tag = @('All', 'Users')
            DelegatedPermission = 'Directory.Read.All'
            ApplicationPermission = 'Directory.Read.All'
        }

Apart from the slight glitch obvious in Figure 1 (reproducible in the Graph Explorer), everything went smoothly when running an export. The time taken to process an export depends on how many objects are in a tenant directory, particularly groups and users (because they tend to be most numerous). Running a full export can take time because of the need to enumerate group memberships and details of service principals. For a small to medium tenant, expect that everything will be done in 10-15 minutes.

EntraExporter hits an error exporting details of administration units
Figure 2: EntraExporter hits an error exporting details of administration units

The export results in a set of folders in the target location. In Figure 3, you can set the set of folders (one for each type defined in the schema). The content of each folder are the JSON files generated by EntraExporter. If there are many objects, the JSON output for individual objects are in their own folder. This is what you see in Figure 3, where each user object has a folder named after the user account object identifier.

Files generated by EntraExporter
Figure 3: Files generated by EntraExporter

Opening a JSON file reveals the properties of an object. Figure 4 shows the JSON file for a user object viewed through Visual Studio Code.

JSON properties of a user account generated by EntraExporter
Figure 4: JSON properties of a user account generated by EntraExporter

Not Perfect But Entra Exporter’s a Nice Tool to Have

No doubt some will consider Entra Exporter a simple tool of little use because it doesn’t come with features like the ability to reconstruct an object from the exported data. But that’s missing the point. Many organizations have written their own versions of Entra Exporter to capture configurations because they need this data for different reasons (auditing, change control, etc.). The advantage of Entra Exporter is that a tool is available for free that is written in PowerShell and therefore very customizable if it doesn’t meet your exact needs.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/08/24/entraexporter-tool/feed/ 3 61313
Entra ID Guest Accounts Can Now Have Sponsors https://office365itpros.com/2023/08/17/guest-account-sponsors/?utm_source=rss&utm_medium=rss&utm_campaign=guest-account-sponsors https://office365itpros.com/2023/08/17/guest-account-sponsors/#comments Thu, 17 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61219

Defining Guest Account Sponsors with GUI and PowerShell

In July 2023, Microsoft added a new preview feature to allow organizations to assign ‘sponsors’ for Entra ID guest accounts. The idea is that an organization should be able to assign people or groups to be the sponsor of guest accounts. The sponsor should be “a responsible individual,” meaning someone who understand why a guest account is present in the directory, how that guest account is used, and what access they have to data. A sponsor can be an individual account or a group, and a guest account can have up to five sponsors (a mixture of accounts and groups).

When the time comes to review guest accounts and decide to keep or remove the account, sponsors can justify the retention of the guest account or ask for its removal. For instance, if a group owner uses a tool like Entra ID Access Review to conduct a periodic review of the membership of a group (team) and doesn’t recognize a guest account, they can contact the sponsor for more information. Whether or not the group owner gets anything useful from the sponsor is another matter.

Defining Entra ID Guest Account Sponsors

According to Microsoft’s documentation, “If you don’t specify a sponsor, the inviter will be added as a sponsor.” They then go on to explain how to invite an external user and add a sponsor to the new Entra ID guest account (Figure 1).

Adding sponsor information for a new guest account
Figure 1: Adding sponsor information for a new guest account

However, if you don’t add a sponsor to the new external account, the sponsor information is not filled in with the identifier of the account used to create and send the invitation. Maybe my tenant is missing some bits, which is entirely possible.

Sponsor information isn’t filled in either if you add a guest account by adding an external user to a team or sharing a document with them. This isn’t surprising because the sponsors feature is in preview and it takes time for applications like Teams, Outlook, SharePoint Online, and OneDrive for Business to catch up and populate new guest account properties.

In summary, if you want to update the sponsor for a guest account using a GUI, the only way is to edit the account properties in the Entra ID admin center.

Programmatic Updates for Guest Account Sponsors

A beta Graph API is available to list, update, and remove guest account sponsors. As usual, the Graph Explorer is an invaluable tool to help understand how a Graph API works (Figure 2).

Getting sponsor information for a guest account with the Graph Explorer
Figure 2: Getting sponsor information for a guest account with the Graph Explorer

The Get-MgBetaUser cmdlet from the beta module of the Microsoft Graph PowerShell SDK (now at V2.3) can fetch information about sponsors. For example, this code fetches information about a guest account including the sponsors. It then uses the Get-MgUser cmdlet to resolve the set of user identifiers into display names.

$User = Get-MgBetaUser -UserId 7bfd3f83-be63-4a5a-bbf8-c821e2836920 -Property Id, displayName, Sponsors -ExpandProperty Sponsors
ForEach ($Id in $User.Sponsors.Id) { Get-MgUser -UserId $Id | Select-Object DisplayName }

Of course, the code doesn’t handle the situation where a sponsor is a group, but that’s easily added if needed.

If you wanted to scan all guest accounts that don’t have sponsors defined and add a default sponsor, you could do something like this. The code:

  • Defines an account to be the default sponsor.
  • Builds a payload to use when updating the guest accounts.
  • Finds guest accounts in the tenant.
  • Checks each guest account for sponsors. If none are found, the script applies the default sponsor.

Connect-MgGraph -Scopes User.ReadWrite.All

$DefaultSponsorId = (Get-MgUser -UserId James.Ryan@office365itpros.com).Id
$Body = '{"@odata.id": "https://graph.microsoft.com/beta/users/' + $DefaultSponsorId + '"}'

[array]$Guests = Get-MgBetaUser -Filter "userType eq 'Guest'" -All -Property Id, displayName, Sponsors -ExpandProperty Sponsors | Sort-Object displayName
If ($Guests) {
    Write-Host "Scanning for sponsors"
    ForEach ($Guest in $Guests) {
      If ($Null -eq $Guest.Sponsors.Id) {
         Write-Host ("Guest {0} has no sponsors - updating with default sponsor" -f $Guest.displayName) 
         $Uri = ("https://graph.microsoft.com/beta/users/{0}/sponsors/`$ref" -f $Guest.Id)
         Invoke-MgGraphRequest -Uri $Uri -Method Post -Body $Body
      }
    }
}

Auditing Updates to Guest Account Sponsors

Last week I wrote about the way that Entra ID auditing does not capture details of changes to the usage location property for user accounts. As it turns out, updating a guest account with sponsor information creates an audit record without details of the change. Again, this could be a matter of timing and an update is coming to make sure that audit log events for account updates capture sponsor information correctly.

Tracking Guest Additions

Since Azure B2B Collaboration introduced guest accounts in summer 2016, administrators have been tracking the creation of guest accounts in different ways (for instance, here’s how to track the addition of guest accounts to teams). In many cases, the reason for doing so was to know who was responsible for the creation of a guest account. With sponsors, that need might go away, or at least it might be easier to retrieve the “who created that account information” by using the sponsor information stored for accounts. That is, once the apps record sponsors.


Learn about using Entra ID, PowerShell, the Microsoft Graph, and the rest of Office 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

]]>
https://office365itpros.com/2023/08/17/guest-account-sponsors/feed/ 2 61219
Updating Entra ID Risky Users with PowerShell https://office365itpros.com/2023/08/16/entra-id-risky-users/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-risky-users https://office365itpros.com/2023/08/16/entra-id-risky-users/#respond Wed, 16 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61184

Entra ID Identity Protection Monitors Sign-Ins to Find Problem Accounts

Entra ID Identity Protection is a solution that uses machine learning to monitor and detect problematic sign-in activity for a tenant. The idea is that machine learning is better at examining audit logs to recognize signs of potential problems, especially when a tenant supports a large number of accounts. Entra ID Identity Protection requires Azure AD Premium P2 licenses.

Graph API for Entra ID Risky Users

The riskyUser resource type is a Graph API used by Entra ID Identity Protection to. programmatically represent risky user accounts. Usually, it is Entra ID Identity Protection that marks an account as being at risk based on the pattern of activity for the account (for instance, a large number of attempted sign-ins that fail). Alternatively, the risk state of a user can be set by an administrator if they know that an account is compromised.

The actions supported by the API are:

  • List risky users.
  • Get details of a risky user.
  • List the history of a risky user.
  • Confirm that the state of a user account is risky due to known compromise.
  • Dismiss the risky status for a user (use the Graph API as shown below).

Examples of Microsoft Graph PowerShell SDK cmdlets based on the Risky User API include:

# Use scope IdentityRiskyUser.ReadWrite.All to read risky user information and IdentityRiskyUser.ReadWrite.All to update.
Connect-MgGraph -Scopes IdentityRiskyUser.ReadWrite.All
Get-MgRiskyUser | Sort-Object RiskLastUpdatedDateTime -Descending
Get-MgRiskyUser -RiskyUserId 96bfb216-e88c-4f1f-86d7-04747e5fc686 | Format-List)
Get-MgRiskyUserHistory -RiskyUserId 96bfb216-e88c-4f1f-86d7-04747e5fc686 | Format-List)
Confirm-MgRiskyUserCompromised -UserIds (Get-MgUser -UserId Ben.James@Office365itpros.com).Id

Accounts that need to be checked show up under risky activities in the Protection section of the Entra ID admin center (risky activities can be attributed to service principals if Identity Protection finds an app doing something unusual). Figure 1 shows the details logged for an account after an administrator ran the Confirm-MgRiskyUserCompromised cmdlet. This action forces Identity Protection to regard the account as being highly at risk, so it sends global administrators email to inform them about the problem.

Details of a risky user in Entra ID Identity Protection

Entra ID risky users
Figure 1: Details of a risky user in Entra ID Identity Protection

Once an account is flagged as risky, it remains in this state until an administrator remediates the risk. On my tenant, I had some old risky users that hadn’t been processed. To clean things up, I used the PowerShell code below to find risky users awaiting administrator remediation and checked the last updated date to see if the risky user state was more than 183 days old. If true, I used the Graph API to dismiss the risky user state.

Write-Host "Finding risky users"
[array]$RiskyUsers = Get-MgRiskyUser -Filter "(riskState ne 'remediated') and (riskState ne 'dismissed')" | Sort-Object RiskLastUpdatedDateTime -Descending

$Uri = "https://graph.microsoft.com/beta/riskyUsers/dismiss"
[datetime]$CheckDate = (Get-Date).AddDays(-183)

ForEach ($User in $RiskyUsers) {  
   If ($User.RiskLastUpdatedDateTime -le $CheckDate) {
      Write-Host ("User {0} ({1}) risk state last updated on {2} - removing..." -f $User.UserDisplayName, $User.UserPrincipalName, $User.RiskLastUpdatedDateTime)
      $DismissedUserInfo = '{"UserIds": [ "' + $User.Id + '" ]}'
      Invoke-MgGraphRequest -Uri $Uri -Body $DismissedUserInfo -Method Post
   }
}


User Jim.Smith (Jim.Smith@office365itpros.com) risk state last updated on 18/08/2022 15:54:04 - removing...
User Chris Bishop (Chris.Bishop@office365itpros.com) risk state last updated on 11/05/2021 06:05:39 - removing...

This code dismisses the risk state even if the state is deemed High. A more complete implementation might exclude these risky users and process only those with risk state of medium or low.

It takes a few minutes before the dismissed state becomes effective for accounts.

Linking Entra ID Risky Users to Conditional Access

When I first read about the Confirm-MgRiskyUserCompromised cmdlet, I wondered if I would ever use such a command. If an administrator knows about an account compromise, surely their first step is to prevent access to whoever has compromised the account by disabling access and changing its password? After all, no need exists to mark an account as risky when an administrator knows that it is compromised/

But then I wondered if the advantage lies in the fact that high-risk accounts can be picked up by a conditional access policy. Identity Protection started off with its own risk policies, and Microsoft is now encouraging customers to migrate to conditional access policies instead, citing advantages such as Graph API support and greater flexibility. Given the number of features Microsoft has added to conditional access policies recently, like protected actions and authentication strength, the argument is certainly true.

Creating an authentication policy to block access to accounts marked at risk is straightforward.

  • Select the users within scope of the policy.
  • Add All Cloud Apps as the target resource.
  • Set User Risk to High (or High and Medium).
  • Set session sign-in frequency to every time.
  • Under access control, select grant access with a password change (and for good measure, require multi-factor authentication).

When the conditional access policy is active, continuous access evaluation will detect the risk and block connections from any user (Figure 2) marked as High risk (like those marked by the Confirm-MgRiskyUserCompromised cmdlet). An administrator will have to reset the account password or, if the account is enabled for Self-Service Password Reset (SSPR), the user will have to choose a new password before they can sign in again.

Entra ID blocks a risky user from making a connection
Figure 2: Entra ID blocks a risky user from making a connection

The thing about conditional access policies is that it’s easy to get into a mess with conflicting and competing policies. I always test with a single user and I use the IdPowerTools app to document the set of policies defined in my tenant.

Entra ID Risky Users Just Another Thing to Consider in a Security Plan

Entra ID Identity Protection isn’t a silver bullet to prevent user account compromise. Enabling multi-factor authentication for all user accounts is a much more fundamental solution to the compromise problem. Identity Protection brings some extra intelligence to the task of managing sign-ins and helps administrators to identify problem connections more quickly and more accurately. Having a Graph API (and SDK cmdlets) available to automate operations for risky user accounts is a bonus.

Deciding how to use these tools takes time and consideration. They must fit in your overall security posture and not conflict with any of the other protection techniques that are in use. Identity Protection is just another factor for administrator to consider.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2023/08/16/entra-id-risky-users/feed/ 0 61184
Filtering Against the Entra ID Employee Hire Date Property https://office365itpros.com/2023/08/10/entra-id-employee-hire-date/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-employee-hire-date https://office365itpros.com/2023/08/10/entra-id-employee-hire-date/#comments Thu, 10 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61146

Two Filters Available for the Entra ID Employee Hire Date Property

In an article published earlier this year about different ways to find Entra ID (Azure AD) user accounts with PowerShell, I commented that the Get-MgUser cmdlet could not apply a server-side filter against the Entra ID employee hire date property. For instance, to find accounts with an employee hire date, you must use Get-MgUser to fetch accounts and then apply a client-side filter to find the target objects. For instance, this code finds accounts with an employee hire date later than 1 January 2023:

[array]$Employees = Get-MgUser -filter "userType eq 'Member' and EmployeeId ge ' '" -Property Id, displayname, userprincipalname, employeeid, employeehiredate, employeetype
$CheckDate = Get-Date “8-Jul-2023”
$Employees | Where-Object {$CheckDate -as [datetime] -lt $_.EmployeeHireDate} | Sort-Object {$_.EmployeeHireDate -as [datetime]} -Descending | Format-Table DisplayName, userPrincipalName, employeeHireDate -AutoSize

DisplayName   UserPrincipalName                 EmployeeHireDate
-----------   -----------------                 ----------------
Michael King  Michael.King@office365itpros.com  01/08/2023 23:00:00
Terry Hegarty Terry.Hegarty@office365itpros.com 01/08/2023 23:00:00
Hans Geering  Hans.Geering@office365itpros.com  31/07/2023 23:00:00
Chris Bishop  Chris.Bishop@office365itpros.com  31/07/2023 23:00:00

The problem persists in the latest version of the Microsoft Graph PowerShell SDK using both the Get-MgUser and Get-MgBetaUser cmdlets.

Dynamic Groups Support for Employee Hire Date

All of which brings me to news that membership rules for Entra ID dynamic groups support the PowerShell le and ge operators against the employee hire date property. This capability is a preview for now.

In a nutshell, the new feature supports the creation of dynamic groups (which require Entra ID Premium P1 licenses) based on a filter against the EmployeeHireDate property. Two kinds of date filters are available. The first performs a simple comparison to test if the employee hire date is greater than or equal to or less than or equal to a specified date. For example, this command creates a dynamic Microsoft 365 group with a membership rule that finds all member accounts with an employee hire date greater or equal to 1 January 2023:

$Group = New-MgGroup -DisplayName "New Employees (Dynamic)" -Description "Dynamic group containing new employees (2023)" -MailEnabled:$True -SecurityEnabled:$False -MailNickname New.Employees.2023 -GroupTypes "DynamicMembership", "Unified" -MembershipRule "(user.employeehiredate -ge ""2023-01-01T00:00:00Z"" -and (user.usertype eq ""Member"")" -MembershipRuleProcessingState "On"

Dates must be passed in the sortable format rather than a more human-friendly type. For PowerShell, use Get-Date to set the date and format the output as follows:

$DateForFilter = (((Get-Date).AddDays(-365)) | Get-Date -format 'yyyy-MM-ddThh:mm:ssZ')

The second filter tests the employee hire date against a calculated date based on the current date. This example creates a dynamic Microsoft 365 group with a membership rule that looks for employees with hire dates within the last 31 days (system.now is the current date):

$Group = New-MgGroup -DisplayName "New Employees (Last Month)" -Description "Dynamic group containing employees hired in the last month" -MailEnabled:$True -SecurityEnabled:$False -MailNickname New.Employees.LastMonth -GroupTypes "DynamicMembership", "Unified" -MembershipRule "(user.employeehiredate -ge system.now -minus p31d ) -and (user.usertype eq ""Member"")" -MembershipRuleProcessingState "On"

It looks like only day intervals are supported. Entra ID rule validation rejects values like p4w (4 weeks) or p1m (1 month).

Validating the Filter Against the Entra ID Employee Hire Date Property

It’s easy to check the effectiveness of the membership rule. Let Entra ID calculate the membership for the dynamic group and note who’s present (Figure 1):

Viewing members of a dynamic group using a membership rule using the Entra ID employee hire date property

Azure AD employee hire date property
Figure 1: Viewing members of a dynamic group using a membership rule using the Entra ID employee hire date property

Then run the Get-MgUser example shown at the top of the article with an appropriate value inserted into the $CheckDate variable (use this code to set the variable to 31 days from the current date).

$CheckDate = (Get-Date).AddDays(-31)

Check the results generated by PowerShell against the set shown in the Entra ID admin center. The two should match. If they don’t, wait for 30 minutes or so to be sure that Entra ID has had time to process any recent updates and try again.

Time Updates All Cmdlets

It takes time for the Graph SDK cmdlets to catch up with new developments and preview features. Now that the Entra ID developers have enabled date filtering against the employee hire date property, it can’t be long before server-side filters work with Get-MgUser too. And if they don’t, there is a workaround – fetch the membership of the dynamic group with Get-MgGroupMember and use that information instead of running Get-MgUser. That’s the kind of lateral thinking we’re looking for in the great PowerShell script-off competition at TEC 2023 next month!


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/08/10/entra-id-employee-hire-date/feed/ 1 61146
Entra ID Audit Captures Some But Not All Updates of User Account Properties https://office365itpros.com/2023/08/08/audit-user-account-changes/?utm_source=rss&utm_medium=rss&utm_campaign=audit-user-account-changes https://office365itpros.com/2023/08/08/audit-user-account-changes/#comments Tue, 08 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61117

Audit User Account Changes – But Not For All Properties

In a Twitter (X) discussion about Microsoft Entra ID logging, one of the participants commented that “On the small end, just being able to see who changed a user account property like UsageLocation” would be a good thing. The point here is that changing the usage location of a user account can have licensing implications.

The complaint is that the Entra ID audit log doesn’t disclose who updated a user account and changes the usage location. And as it turns out, the statement is true, as a quick test reveals. Update a user account and change several properties, including the usage location. Wait for a few minutes and check what the Entra ID audit log reports. It should show something like Figure 1. The changes made to all other properties are there, but there’s no trace of the change made to move the account’s usage location (in this case, from Ireland to France).

Details of updated properties for a user account in the Entra ID audit log

Audit user account changes
Figure 1: Details of updated properties for a user account in the Entra ID audit log

Later on in the conversation, the original complainant stated that they had “opened a case last year on the UsageLocation issue. I was told that the missing data is ‘by design’ and it was closed.” That response seems strange. Why would Entra ID consider that not logging changes made to account user locations is a design feature? After all, their documentation emphasizes that “you must specify the Usage location for all members.”

How the Audit Log Stores Details of User Account Updates

Entries from the Entra ID audit log flow through to the unified audit log (now holding 180 days of audit data for Office 365 E3 accounts). Perhaps the data ingested by the unified audit log would hold the missing usage location information. It’s always worth checking.

Many workloads pump information to the unified audit log, and it’s a great source of who-did-what knowledge covering situations like permission consent grants, usage of sensitivity labels, and keeping an eye on membership changes in Microsoft 365 groups. Knowing how to extract information from the audit log is a skill that every Microsoft 365 enterprise tenant administrator should have.

Unfortunately, while some fields are standard, the bulk of the interesting audit information is in the AuditData property. Workloads can stick whatever they like into AuditData, and some workloads take free liberty to do their own thing. The result is that interpreting the content of audit events is always “interesting” and takes more time than it should.

In this case, the action we want to check is “update user.” (with or without the full stop). Not all of the events logged for this action are interesting because some originate from background processes. Checking a bunch of events revealed that the ones which hold relevant data have an entry in the ModifiedProperties property called “Included Updated Properties.” For instance, the Entra ID audit record shown in Figure 1 includes this data when ingested into the unified audit log:

$Auditdata.ModifiedProperties | fl

Name     : City
NewValue : [
             "Flayosc"
           ]
OldValue : [
             "Dublin"
           ]

Name     : Country
NewValue : [
             "France"
           ]
OldValue : [
             "Ireland"
           ]

Name     : TelephoneNumber
NewValue : [
             "+33 4 9242554"
           ]
OldValue : [
             "01-2070807"
           ]

Name     : StreetAddress
NewValue : [
             "24 Chemin de Floriege"
           ]
OldValue : [
             "15 Fairways"
           ]

Name     : State
NewValue : [
             "Var"
           ]
OldValue : [
             "Dublin"
           ]

Name     : PostalCode
NewValue : [
             "83780"
           ]
OldValue : [
             "D18A6R4"
           ]

Name     : Included Updated Properties
NewValue : City, Country, TelephoneNumber, StreetAddress, State, PostalCode
OldValue :

Six properties are described in the Included Updated Properties property, but there’s no trace of UsageLocation. So no joy there…

Writing a Script to Report Changed Properties

After discovering how audit records hold details about updated properties, it didn’t take too long to create a script to report changed properties for user accounts. The biggest problem is extracting data in a reportable format from the AuditData property. With some trial and error and some persistence, it’s possible to generate a reasonable report. Figure 2 shows the script output.

Reporting changes to user account properties
Figure 2: Reporting changes to user account properties

You can download the script from GitHub. It is very much an example to illustrate the principal of extracting this information and can be improved. For instance, detailing the exact changes made to licenses assigned to an account.

The Hassle of Dealing with Non-Standard Audit Events

The unified audit log is a huge benefit for enterprise tenants. It’s just a pity that the Microsoft development groups make it so difficult for administrators to extract information from the audit log because of some quixotic approaches to how they format data written in log events. It would be nice if all groups used a standard method to format audit entries, but I guess that’s not going to happen. But it would be nice if Entra ID logged changes to the usage location property.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2023/08/08/audit-user-account-changes/feed/ 1 61117
Managing Assigned Licenses for Deleted User Accounts https://office365itpros.com/2023/08/07/deleted-user-account-licenses/?utm_source=rss&utm_medium=rss&utm_campaign=deleted-user-account-licenses https://office365itpros.com/2023/08/07/deleted-user-account-licenses/#comments Mon, 07 Aug 2023 01:00:00 +0000 https://office365itpros.com/?p=61072

Why Some Deleted User Accounts Store License Assignment Information And Some Do Not

A reader asks why the Microsoft 365 admin center displays a license for a deleted user account (Figure 1). The follow-up question is how they can remove the license and reassign it to another user.

Deleted user account with license assignment information
Figure 1: Deleted user account with license assignment information

The answer is that they don’t need to do anything. When an administrator removes a user account, Entra ID moves the account into its deleted items container (aka the wastebasket). The deleted account remains there for 30 days, during which time an administrator can restore the account (see the big blue button in Figure 1). The ideal situation is for a restored account to come back with all its settings intact, including assigned licenses. Entra ID tracks the licenses that the deleted account once had so that it can reassign the licenses to the newly-restored account.

Any licenses assigned to a deleted user account become available following the account’s deletion. This includes accounts used for shared mailboxes where assigned licenses exist to enable features like archiving. No one wants to keep expensive licenses on ice pending account restores, so often the licenses end up being assigned to other accounts.

It Depends on How User Accounts Are Deleted

The interesting thing is that the presence of assigned licenses for deleted accounts depends on the method used to delete the account. When an administrator deletes an account through the Microsoft 365 admin center, the process removes license assignments before removing the account, which means that if you examine the properties of the deleted account afterward, no licenses are present (Figure 2).

Deleted user account with no license assignment information
Figure 2: Deleted user account with no license assignment information

However, if you use PowerShell or the Microsoft Entra admin center to remove an account, the deleted account object retains license information. The licenses are not assigned, but the license information is present in the properties of the deleted user object. This is why Figure 1 shows that a deleted account has a license.

The reason why the Microsoft 365 admin center removes licenses and other administrative interfaces do not is due to the multi-phase process the Microsoft 365 admin center uses for account removal. The process includes steps such giving another user access to the user’s OneDrive for Business account (Figure 3) to allow for the recovery of any important information before the permanent removal of the user account.

Steps in the Microsoft 365 admin center account deletion process
Figure 3: Steps in the Microsoft 365 admin center account deletion process

PowerShell and the Microsoft Entra admin center only concern themselves with the removal of the user account object, and that’s why some deleted user accounts have license assignment information and others do not.

Care Needed When Restoring Deleted Accounts

The Microsoft 365 admin center user restore process warns administrators to:

  • Assign licenses after restoring the account.
  • Change the account password.

A user account has no access to Microsoft 365 services after it is restored until these steps are complete.

By comparison, if you restore a deleted account through the Microsoft Entra admin center or PowerShell, the license assignments noted in the account properties become active again. This can lead to an over-assignment condition where too many user accounts have licenses for specific products, like Office 365 E3. In this situation, administrators must buy additional licenses or remove licenses from other accounts (or delete other accounts).

To check if the properties of any deleted accounts include license assignments, you can run these Microsoft Graph PowerShell SDK commands to fetch details of deleted accounts and report if any license data exists:

Connect-MgGraph -Scope Directory.Read.All
[array]$DeletedUsers = Get-MgDirectoryDeletedItemAsUser -Property DeletedDateTime, Id, displayName, userPrincipalName, assignedlicenses | Sort-Object DeletedDateTime -Descending
ForEach ($User in $DeletedUsers) {
  If ($User.assignedLicenses) {
     $Licenses = $User | Select-Object -ExpandProperty assignedLicenses
     [string]$Skus = $Licenses.SkuID -Join ", "
     Write-Host ("Deleted user {0} has license information noted in their account properties {1}" -f $User.displayName, $Skus ) }
}

If you use PowerShell to script the recovery of user accounts, you should check for license assignments and validate that available licenses are available before recovering the account. This article explains how to fetch subscription information using the Get-MgSubscribedSku cmdlet and the subscriptions API, including the count of assigned and available licenses. It’s easy to check if a license for a SKU is available before assigning it to a recovered account.

Alternatively, go ahead and recover the account and fix the licensing problem later through the Microsoft 365 admin center.

Processing Differences Exist

This discussion reveals a difference in behavior between the raw processing performed by Graph APIs and the wrapper around the APIs implemented in the Microsoft 365 admin center. Sometimes the differences bubble up to the surface and the reasons for the differences aren’t immediately clear until you poke around to discover why things happen the way that they do. Isn’t that often the case in IT?


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/08/07/deleted-user-account-licenses/feed/ 5 61072
Microsoft Entra ID Access Reviews Get Machine Learning Recommendations https://office365itpros.com/2023/07/21/entra-id-access-review-ai/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-access-review-ai https://office365itpros.com/2023/07/21/entra-id-access-review-ai/#respond Fri, 21 Jul 2023 01:00:00 +0000 https://office365itpros.com/?p=60922

Entra ID Access Reviews Based on User Affiliation Won’t Work Without an Accurate Directory

I like the idea behind Azure AD (Entra ID) Access Reviews and have previously described their use to identify inactive guest members of Microsoft 365 groups. I’ve also covered how to use the Graph API to retrieve information about Access Reviews.

Access reviews are a premium identity governance feature, which means that the people involved in reviews need Azure AD Premium P2 licenses (more on this later). Given that automation saves time, paying for a few P2 licenses is not a big deal.

Which brings us to the July 17 announcement covering two new features for Access reviews:

  • Machine learning powered access review recommendations (user to group affiliation).
  • User inactivity access review scoping.

Artificial Intelligence Everywhere

As everyone knows, Microsoft’s current big bet is the application of machine learning and artificial intelligence wherever possible within their products. Microsoft 365 Copilot is the poster child for this initiative, but I have my doubts that many organizations will seize the opportunity to buy $30 monthly licenses to help people create better documents or process email more quickly. Yes, it’s only a dollar a day, but a dollar a day across an entire organization soon becomes big money, especially if you need to buy Microsoft 365 E3 or E5 licenses to become eligible to use Copilot.

Directory Accuracy Key for User-to-Group Affiliation in Entra ID Access Reviews

According to Microsoft’s documentation, “Machine Learning based recommendation opens the journey to automate access reviews, thereby enabling intelligent automation and reducing access rights attestation fatigue.” That’s quite a promise. In reality, recommendations based on user-to-group affiliation means that access reviews use a machine learning-based score to figure out if group members are close to or far from other group members in terms of the organization’s reporting structure.

In other words, if you are in a team with another person and share the same manager, you have high affiliation. Someone else who works in a completely different part of the organization and has a manager who has no relationship in the reporting structure to another in your reporting chain has low affiliation with you and your co-workers.

This is yet another example of a Microsoft feature that depends on a high level of accuracy for manager-employee links in the directory. Unhappily, the directory of some tenants is sadly neglected, with just enough attention being paid to ensure that users can sign into their accounts. Maintaining organizational information so that Teams, the Microsoft 365 user profile, and Outlook’s Org Explorer can display accurate organization charts is not as high on the agenda as Microsoft obviously thinks it should be.

Finding Inactive Group Members

Machine learning to analyze user affiliation won’t work for guest members of Microsoft 365 groups because these accounts usually aren’t part of the organization’s reporting structure. What Microsoft calls “User inactivity access review scoping” means checking sign-in logs to establish if an account has signed in within a set period (like 30 days). If they haven’t signed in, the account is deemed to be inactive and becomes a candidate for removal from the group.

Although it’s got a spiffing new name, this feature was in public preview for a long time and is a blunt instrument for detecting inactivity. For instance, many guests participate in group discussions via email. They don’t need to sign into the host tenant to receive copies of group discussions.

Testing Entra ID Access Reviews with Affiliation

In any case, I decided to try out the new features. After creating a new access review and requesting that the review should include user-to-group affiliation, I saw that Entra ID politely rejected my request (Figure 1).

No AI available for this Entra ID Access Review
Figure 1: No AI available for this Entra ID Access Review

The answer lies in the fact that access reviews including user to group affiliation or inactive users require Microsoft Entra ID Governance licenses. I have Azure AD Premium P1 and P2 licenses, but no governance licenses.

According to Microsoft’s June 7 announcement for Microsoft Entra ID Governance:

ID Governance can be added to Azure AD Premium P1 or P2 licenses as a cost-effective way to bring comprehensive identity governance to all employees and business guests, for $7 per user per month for Azure AD Premium Plan 1 (P1) customers.”

Microsoft offers a 1-month free trial of 25 licenses for Microsoft Entra ID Governance. In this instance, I’ll pass. Perhaps the delights of Entra ID Governance will attract me in the future. It’s just disappointing to find that features are blocked because of new licensing demands.

Reviewing Guests is a Good Idea, and You Don’t Need Entra ID Access Reviews to Check

It’s sensible to review guest accounts regularly and remove those that are no longer used for B2B collaboration (guest accounts in Teams and groups) or SharePoint sharing. You don’t need Access Reviews to check guest accounts as some basic PowerShell will do the trick. And if you only want to find old guest accounts over a certain age, you can do that with this script. Even better, neither script won’t need any additional licenses.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/07/21/entra-id-access-review-ai/feed/ 0 60922
Microsoft Launches Restricted Administrative Units in Preview https://office365itpros.com/2023/07/14/restricted-administrative-units/?utm_source=rss&utm_medium=rss&utm_campaign=restricted-administrative-units https://office365itpros.com/2023/07/14/restricted-administrative-units/#comments Fri, 14 Jul 2023 01:00:00 +0000 https://office365itpros.com/?p=60850

Restricted Administrative Units Protect Sensitive User Accounts and Security Groups

Following up on its announcement of the wonders promised by the renaming of Azure AD to Microsoft Entra ID, Microsoft released the preview of Entra ID Restricted Administrative Units, a type of administrative unit designed to protect sensitive user accounts, devices, and security groups from unfettered access by tenant administrators. Microsoft describes three scenarios when they think this capability is useful:

  • Protect user accounts for people such as senior executives so that accounts holding regular administrative roles cannot perform tasks such as resetting passwords for those accounts.
  • Enable country-level administration for specific user accounts and security groups.
  • Restrict the ability to update the membership of security groups that protect sensitive data.

It’s worth noting that restrictions apply within Entra ID. Administrators can continue to process updates to mailbox properties such as adjusting the primary SMTP address of mailboxes owned by accounts within restricted administrative units.

Creating a Restricted Administrative Units

Creating a restricted administrative group is simple. Go to the Microsoft Entra admin center, access the administrative units blade, and add a new unit. Make sure that the Restricted management administrative unit option is set to Yes (Figure 1).

Creating a new restricted administrative unit
Figure 1: Creating a new restricted administrative unit

You can’t switch a normal administrative unit to restricted after creation, nor can you do the reverse and remove the restricted scope to make a restricted administrative unit “normal” once it’s created.

Management Roles for Restricted Administrative Units

Next, just like a regular administrative unit, you assign management roles. The difference is that Entra ID scopes these roles to the administrative unit, so you should assign appropriate roles that you consider necessary to manage the accounts and security groups (Microsoft 365 groups and distribution lists are unsupported) that are members of the administrative unit. For instance, if you want country-level management for user accounts, you’d assign administrators from that country to the User administrator role.

Figure 2 shows the final point in the creation wizard, and you can see that two roles assignments exist for the restricted administrative unit. Administrators of restricted administrative units require A Microsoft Entra ID P1 licenses.

Final stage of creating a new restricted administrative unit
Figure 2: Final stage of creating a new restricted administrative unit

Microsoft’s documentation includes more detail, including some limits and restrictions.

Restricted Administrative Units in Action

The nice thing about restricted administrative unit is that accounts assigned global (full directory) roles cannot override the scoping that restricts management access to the administrative unit. Take the situation where a global administrator attempts to update the job title of an account that’s a member of a restricted administrative unit. The Microsoft Entra admin center blocks access to editing account properties (Figure 3).

Restricted administrative unit scoping prevents account property updates
Figure 3: Restricted administrative unit scoping prevents account property updates

And if the administrator tries to circumvent the block with PowerShell by running the Update-MgUser cmdlet, the operation fails with an insufficient privileges error:

Update-MgUser -UserId Rene.Artois@office365itpros.com -JobTitle "Cafe Owner and Resistence Hero"

update-mguser : Insufficient privileges to complete the operation. Target object is a member of a restricted management administrative unit and can only be modified by administrators scoped to that administrative unit. Check that you are assigned a role that has permission to perform the operation for this restricted management administrative unit. Learn more: https://go.microsoft.com/fwlink/?linkid=2197831
Status: 403 (Forbidden)
ErrorCode: Authorization_RequestDenied

Of course, global administrators can solve their problem by removing the account from the restricted administrative unit, updating the account properties, and putting them back into the unit. However, these actions create audit records that might be difficult for the administrator to explain.

Remember that individual user accounts can be members of multiple administrative units. For example, my account could be a member of four administrative units, two of which are restricted. In this situation, holders of roles assigned to either of the restricted administrative units can manage my account.

New and Useful Scoping Mechanism

Restricted administrative units offer another way to scope responsibilities for account, device, and security group management. I suspect the lack of support for Microsoft 365 groups is because of the number of associated workloads that can connect to these groups. Not supporting distribution groups is also unsurprising given their affiliation with Exchange Online. The likelihood is that large enterprises will be most interested in the functionality, but it’s open to all tenants with the necessary licenses.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2023/07/14/restricted-administrative-units/feed/ 2 60850
Microsoft Rebrands Azure AD as Microsoft Entra ID https://office365itpros.com/2023/07/13/microsoft-entra-id-azure-ad/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-entra-id-azure-ad https://office365itpros.com/2023/07/13/microsoft-entra-id-azure-ad/#comments Thu, 13 Jul 2023 01:00:00 +0000 https://office365itpros.com/?p=60822

Microsoft Entra is the Latest Microsoft Rebranding Triumph

On July 11, Microsoft announced that the Microsoft Entra brand is absorbing Azure Active Directory (Azure AD), which now becomes Microsoft Entra ID. The announcement came along with news of two new Entra products as Microsoft ventures into the Security Service Edge (SSE) arena to take on competitors such as Zscaler, Palo Alto Networks, and Netskope, all leaders in Gartner’s 2023 Magic Quadrant for the SSE space.

According to the announcement, Microsoft 365 scenarios in Microsoft Entra Internet Access are in preview today. The Microsoft Technical Community blog says that Entra Internet Access includes “unique capabilities for Microsoft 365, including Universal Tenant Restrictions, to prevent data exfiltration to other tenants or personal accounts including anonymous access, near-real time threat detection, higher precision of the risk assessment on user, location, and device, and more seamless access to Microsoft 365 apps.” If you’re interested, head to the preview sign-up page for Entra Internet Access.

The rebranding of Azure AD to become Microsoft Entra ID
Figure 1: The rebranding of Azure AD to become Microsoft Entra ID

A message center notification (MC637368) followed up to make sure that Microsoft 365 tenant administrators heard the news about Azure AD’s new name, even though this is just a rebranding exercise that delivers precisely zero new functionality to any tenant. It’s like previous rebranding triumphs where Microsoft made:

  • Microsoft 365 the catch-all brand for Office.
  • Microsoft Defender the catch-all brand for Security.
  • Microsoft Purview the catch-all brand for Compliance.
  • Microsoft Viva the catch-all brand for anything that the marketeers could see.

Web pages might change, documentation might use different terminology, but Azure AD remains the same. Microsoft characterizes the name change as representing “the evolution and unification of the Microsoft Entra product family, and a commitment to simplify secure access experiences for everyone.” This is corporate speak for “we’re stuffing Azure AD into the Microsoft Entra brand to create Entra ID. It makes us look good even if it doesn’t do anything for the end user.” More information about the rebranding is available here.

Microsoft Entra ID Isn’t for On-Premises Software

In my opinion, Azure AD did a good job to deliver secure access experiences with many enhancements delivered over the last two years in the drive to make modern authentication and MFA more pervasive, like adding Authenticator Lite to Outlook mobile, and improving how conditional access policies work by including new capabilities like measuring the authentication strength for connections. The rebrand adds nothing.

A case can be argued that Microsoft is throwing away the reputation accrued over nearly 25 years by Active Directory and Azure Active Directory to give a existing product a new name. Equally, you could argue that renaming Azure AD will remove the confusion that sometimes exists between the cloud and on-premises directories. What’s for sure is that Windows Active Directory is not changing its name because the Entra brand does not extend to on-premises software. The same applies to Active Directory Federation Services (AD FS) and Active Directory Domain Services (AD DS).

On the plus side, Microsoft isn’t changing licensing or pricing. They also say that they’re not changing capabilities, but that’s just corporate fluff too because code doesn’t work differently when it gets a new name. URLs, APIs, and authentication libraries remain the same.

Microsoft Entra Renaming Schedule

Following the 30-day notification period for tenants, Microsoft will roll out the name change over the rest of 2023, with service plan names (the kind you see when assigning licenses to user accounts) due to change on October 1, 2023. You can download a useful CSV file of license and service plan names from Microsoft. I use this data in the Microsoft 365 licensing report script (updated to work with the Microsoft Graph PowerShell SDK V2).

By early 2024, we should all have transferred our allegiance to Microsoft Entra ID and consigned the Azure AD name to the wastebasket of computer brands.

More Work for the Book Team

From the perspective of the Office 365 for IT Pros eBook, we have some work to do to update our chapters to replace Azure AD with Entra ID where appropriate. I guess we don’t have to do this immediately, but it’s certainly something that must happen over time. It’s just another item for our to-do list!


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2023/07/13/microsoft-entra-id-azure-ad/feed/ 1 60822
Retrieving Azure AD (Entra ID) Privileged Identity Management Role Assignments https://office365itpros.com/2023/07/12/privileged-identity-management-ps/?utm_source=rss&utm_medium=rss&utm_campaign=privileged-identity-management-ps https://office365itpros.com/2023/07/12/privileged-identity-management-ps/#comments Wed, 12 Jul 2023 01:00:00 +0000 https://office365itpros.com/?p=60809

Taking Account of PIM When Blocking User Access to Exchange Online PowerShell

Updated 15 August 2024

In May, I wrote a Practical365.com article about disabling PowerShell access to Exchange Online for all but administrative accounts. Given the happiness of attackers to use PowerShell to attack Exchange (mostly against Exchange Server, but certainly also Exchange Online), it makes sense to remove the ability of “normal” users to run Exchange cmdlets.

In any case, the example script I use in the article demonstrates how to use the Get-MgDirectoryRoleMember cmdlet to find holders of the Exchange administrator and Global administrator roles. These are the people who need to run PowerShell against Exchange Online, so the script leaves their accounts intact. For anyone else, the script calls the Set-User cmdlet to disable PowerShell access. I suggest that the script is a good candidate for Azure Automation to make sure that new accounts can’t use PowerShell.

Privileged Identity Management

Everything works for most tenants. The problem is that some tenants use Azure AD Privileged Identity Management (PIM), an optional service that requires Azure AD Premium P2 licenses. PIM is most commonly used by large enterprises to control access to resources. Unlike normal open-ended permanent assignments to privileged roles like Exchange administrator, PIM allows the assignments to be time-limited on an on-demand basis.

To do this, PIM differentiates between eligible and active role assignments. An eligible role assignment is not currently effective. If needed, an administrator can activate the assignment to allow its holder to use the permissions available to active role holders. Assignments can be time-limited and expire after a certain period. A comment for the original article pointed out that it didn’t handle PIM assignments and the script is therefore unusable in tenants that use PIM.

If you look at role assignments through the Privileged Identity Management section of the Microsoft Entra admin center, you can see those with eligible, active, and expired assignments for the different roles used in the tenant. Figure 1 shows the active assignments for the Exchange administrator and Global administrator roles. You can see that some service principals are in the set of Exchange administrators. Azure Automation uses these service principals to allow managed identities to sign into Exchange Online and run cmdlets as an administrator.

 PIM assignments for the Exchange administrator and Global administrator roles
Figure 1: PIM assignments for the Exchange administrator and Global administrator roles

The problem is that the Get-MgDirectoryRoleMember cmdlet only reports active role assignments. The assignments eligible for activation are ignored. For the purposes of this exercise, tenants using PIM must include accounts with eligible assignments when determining what accounts can access PowerShell.

Privileged Identity Management APIs

After some searching, I found a script written by Paul Contreras that explains how to get PIM role assignments for Azure AD. The script uses the Get-AzureADMSPrivilegedRoleAssignment cmdlet from the AzureADPreview module to retrieve assignments.

Given that the AzureADPreview module is due for deprecation in March 2024, I looked for an equivalent Microsoft Graph PowerShell SDK cmdlet. Microsoft’s cmdlet map to help developers move from the Azure AD and MSOL modules to the SDK didn’t help. I had great hope for the Get-MgBetaRoleManagementDirectoryRoleAssignment cmdlet but the cmdlet appears to only return “normal” role assignments.

One complication is that the current (beta) Graph API for governance role assignments is due for deprecation. Its documentation points to “Privileged Identity Management iteration 2 APIs.” Obviously, the underlying APIs are in a state of change, so the lack of SDK support isn’t surprising.

Amending the Role Assignment Script for PIM (Updated)

I amended the original script to use the Get-AzureADMSPrivilegedRoleAssignment cmdlet to fetch the assignments known for the Global administrator and Exchange administrator roles. This was fine until the retirement of the AzureAD module. V2.0 of the script replaces the AzureAD cmdlet with the Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule cmdlet from the Microsoft Graph PowerShell SDK (V2.22).

Write-Output "Retrieving assignment information from Privileged Identity Management..."                    
# Get PIM assignments for accounts holding Exchange administrator or Global administrator roles
[array]$ActiveAssignments = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter "(RoleDefinitionId eq '$($ExoAdminRoleId)') or (RoleDefinitionId eq '$($GlobalAdminRoleId)')" -ExpandProperty RoleDefinition, Principal, DirectoryScope -All

# Filter out the Exchange administrators
[array]$ExoRoleMembers = $ActiveAssignments | Where-Object {$_.RoleDefinitionId -eq $ExoAdminRoleId} | Select-Object RoleDefinitionId, Principal, MemberType   
If (!($ExoRoleMembers)) { Write-Output "Can't find any Exchange administrators! Exiting..." ; break }                                                                                                

# Do the same for global administrators
[array]$GARoleMembers = $ActiveAssignments | Where-Object {$_.RoleDefinitionId -eq $GlobalAdminRoleId} | Select-Object RoleDefinitionId, Principal, MemberType
If (!($GARoleMembers)) { Write-Output "Can't find any global administrators! Exiting..." ; break }

The script then loops through the arrays of assignments to fetch details of user account (with Get-MgUser) and members of groups used for PIM (with Get-MgGroupMember). The script stores information about the assignments that we can report (Figure 2).

Reporting PIM role assignments

Privileged Identity Management
Figure 2: Reporting PIM role assignments

The next step is to create an array of administrator user principal names to check against Exchange mailboxes. Basically, if a mailbox belongs to an administrator, we allow PowerShell access. If it doesn’t, we block PowerShell access.

[array]$ExoMailboxes = Get-ExoMailbox -Filter {CustomAttribute5 -eq $Null} -ResultSize Unlimited -RecipientTypeDetails UserMailbox -Properties CustomAttribute5
ForEach ($Mbx in $ExoMailboxes) {
   # If not an admin holder, go ahead and block PowerShell
   If ($Mbx.userPrincipalName -notin $AdminAccounts) {
     Write-Output ("Blocking PowerShell access for mailbox {0}..." -f $Mbx.displayName)
     Try {
         Set-User -Identity $Mbx.userPrincipalName -RemotePowerShellEnabled $False -Confirm:$False
         $MessageText = "PowerShell disabled on " + (Get-Date -format s)
         Set-Mailbox -Identity $Mbx.userPrincipalName -CustomAttribute5 $MessageText
     }
     Catch {
         Write-Output ("Error disabling PowerShell for mailbox {0}" -f $Mbx.userPrincipalNane )
     }
   }
} # End ForEach

An improvement to the original script is that the final step is to check that administrator accounts have PowerShell access. This is to pick up new administrators that receive individual PIM assignments or join a group with a PIM assignment.

Write-Output "Checking administrator mailboxes to make sure that they have PowerShell access..."
ForEach ($Mbx in $AdminAccounts) {
   [string]$mbx = $mbx
   $PSEnabled = (Get-User -Identity $Mbx  -ErrorAction SilentlyContinue).RemotePowerShellEnabled
   If (!($PsEnabled)) {
        Write-Output ("Resetting PowerShell access for admin account {0}" -f $Mbx)
        Set-User -Identity $Mbx -RemotePowerShellEnabled $True -Confirm:$False 
   }
}

The full script is available from GitHub.

Always Learning

The nice thing about working with Microsoft 365 is that there’s always something to learn. Authors learn from the comments posted for our articles. The comments force us to research before we can answer questions posed by readers. That’s a good thing.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/07/12/privileged-identity-management-ps/feed/ 4 60809
How to Report Renewal Dates for Microsoft 365 Subscriptions https://office365itpros.com/2023/07/06/microsoft-365-subscriptions-ps/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-365-subscriptions-ps https://office365itpros.com/2023/07/06/microsoft-365-subscriptions-ps/#comments Thu, 06 Jul 2023 01:00:00 +0000 https://office365itpros.com/?p=60708

New Method to Retrieve Renewal Dates for Microsoft 365 Subscriptions

As part of my campaign to help people move off the old MSOL and AzureAD PowerShell modules to use the Microsoft Graph PowerShell SDK before Microsoft deprecates the modules, I wrote a script to demonstrate how to use the Graph SDK to create a licensing report for a tenant. One of the replies to the article observed that the output of the Get-MgSubscribedSku cmdlet didn’t provide the same information as the old Get-MsolSubscription cmdlet. Specifically, the SDK cmdlet doesn’t tell you the renewal date for a product (SKU).

Relief is now available, but not yet in an SDK cmdlet. Instead, you can fetch the renewal information using a new beta Graph subscriptions endpoint described in Vasil’s blog. This is different to the SubscribedSku API, which is what I think is the base for the Get-MgSubscribedSku cmdlet.

Practical Example of Displaying Renewal Dates for Microsoft 365 Subscriptions

As an example of how you might use the information, I took the output generated by the Get-MgSubscribedSku cmdlet and reformatted it so that it looks like the output from the Get-MsolSubscription cmdlet. The cmdlet lists the SKU part number, active units (available units), warning units (licenses that have expired or have another problem), and consumed units (licenses assigned to user accounts). I wanted to add the renewal date and number of days until the renewal date.

To fetch the renewal dates, I then use the Invoke-MgGraphRequest cmdlet to query the https://graph.microsoft.com/V1.0/directory/subscriptions endpoint. If a SKU has a renewal date, it is in the nextLifecycleDateTime property. Some SKUs that don’t expire (like Power BI standard) don’t have renewal dates. Here’s an example of the information for a Viva Topics subscription that has a renewal date.

Name                           Value
----                           -----
skuId                          4016f256-b063-4864-816e-d818aad600c9
skuPartNumber                  TOPIC_EXPERIENCES
createdDateTime                05/02/2021 18:09:21
totalLicenses                  25
id                             de6eac24-b4b7-4f7e-abeb-9e4f10b36883
serviceStatus                  {System.Collections.Hashtable, System.Collections.Hashtable, System.Collections.Hasht...
ocpSubscriptionId              eeda0292-642e-4901-9825-aa7dfc9b0efc
isTrial                        True
status                         Warning
nextLifecycleDateTime          30/07/2023 14:53:22

To make it easy to lookup the renewal data for a SKU, I created a hash table to store SKU identifiers and renewal dates. The final step is to loop through the SKU information and add the renewal date. Here’s the code:

Connect-MgGraph -Scopes Directory.Read.All -NoWelcome
# Get the basic information about tenant subscriptions
[array]$Skus = Get-MgSubscribedSku
$SkuReport = [System.Collections.Generic.List[Object]]::new()
ForEach ($Sku in $Skus) {
 $DataLine = [PSCustomObject][Ordered]@{
   SkuPartNumber = $Sku.SkuPartNumber
   SkuId         = $Sku.SkuId
   ActiveUnits   = $Sku.PrepaidUnits.Enabled
   WarningUnits  = $Sku.PrepaidUnits.Warning
   ConsumedUnits = $Sku.ConsumedUnits }
 $SkuReport.Add($Dataline)
}

# Get the renewal data
$Uri = "https://graph.microsoft.com/V1.0/directory/subscriptions"
[array]$SkuData = Invoke-MgGraphRequest -Uri $Uri -Method Get
# Put the renewal information into a hash table
$SkuHash = @{}
ForEach ($Sku in $SkuData.Value) { $SkuHash.Add($Sku.SkuId,$Sku.nextLifecycleDateTime) }

# Update the report with the renewal information
ForEach ($R in $SkuReport) {
  $DaysToRenew = $Null
  $SkuRenewalDate = $SkuHash[$R.SkuId]
  $R | Add-Member -NotePropertyName "Renewal date" -NotePropertyValue $SkuRenewalDate -Force 
  If ($SkuRenewalDate) {
   $DaysToRenew = -(New-TimeSpan $SkuRenewalDate).Days
   $R | Add-Member -NotePropertyName "Days to renewal" -NotePropertyValue $DaysToRenew -Force 
 }
}

$SkuReport | Format-Table SkuPartNumber, ActiveUnits, WarningUnits, ConsumedUnits, "Renewal date", "Days to renewal" -AutoSize

Figure 1 shows the output.

Reporting Microsoft 365 subscriptions with renewal dates.
Figure 1: Reporting Microsoft 365 subscriptions with renewal dates

Future SDK Cmdlet Will Probably Come

Obviously, it would be much better if an SDK cmdlet exposed renewal dates for Microsoft 365 subscriptions. Given that the subscriptions endpoint is new, it’s likely that a new SDK will appear after Microsoft’s AutoRest process runs to process the metadata for the endpoint. I’d expect this to happen sometime in the next few weeks.

In the interim, if access to subscription renewal dates is holding up the migration of some old MSOL or AzureAD scripts, a solution is available.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/07/06/microsoft-365-subscriptions-ps/feed/ 2 60708
Reporting User-Preferred MFA Methods for Entra ID User Accounts https://office365itpros.com/2023/06/21/report-user-authentication-methods/?utm_source=rss&utm_medium=rss&utm_campaign=report-user-authentication-methods https://office365itpros.com/2023/06/21/report-user-authentication-methods/#comments Wed, 21 Jun 2023 01:00:00 +0000 https://office365itpros.com/?p=60513

New Graph API Reveals MFA Preferred Authentication Method for User Accounts

Graph authentication methods

In his copious spare time when he’s not reviewing chapters of the Office 365 for IT Pros eBook in his technical editor role, Vasil Michev writes for his blog. A recent post covers the Graph API to configure multi-factor authentication methods for Azure AD user accounts. This API is helpful because it fills in a gap in Graph coverage.

We’ve been able to report authentication methods set on accounts for quite a while, but setting methods has been problematic, especially with the upcoming deprecation of the Microsoft Services Online module (MSOL). Until now, the MSOL cmdlets to deal with “strong authentication methods” are what people have had to use in automation scenarios. Go to Vasil’s blog to learn about how to fetch and set the preferred MFA authentication method for Azure AD accounts (the signInPreferences object for accounts), or read up on the documentation.

Vasil makes the point that the new APIs have not yet appeared in the form of cmdlets in the Microsoft Graph PowerShell SDK. This is because a process needs to run (called AutoRest) to generate the SDK cmdlets from Graph APIs. Microsoft runs the process regularly, but some delay is always expected.

Invoke Graph Requests

The workaround is to use the Invoke-MgGraphRequest cmdlet. Here’s an example of using the cmdlet to fetch details of all Azure AD user accounts that have at least one assigned license (to filter out accounts used for room mailboxes, etc.) The filter used with the Get-MgUser cmdlet is a good example of using a lambda operator with what Microsoft calls a complex Azure AD query (the check assigned licenses). Because it’s a complex query, we need to use the ConsistencyLevel parameter and pass eventual as its value. If you haven’t seen this kind of filter used to find accounts before, store it away because it’ll be one that you use time and time again in your scripts.

After fetching the set of users, it’s a matter of running the query to return the authentication sign in preferences for each account and storing the details in a PowerShell list object. Here’s the code:

Connect-MgGraph -Scopes UserAuthenticationMethod.ReadWrite.All
[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All

$Report = [System.Collections.Generic.List[Object]]::new() 
ForEach ($User in $Users) {
 $Uri = ("https://graph.microsoft.com/beta/users/{0}/authentication/signInPreferences" -f $User.Id)
 $AuthData = Invoke-MgGraphRequest -Uri $Uri -Method Get

 $ReportLine = [PSCustomObject]@{
    User   = $User.displayName
    UPN    = $User.userPrincipalName
    'System preferred MFA enabled' = $AuthData.isSystemPreferredAuthenticationMethodEnabled
    'System preferred MFA method'  = $AuthData.systemPreferredAuthenticationMethod
    'Secondary auth method'        = $AuthData.userPreferredMethodForSecondaryAuthentication }
  $Report.Add($ReportLine)

}

System Preferred Authentication Policy

An important factor to take into account is the existence of the Entra ID system-preferred authentication policy, which is now generally available. When this policy is active (as it soon will be for all tenants), Azure AD uses the strongest authentication method available to an account. A note in the documentation for updating authentication methods says that “this value is ignored except for a few scenarios where a user is authenticating via NPS extension or ADFS adapter.” That’s something to consider when updating user accounts.

Progress, Not Perfect

I don’t think anyone would say that things are perfect in terms of the transition from the old MSOL and Azure AD PowerShell modules to the Graph (APIs or SDK cmdlets). Migrations are never perfect, and we’ll be coping with the effects of this changeover for many months to come. That being said, it’s nice to see progress, albeit in small steps.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2023/06/21/report-user-authentication-methods/feed/ 2 60513
Azure AD Access Token Lifetimes and Long-running PowerShell Scripts https://office365itpros.com/2023/05/29/azure-ad-access-token-lifetime/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-access-token-lifetime https://office365itpros.com/2023/05/29/azure-ad-access-token-lifetime/#respond Mon, 29 May 2023 01:00:00 +0000 https://office365itpros.com/?p=60194

Sometimes Scripts Need Extended Azure AD Access Token Lifetimes

A recent issue where Microsoft limited the page size for the Graph List Users API when retrieving sign-in activity sparked a request from a reader who had problems with a script. They reported that roughly an hour into the script, it failed with a 401 Unauthorized error. The reason is that the access token granted to the app to allow it to run Graph requests to fetch data expired, meaning that the next time the app tried to request data, the Graph refused.

The default Azure AD access token lifetime varies between 60 and 90 minutes (75 minutes on average). The variation exists on purpose to avoid cyclical spikes in demand. Exceptions to the rule do exist. For example, applications like SharePoint Online and OWA that support continuous access evaluation (CAE) can use tokens that last up to 28 hours. These apps support a feature known as claim challenge that is unlikely to be found in apps that execute Graph requests through PowerShell.

Apps can retrieve access tokens from Azure AD using different OAuth 2.0 authentication flows, including password, device code, and authorization code. Azure AD registered apps usually use the client credentials authentication flow. The app authenticates using its own credentials instead of trying to impersonate a user. Valid app credentials include a secret known to the app, a certificate, or a certificate thumbprint.

The client credentials authentication flow does not include the issuance of a refresh token. The lack of a refresh token, which allows apps to silently renew access tokens, means that if you want to keep a script running, you must either:

  • Configure the tenant with a longer access token lifetime.
  • Include code in the script to fetch a new access token before the current one expires.

Configurable Azure AD Access Token Lifetimes

Azure AD supports configurable token lifetimes. This is a preview feature that can set a longer lifetime for an access token. However, the current implementation supports setting token lifetimes for all apps in an organization or for multi-tenant applications. For instance, this code creates a new token lifetime policy that sets a default two-hour token lifetime. Note the organization default setting is True, so this policy applies to all apps in the organization.

$PolicySettings = @{
    "definition"= @("{'TokenLifetimePolicy':{'Version': 1, 'AccessTokenLifetime': '2:00:00'}}")
    "displayName"= "Org-wide 2 Hr AccessTokenPolicy"
    "IsOrganizationDefault" = $True
} 
 
New-MgPolicyTokenLifetimePolicy -BodyParameter $PolicySettings

To test the policy, use an app to request an access token. Here is some PowerShell code to get an access token using the client credentials authentication flow. In this case, the credential is a client secret stored in the app.

$AppId = “de0d7a5d-982a-49e2-8c52-f4596f32b437”
$TenantId = “a662313f-14fc-43a2-9a7a-d2e27f4f3478”
$AppSecret = “3il8Q~Yx4_DOJZxHAxvp7akxW5TQxXdSzhsGpdme”
$Uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$Body = @{
    client_id     = $AppId
    scope         = "https://graph.microsoft.com/.default"
    client_secret = $AppSecret
    grant_type    = "client_credentials"
}
# Get OAuth 2.0 Token
$TokenRequest = Invoke-WebRequest -Method Post -Uri $Uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
# Unpack Access Token
$Token = ($tokenRequest.Content | ConvertFrom-Json).access_token

Write-Host ("Retrieved new access token at {0}" -f (Get-Date)) -foregroundcolor red

Take the access token stored in the $Token variable and examine its contents. For example, Figure 1 shows how jwt.io displays the settings in an access token. To verify that the token lifetime works is expected, compare the time of issuance with the expiration time. In this instance, the timespan should be two hours.

Checking the expiration time for an Azure AD access token

Azure AD access token lifetime
Figure 1: Checking the expiration time for an Azure AD access token

Although creating a token lifetime policy with a new default lifetime for the organization works, increasing token lifetime in this manner is not something to do on a whim. It would be better to be able to assign a token lifetime policy only to the apps that need to use extended token lifetimes.

An organization can support multiple token lifetime policies. It would be nice to be able to apply suitable policies to apps as needed but this doesn’t seem to be possible currently. The Microsoft PowerShell Graph SDK includes the New-MgApplicationTokenLifetimePolicyByRef cmdlet, and you can use the cmdlet assign a token lifetime policy to an application. Alas, this has no effect on the access tokens issued by Azure AD to the app. I’ve been discussing this point with Microsoft and investigations continue.

Tracking Azure AD Access Token Lifetime in Scripts

The alternative is to incorporate code into scripts to track the lifetime of an access token so that the script can retrieve a new token before the old one expires. The script for the Microsoft 365 Groups and Teams Activity Report uses this technique. A function checks if the current time is greater than the calculated token expiration time. If it is, the script requests a new token:

Function Check-AccessToken {
# Function to check if the access token needs to be refreshed. If it does, request a new token
# This often needs to happen when the script processes more than a few thousands groups
$TimeNow = (Get-Date)
if($TimeNow -ge $TokenExpiredDate) {
  $Global:Token = GetAccessToken
  $Global:TokenExpiredDate = (Get-Date).AddMinutes($TimeToRefreshToken) 
#  Write-Host "Requested new access token - expiration at" $TokenExpiredDate 
}
Return $Token
}

The function can then be called whenever necessary within the script.

$Global:Token = Check-AccessToken

This is a relatively unsophisticated mechanism, but it allows the script to process tens of thousands of groups. Variations on the theme can handle other situations.

Only for Special Scripts

The default lifetime for an access token is sufficient for most scripts. Even scripts that run dozens of Graph requests can usually complete processing in a few minutes. It is scripts that must retrieve tens of thousands of items (or even hundreds of thousands of items) that usually deal with inadequate Azure AD access token lifetimes. In those cases, you’ll be glad that methods exist to avoid the dreaded 401 Unauthorized error.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/05/29/azure-ad-access-token-lifetime/feed/ 0 60194
Microsoft Graph Early Adopter Badges and Other Stuff https://office365itpros.com/2023/05/26/microsoft-graph-early-adopter/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-graph-early-adopter https://office365itpros.com/2023/05/26/microsoft-graph-early-adopter/#comments Fri, 26 May 2023 01:00:00 +0000 https://office365itpros.com/?p=60213

Giving Microsoft Feedback, Azure AD Cmdlet Throttling, and Microsoft Graph Early Adopter Badges

I’m the proud possessor of a badge awarded through the Microsoft Graph Early Adopter Recognition program, something that I never knew about nor realized that badges were on offer. Notification about the badge arrived in a surprise email. Apparently, the badge (Figure 1) recognizes people who provide Microsoft with valuable (meaningful) feedback about Microsoft Graph tools and SDKs. According to the program blurb, you should submit feedback by creating an issue in the GitHub repository of a Microsoft Graph product to allow the program managers to know about the issue and recognize the feedback.

The Microsoft Graph Early Adopter badge
Figure 1: The Microsoft Graph Early Adopter badge

Feedback About the Microsoft Graph PowerShell SDK

As far as I know, the only time I left feedback like this was to note some concerns about the direction Microsoft was heading for V2.0 of the Microsoft Graph PowerShell SDK. Microsoft has still not addressed some of the concerns, especially around the proposal to have sets of differently-named cmdlets for the V1.0 and beta endpoints.

If Microsoft’s proposal proceeds, anyone who’s upgrading PowerShell code to replace cmdlets from the soon-to-retire Azure AD and Microsoft Online Services modules with Microsoft Graph PowerShell SDK will have to revisit their code anywhere they use the beta endpoint. For example, the Get-MgUser cmdlet doesn’t return license details for an account via the V1.0 endpoint but it does via the beta endpoint. In any case, spirited discussions continue about that point.

Azure AD and MSOL Cmdlet Throttling

Speaking of the PowerShell retirements, I’ve noticed many examples where people report problems with throttling of their scripts. Figure 2 shows an example reported in the Facebook Office 365 Technical Discussions group where the New-MsolUser cmdlet halted after 20 transactions because it “exceeded the maximum number of allowable transactions.” The advice to “try again later” is because this is a temporary throttle imposed by Microsoft to advise people that they need to move off the deprecated modules.

Figure 2: The woes of throttling hit the New-MsolUser cmdlet
Figure 2: The woes of throttling hit the New-MsolUser cmdlet

It would be nice if Microsoft issued a more explicit and understandable error message. Something along the lines of “this cmdlet will stop working on 30 June 2023. Time to update your code! For now, we’re just throttling, but we will get serious soon…” It’s obvious that the message about the module retirements has not landed in some places, even though Microsoft has been banging the drum for about two years.

Note that cmdlet throttling only happens for cmdlets that interact with license management. The other Azure AD and MSOL cmdlets will continue working after the retirement date, but assigning and updating licenses to Azure AD accounts through PowerShell should now use Graph API requests or Graph SDK cmdlets.

Getting Back to Badges

Going back to the original topic, I don’t quite know how to feel about badges awarded for giving feedback. People like recognition, which is why Teams has the Praise app and Viva Insights includes a version of that app. The joy went out of those apps when Microsoft removed support for the creation and use of custom badges.

I never put myself in the category of those motivated by badges or awards, so I am ambivalent about the Microsoft Graph Early Adopter badge. I understand why the Microsoft team has gone down the path of creating a digital badge to recognize external contributions, but it doesn’t move my needle. But if it floats your boat, enjoy the opportunity to share the recognition with your nearest and dearest.

On the point of feedback, maybe the best way to let Microsoft know exactly what you think about their products, at least in the Microsoft 365 space, is to use the feedback portal. Spend a little time thinking about the message you want to send. Write it down in Word or another text editor. Leave it for an hour or so and then check the text again. And finally, copy your feedback into the appropriate space. You know it makes sense.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365

]]>
https://office365itpros.com/2023/05/26/microsoft-graph-early-adopter/feed/ 1 60213
Protected Actions for Azure AD Conditional Access Policies https://office365itpros.com/2023/05/11/protected-actions-ca/?utm_source=rss&utm_medium=rss&utm_campaign=protected-actions-ca https://office365itpros.com/2023/05/11/protected-actions-ca/#comments Thu, 11 May 2023 01:00:00 +0000 https://office365itpros.com/?p=60059

Protected Actions are a New Method to Highlight Specific Administrative Actions

Over the last year or so, Microsoft has pumped out a set of enhancements to make Azure AD conditional access policies more flexible and powerful. Changes such as token protection (to help address the threat of token theft) and authentication strength (to insist on a specific form of multi-factor authentication for a connection) are good examples of what’s going on.

The latest preview defines a set of “Protected actions” for use with conditional access. The preview associates an authentication context (previously used to mark sensitive SharePoint Online sites) with administrator actions in a conditional access policy. When active, the policy insists that administrators who wish to perform actions specified in the policy must meet specific requirements. For example, instead of satisfying a multi-factor authentication challenge with the Microsoft authenticator app, the policy might force administrator to use a FIDO2 key before Azure AD allows them to perform an action.

Limited Set of Protected Actions for Preview

For now, the preview supports seven protected actions. Three are related to named locations; four cover management of conditional access policies. The set is enough to let people understand the concept of what Microsoft is trying to do and I expect Microsoft to add more protected actions over time.

Using Protected Actions

To start, go to the Conditional Access section of the Microsoft Entra admin center and define an authentication context. The easiest way to think about an authentication context is to regard it as a tag to mark something to protect with a conditional access policy. In this case, the tag links some protected actions with a policy. When Azure AD assesses connections, it knows that anytime accounts within the scope of the policy try to perform a protected action, their connection must meet the conditions set in the policy. A tenant can define up to 25 authentication contexts to use as they wish. To test protected actions, I created an authentication context called CAPolicy.

Next, create a conditional access policy to use the new authentication context. Figure 1 shows what I used. The policy covers some selected users and specifies the newly-created authentication context. The access control requires passwordless MFA.

Conditional access policy to use protected actions
Figure 1: Conditional access policy to use protected actions

The next step is to add protected actions to the authentication context. Open the Roles & Admins section of the Entra admin center and select Protected actions. Select the authentication context and then add protected actions (referred to as permissions in the GUI). You only need to add a single action to make the conditional access policy effective. I chose the four actions related to conditional access policies (Figure 2).

Selecting protected actions to link to an authentication context
Figure 2: Selecting protected actions to link to an authentication context

Testing Protected Actions

Now sign in as one of the accounts within the scope of the conditional access policy without using passwordless authentication and try to amend the settings of a conditional access policy (one of the four protected actions selected above). You can amend settings like adding a new authentication context or changing the accounts and groups within the scope of the policy, but you can’t save updates to a conditional access policy through the GUI (Figure 3) or with PowerShell (using the Microsoft Graph PowerShell SDK).

Blocking protected actions
Figure 3: Blocking protected actions

If the account is enabled for multi-factor authentication and can satisfy the challenge requirements set by the policy, Azure AD displays a “click here to reauthenticate” banner to allow the user to go through “step-up authentication” and meet the requirements. In the example shown in Figure 3, the account isn’t MFA-enabled and therefore cannot authenticate in the manner set by the policy, which is why Azure AD simply disables updates.

For more information, consult the online documentation.

Solid if Limited Concept (for Now)

Protected actions is a preview, with limited capabilities due toa small set of selectable actions. However, there’s enough there to see how valuable this concept might be if Microsoft expands the set of protectable actions to cover more features available through the Microsoft Entra admin center and perhaps even the Azure admin center.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Microsoft 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/05/11/protected-actions-ca/feed/ 1 60059
Find Out Who’s Using Teams Shared Channels in Another Tenant https://office365itpros.com/2023/04/24/teams-shared-channels-profile/?utm_source=rss&utm_medium=rss&utm_campaign=teams-shared-channels-profile https://office365itpros.com/2023/04/24/teams-shared-channels-profile/#respond Mon, 24 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59879

Use Inbound and Outbound Shared User Profiles to Reveal the Ins and Outs of Membership in Teams Shared Channels

In August 2022, I discussed how to use the Get-AssociatedTeam cmdlet to report the membership of channels in teams for users within a tenant. It’s a useful cmdlet that includes the ability to report membership of shared channels in other tenants. In most cases, the reports that can be generated from the data returned by the Get-AssociatedTeam cmdlet meet the needs of administrators to know what channels users access.

Microsoft 365 often offers multiple ways to report data. In this instance, Azure AD supports shared user profile resources created for use with Azure AD B2B Direct Connect, the underlying cross-tenant access mechanism for shared channels.

  • An inbound shared user profile represents an Azure AD user from an external Azure AD tenant whose profile data is shared with your tenant. The profile data is used by applications like Teams to display information about the inbound user in shared channels.
  • Conversely, an outbound shared user profile represents Azure AD users from your tenant who share their profile information when they access resources in other Azure AD tenants.

Essentially, when a shared channel owner invites an external user to become a member of the channel and that user confirms their acceptance, Azure AD creates an inbound shared user profile to note this fact. Azure AD creates an outbound shared user profile when a user from your tenant becomes a member of a shared channel hosted by another tenant. For example, Figure 1 shows the membership of a Teams shared channel. The users marked with (External) have inbound shared user profiles.

Membership information for Teams shared channels
Figure 1: Membership information for Teams shared channels

Using PowerShell to Report Shared User Profiles

The Microsoft Graph PowerShell SDK contains cmdlets to fetch information about unbound and outbound user profiles. With consent for the CrossTenantUserProfileSharing.Read.All permission, you can connect to the Graph and run these commands:

Connect-MgGraph -Scopes CrossTenantUserProfileSharing.Read.All
Select-MgProfile beta
Get-MgDirectoryOutboundSharedUserProfile

UserId
------
08dda855-5dc3-4fdc-8458-cbc494a5a774
5b52fba5-349e-4624-88cd-d790883fe4c4
a221d10f-e0cf-4a1d-b6a2-4e844670f118
cad05ccf-a359-4ac7-89e0-1e33bf37579e
eff4cd58-1bb8-4899-94de-795f656b4a18

The output is a list of identifiers for Azure AD user accounts, so it’s not very exciting. IApart from not listing account names, the output doesn’t tell us what outbound tenants are accessed. To get that information, we must run the Get-MgDirectoryOutboundSharedUserProfileTenant cmdlet for each account. The output of that cmdlet is a list of tenant identifiers, which we can resolve to discover the tenant name. Here’s the code:

[array]$Users =  Get-MgDirectoryOutboundSharedUserProfile | Select-Object -ExpandProperty UserId
ForEach ($User in $Users) {
   $UserData = Get-MgUser -UserId $User
   [array]$TenantNames = $Null; $TenantDisplayNames = $Null
   [array]$TenantIds = Get-MgDirectoryOutboundSharedUserProfileTenant -OutboundSharedUserProfileUserId $User | Select-Object -ExpandProperty TenantId
   If ($TenantIds) {
       ForEach ($TenantId in $TenantIds) {
         $Uri = ("https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='{0}')" -f $TenantId.ToString())
         $ExternalTenantData = Invoke-MgGraphRequest -Uri $Uri -Method Get  
         $TenantNames += $ExternalTenantData.DisplayName
       }
       $TenantDisplayNames = $TenantNames -join ", "    
   }
   Write-Host ("User {0} has outbound shared profiles in these tenants {1}" -f $UserData.DisplayName, $TenantDisplayNames)
}

User Sean Landy has outbound shared profiles in these tenants o365maestro
User Ken Bowers has outbound shared profiles in these tenants o365maestro
User Tony Redmond has outbound shared profiles in these tenants o365maestro, Microsoft Community & Event Tenant

Getting Inbound Shared User Profiles

The Get-MgDirectoryinboundSharedUserProfile cmdlet lists information stored about inbound shared user profiles. We can’t read Azure AD to find information about these users because they come from other tenants. This is what the cmdlet returns:

Get-MgDirectoryinboundSharedUserProfile | Format-List

DisplayName          : Alex Wilber
HomeTenantId         : 22e90715-3da6-4a78-9ec6-b3282389492b
UserId               : a6453657-2058-4c15-a38a-b0a94f0ed737
UserPrincipalName    : AlexW@o365maestro.onmicrosoft.com
AdditionalProperties : {}

Once again, we can resolve the tenant identifier to make the information more understandable:

[array]$Guests = Get-MgDirectoryinboundSharedUserProfile
ForEach ($Guest in $Guests) {
    $Uri = ("https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='{0}')" -f $Guest.HomeTenantId.ToString())
    $ExternalTenantData = Invoke-MgGraphRequest -Uri $Uri -Method Get  
    Write-Host ("User {0} comes from tenant {1}" -f $Guest.DisplayName,  $ExternalTenantData.DisplayName)
}

User Christina Smith comes from tenant CM Portal Solutions
User Nicolas Blood comes from tenant NBConsult
User Alex Wilber comes from tenant o365maestro
User Tom Jones comes from tenant o365maestro
User Vlad Bitton comes from tenant vNext Solutions

The interesting thing here is that I didn’t recognize some of the user names and tenants that Azure AD stored inbound shared user profiles for. However, given that the names were all MVPs and my tenant supported many beta versions of Teams shared channels in the past, it’s entirely possible that the profiles originated in a test. Azure AD doesn’t register a date to tell you when it created a profile, so there’s no clue from that source.

Tracking External Access to Teams Shared Channels

My previous article describes how to create a report about the users accessing shared channels in your tenant. The added piece of information covered here is finding the set of Azure AD accounts from your tenant who use Azure AD B2B Connect to access resources in other tenants. That’s a valuable nugget if you want to track who’s interacting with Teams shared channels externally.

]]>
https://office365itpros.com/2023/04/24/teams-shared-channels-profile/feed/ 0 59879
Reducing the Likelihood of Token Theft with Conditional Access Policies https://office365itpros.com/2023/04/21/token-protection-azure-ad-ca/?utm_source=rss&utm_medium=rss&utm_campaign=token-protection-azure-ad-ca https://office365itpros.com/2023/04/21/token-protection-azure-ad-ca/#comments Fri, 21 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59891

New Token Protection Conditional Access Policy Session Control

Now that the removal of basic authentication from Exchange Online has made password spray attacks far less likely to compromise user credentials for an Azure AD account, those who want to sneak into a tenant need another avenue to explore. Microsoft’s Detection and Response Team (DART) reports an increase in adversary-in-the-middle phishing attacks where attempts are made to capture user credentials and the tokens used by applications to access protected resources like user mailboxes or SharePoint Online sites.

If you need further evidence of the techniques used to compromise and exploit tokens, this article by Edwin David is a good read. It’s a reminder that although all Azure AD accounts should be protected by multi-factor authentication, MFA is not a silver bullet and attackers will continue to develop methods to work around barriers erected by tenants.

Token Binding to Devices

Which brings me to a new session control for Azure AD conditional access policies designed to protect sign-in tokens (refresh tokens) using token protection. The control, which has just appeared in preview, creates a “cryptographically secure tie” between the token and the device Azure AD issues the token to (aka token binding). Without the client secret (the device), the token is useless to an attacker. The device needs to run Windows 10 or above and be Azure AD joined, hybrid Azure AD joined, or registered in Azure AD. When this is the case, a user’s identity is bound to the device.

Microsoft notes that “Token theft is thought to be a relatively rare event, but the damage from it can be significant.” One interpretation of this statement is that Microsoft knows the bad guys are working on using more token thefts, so they’re investing to get ahead of the curve.

Clients

It’s a preview, so some limitations are inevitable. For instance, conditional access policies with token protection can only process connections from tenant accounts and can’t handle inbound connections from guest accounts. Token protection supports Microsoft 365 apps for enterprise subscription versions of desktop clients accessing Exchange Online and SharePoint Online. Perpetual versions of the Office apps aren’t supported. The apps include the OneDrive sync client (22.217 or later) and the Teams desktop client (1.6.00.1331 or later). These are relatively old versions already, so meeting the software requirements should not be a big issue.

PowerShell clients accessing Exchange Online, SharePoint Online, or these endpoints via the Microsoft Graph APIs are unsupported by conditional access policies with token protection, meaning that users are blocked from accessing Exchange and SharePoint. The same is true for some other apps like Visual Studio and the Power BI desktop app. It also applies to connections generated using OWA and Outlook mobile.

In effect, the users selected to test a token protection condition access policy (Figure 1) should be those who don’t need to use any of the unsupported clients and are happy to limit their access to Outlook desktop and Teams.

Parts of a conditional access policy with token protection
Figure 1: Parts of a conditional access policy with token protection

Users who don’t meet the policy requirements (like attempting to sign in with OWA, the browser version of Teams, or the SharePoint Online or OneDrive for Business browser clients) will fail to connect (Figure 2).

Token protection stops an app connecting
Figure 2: Token protection stops an app connecting

In fact, any Office browser app that connects to Exchange or SharePoint resources will be inaccessible. For instance, Viva Engage (Yammer) will start up before immediately exiting when the client attempts to access SharePoint Online.

A Pointer to the Future

Given the relative lack of support by Microsoft 365 apps for token protection, this preview feature is unlikely to get the same range of testing as other recent extensions to conditional access policies (like authentication strength). That being said, if token theft becomes as biga  problem as some security commentators think it might, it will be good to have methods like token protection ready to repel the threat.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/04/21/token-protection-azure-ad-ca/feed/ 1 59891
The Right Way to Revoke Access from Entra ID User Accounts with PowerShell https://office365itpros.com/2023/04/18/revoke-access-for-entra-id-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=revoke-access-for-entra-id-accounts https://office365itpros.com/2023/04/18/revoke-access-for-entra-id-accounts/#comments Tue, 18 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59843

Use the Revoke-MgUserSignInSession cmdlet to Revoke Access for Entra ID Accounts

Updated 24 January 2024

Microsoft’s documentation for how to revoke access to an Entra ID user account describes the use of the Revoke-AzureADUserAllRefreshToken cmdlet from the Azure AD PowerShell module. That’s unfortunate because of the upcoming deprecation of that module. If we consult Microsoft’s cmdlet map to find the appropriate replacement cmdlet from the Microsoft Graph PowerShell SDK, it turns out to be Invoke-MgInvalidateUserRefreshToken, which “Invalidates all of the user’s refresh tokens issued to applications (as well as session cookies in a user’s browser), by resetting the refreshTokensValidFromDateTime user property to the current date-time.”

The guidance could not be clearer. Any script using the Revoke-AzureADUserAllRefreshToken should replace it with the Invoke-MgInvalidateUserRefreshToken cmdlet. Except when you discover that the SDK also includes the Revoke-MgUserSignInSession cmdlet. This cmdlet is in beta and its documentation is less than perfect (or totally inadequate), but the salient fact is that it performs the same task. These two commands have the same effect:

$RevokeStatus = Revoke-MgUserSignInSession -UserId $UserId
$InvalidateStatus = Invoke-MgInvalidateUserRefreshToken -UserId $UserId

Up to now, the Office 365 for IT Pros eBook (chapter 5) documented how to use the Invoke-MgInvalidateUserRefreshToken cmdlet to block an Entra ID user account. Finding the alternative cmdlet used in a Microsoft example provoked a query to ask why two cmdlets did the same thing.

Microsoft’s response is that they built Invoke-MgInvalidateUserRefreshToken for a specific purpose. The cmdlet still works and has the significant benefit of being part of the production (V1.0) module. However, Microsoft’s recommendation is to use Revoke-MgUserSignInSession in the future, even if it is in the beta module.

Revoking Access for an Entra ID Account is the Start

Of course, revoking access for an Entra ID user account might just be the first step in the process of securing the account. Revoking access will force the user to reauthenticate, but if you want to stop further access to the account, you must:

Disabling the account and changing the password are both critical events that force Entra ID to signal applications that support continuous access evaluation (CAE) to terminate sessions. Many of the important Microsoft 365 apps like Outlook and SharePoint Online support CAE (see current list).

This PowerShell code does the necessary. The account signed into the Microsoft Graph PowerShell SDK must have the user administrator role to update account details and the Cloud Device Administrator role to update the device. Alternatively, the Global administrator role will do the job:

Connect-MgGraph -Scopes Directory.AccessAsUser.All
$Account = Read-Host "Enter the User Principal Name of the account to block"
$User = (Get-MgUser -UserId $Account -ErrorAction SilentlyContinue)
If (!($User)) { Write-Host ("Can't find an Entra ID user account for {0}" -f $Account); break }
Write-Host ("Revoking access and changing password for account {0}" -f $User.DisplayName)  
# Disable the account
Update-MgUser -UserId $User.Id -AccountEnabled:$False
# Create a password profile with details of a new password
$NewPassword = @{}
$NewPassword["Password"]= "!NewYorkCity2022?"
$NewPassword["ForceChangePasswordNextSignIn"] = $True
Update-MgUser -UserId $User.Id -PasswordProfile $NewPassword
# Revoke signed in sessions and refresh tokens
$RevokeStatus = Revoke-MgUserSignInSession -UserId $User.Id
If ($RevokeStatus.Value -eq $true) {
   Write-Host ("Access revoked for user {0}" -f $User.DisplayName)
}
# Disable registered devices
[array]$UserDevices = Get-MgUserRegisteredDevice -UserId $User.Id
If ($UserDevices) {
ForEach ($Device in $UserDevices) {
    Update-MgDevice -DeviceId $Device.Id -AccountEnabled:$False}
}

Figure 1 shows that after running the script, the user account is disabled and the SignInSessionsValidFromDateTime property (referred to as refreshTokensValidFromDateTime above) is set to the time when the Revoke-MgUserSignInSession cmdlet ran.

Running PowerShell to revoke access for an Entra ID account.
Figure 1: Running PowerShell to revoke access for an Entra ID user account

Consequences of Disabling an Entra ID User Account

In a scenario like a departing employee, losing access to some teams might not be important. If it is, or in situations where it’s necessary to preserve the account in full working order, an alternative to disabling an account is to change its password and revoke access. The account remains active but is inaccessible unless those attempting to sign-in know the new password.

Example of Knowledge Gap

In July 2022, I wrote about the opening of a knowledge gap as tenants transitioned from the depreciated Azure AD and Microsoft Online Services (MSOL) modules. Having two cmdlets that revoke user access to pick from is one too many. It doesn’t help people migrate scripts to use the Microsoft Graph PowerShell SDK. But at least the recommendation is clear: use Revoke-MgUserSignInSession.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/04/18/revoke-access-for-entra-id-accounts/feed/ 7 59843
Generate a HTML Report of Managers and Direct Reports with the Graph SDK https://office365itpros.com/2023/04/06/entra-id-manager-direct-reports/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-manager-direct-reports https://office365itpros.com/2023/04/06/entra-id-manager-direct-reports/#comments Thu, 06 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59707

Creating a Report From Entra ID Manager and Direct Reports Data with PowerShell

It’s always good to be able to build on the knowledge contributed by someone else. This brings me to a post by Vasil Michev, the esteemed technical editor for the Office 365 for IT Pros eBook. The post covers how to Create an All Managers group in Microsoft 365 and covers how to do this in different ways for different types of group. It brought back some memories of Microsoft’s initiative in April 2017 to auto-generate a Microsoft 365 group for every manager with its membership populated with the manager’s direct report.

Retrieving Entra ID Managers and Direct Reports

In any case, Vasil discussed how the Get-Recipient (but not Get­ExoRecipient) and Get-User cmdlets have a filter to find accounts that have direct reports using the backlink from users to their managers. By definition, these accounts are managers, so you can use the commands as the basis to control the membership of distribution lists, dynamic distribution lists, or Microsoft 365 groups.

Get-Recipient -Filter {DirectReports -ne $Null}
Get-User -Filter {DirectReports -ne $Null}

The only problem is that the output of the two cmdlets is imperfect. The cmdlets find accounts with direct reports, but their results include some accounts that don’t have any direct reports. In my tenant, I found that the cmdlets found three accounts with no direct reports. I believe that these accounts had direct reports at some point in the past, but they don’t now. For instance, when I queried the accounts to see the set of direct reports reported by Get-User, I see a blank:

Get-User -Identity Ben.Owens | Select-Object Name, Manager, DirectReports

Name      Manager      DirectReports
----      -------      -------------
Ben Owens tony.redmond {}

The same is true when viewing details of the account through Exchange address lists, the organization chart in Teams, or the Outlook Org Explorer (Figure 1).

Outlook Org Explorer lists no direct reports for a manager
Figure 1: Outlook Org Explorer lists no direct reports for a manager

According to message center notification MC492902 (updated 7 February 2023), the Outlook Org Explorer is only available to users with the “Microsoft Viva Suite” or “Microsoft Viva Suite with Glint” licenses, which is why you might not be seeing it. Originally, Microsoft said that the Org Explorer would be available to accounts with Microsoft 365 E3/E5 or Microsoft 365 Business licenses, but they decided to align this feature with the Viva initiative. The Org Explorer is not available for OWA.

My conclusion is that synchronization betweenEntra ID and Exchange Online leaves some vestige behind in the DirectReports property following the removal of the last direct report for a manager. It’s enough to stop the filter working accurately.

Reporting Entra ID Managers and Direct Reports

Which brings me back to considering how to report the links between managers and employees using the information stored in Entra ID. I covered this ground in an article two years ago, but I didn’t realize the flaw in Get-User at the time, so the script I wrote (available from GitHub) can produce incorrect results. A different approach is needed.

Given that Entra ID is the source of the information, it makes sense to use Graph APIs to retrieve data. I chose to use the Microsoft Graph PowerShell SDK to avoid the necessity to create a registered app.

The new script (also available from GitHub) does the following:

  • Finds user accounts with at least one assigned license. This step filters out accounts created for purposes like room and shared mailboxes.
  • Use the Get-MgUserManager cmdlet to check each account to see if it has a manager. If not, note this fact.
  • Use the Get-MgUserDirectReport cmdlet to see if the account has direct reports. If it does, record the details of the manager’s reports.
  • Create an HTML report detailing each manager and their reports.
  • At the end of the report, add a section detailing accounts without managers.
  • Output the HTML file and a CSV file containing details of managers and reports.

Figure 2 shows some example output. Because the code is PowerShell, it’s easy to tweak it to include other information about each employee.

Reporting managers and their direct reports

Azure AD Managers
Figure 2: Reporting managers and their direct reports

Go to the Source to Find Managers and Direct Reports

It’s never nice to discover that a technique you thought worked well is no longer fit for purpose and it’s necessary to rework a script. The Get-User and Get-Recipient cmdlets return accurate information about managers and direct reports, but only if managers always have at least one report. I guess that’s possible, but it’s better to make sure by using Graph APIs to retrieve data about managers and their direct reports. At least then you’ll know that your reports show the same reporting relationships that surface elsewhere in Microsoft 365.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/04/06/entra-id-manager-direct-reports/feed/ 6 59707
Microsoft Limits Graph API Requests for User Account Data https://office365itpros.com/2023/04/05/signinactivity-limit-graph-api/?utm_source=rss&utm_medium=rss&utm_campaign=signinactivity-limit-graph-api https://office365itpros.com/2023/04/05/signinactivity-limit-graph-api/#respond Wed, 05 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59723

Old Limit with SignInActivity was 999 – New Limit for Azure AD Accounts is 120

Because it retrieves details of Azure AD accounts, the List Users API is one of the most heavily used of the Microsoft Graph APIs. It also underpins the Get-MgUser cmdlet from the Microsoft Graph PowerShell SDK. Microsoft generates the cmdlet from the API using a process called AutoRest, which means that changes made to the API show up soon afterward in the cmdlet.

I’ve documented some of the issues that developers must deal with when coding with the cmdlets from the Microsoft Graph PowerShell SDK. The cmdlets have been stable recently, which is a relief because tenants are migrating scripts from the Azure AD and MSOL modules. However, last week an issue erupted in a GitHub discussion that caused a lot of disruption.

In a nutshell, if you use List Users to fetch Azure AD accounts and include the SignInActivity property, the API limits the page size for results to 120 items. Calls made without specifying SignInActivity can set the page size to be anything up to 999 items.

An Unannounced Change

To help manage demand on the service, all Graph API requests limit the number of items that they return. To retrieve all matching items for a request, developers must fetch pages of results until nothing remains. When a developer knows that large numbers of items must be fetched, they often increase the page size to reduce the number of requests.

Microsoft didn’t say anything about the new restriction on requests that fetch Azure AD account data with sign-in activity. Developers only discovered the problem when programs and scripts failed. I first learned of the issue when some of the users of the Office 365 for IT Pros GitHub repository reported that a Graph request which included a $top query parameter to increase the page size to 999 items failed. For example:

$uri = "https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,mail,id,CreatedDateTime,signInActivity,UserType&`$top=999"
[array]$Data = Invoke-RestMethod -Method GET -Uri $Uri -ContentType "application/json" -Headers $Headers
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:1 char:16
+ ... ray]$Data = Invoke-RestMethod -Method GET -Uri $Uri -ContentType "app ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest)
   [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.I

As shown in Figure 2, testing with the Get-MgUser cmdlet revealed some more information in the error (“Cannot query data for more than 120 users at a time”). This was the first time I learned about a query limit:

Get-MgUser reports more useful error information

Cannot query data for more than 120 users at a time (SignInActivity)
Figure 2: Get-MgUser reports more useful error information

According to a response reported in the GitHub discussion, Microsoft support reported

The PG have confirmed that this endpoint will be transitioning from beta to General Availability (GA).

As part of this transition, changes to its behavior has been made, this includes not requesting more than 120 results per call. They recommend requesting less than 120 results per call, which can be done by setting the top parameter to, say 100.”

It’s likely that Microsoft made the change because retrieving sign-in activity data for Azure AD accounts is an expensive operation. Reducing the page size to 120 possibly makes it easier to process a request than if it asked for 999 items.

Beta Version of List Users Moving to Production

When the product group (PG) says that the endpoint is transitioning from beta to GA, it means that instead of needing to use https://graph.microsoft.com/beta/users to access sign-in activity, the data will be available through https://graph.microsoft.com/V1.0/users. If you use the Microsoft Graph PowerShell SDK, you won’t have to run the Select-MgProfile cmdlet to choose the beta endpoint. Moving the beta version of the API to the production endpoint is a good thing because there are many other account properties now only available through the beta endpoint (like license assignments).

If you use the Microsoft Graph PowerShell SDK, the Get-MgUser cmdlet is unaffected by the change if you specify the All parameter. This is because the cmdlet handles pagination internally and fetches all pages automatically without the need to specify a page size. For instance, this works:

$AccountProperties = @( ‘Id’, ‘DisplayName’, ‘SignInActivity’)
[array]$Users = Get-MgUser -All -Property $AccountProperties | Select-Object $AccountProperties

Moving to Production

Although it’s good that Microsoft is (slowly) moving the beta versions of the List Users API towards production, it’s a pity that they introduced a change that broke so many scripts and programs without any warning. At worse, this so exhibits a certain contempt for the developer community. At best, it’s a bad sign when communication with the developer community is not a priority. That’s just sad.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/04/05/signinactivity-limit-graph-api/feed/ 0 59723
Time Running Out for AzureAD and MSOL PowerShell Modules https://office365itpros.com/2023/04/04/azuread-powershell-retirement/?utm_source=rss&utm_medium=rss&utm_campaign=azuread-powershell-retirement https://office365itpros.com/2023/04/04/azuread-powershell-retirement/#comments Tue, 04 Apr 2023 01:00:00 +0000 https://office365itpros.com/?p=59646

Last Gasp for AzureAD PowerShell Retirement as Deadline Approaches

Updated 2 April 2024

Microsoft’s original announcement about the deprecation of the AzureAD and Microsoft Online Services (MSOL) PowerShell modules goes back to 26 August, 2021. At that time, Microsoft wanted to have the retirement done by June 30, 2022. Customer pushback duly ensued and Microsoft decided to push the dates out another year to allow customers more time to upgrade their scripts. They subsequently deferred the deprecation for a further nine months to March 30, 2024. The time for the AzureAD PowerShell retirement is now rapidly approaching.

This was the only sensible course of action. The Graph APIs for dealing with many Entra ID user account interactions, especially license assignments, were sadly undocumented. The suggestion of using cmdlets from the Microsoft Graph PowerShell SDK ran into difficulties because some of the cmdlets didn’t work as expected. Allied to that, the documentation for the SDK cmdlets remains poor and inscrutable at times. These issues have largely been addressed.

Microsoft Graph PowerShell SDK Improved Over Time

Time is a great healer and allows for improvements to be made. The Graph Explorer works better and the Graph X-Ray tool reveals details about how Microsoft uses Graph calls in places like the Microsoft Entra admin center.

In addition, Microsoft developed documentation to help people migrate scripts, including a cmdlet map to translate old cmdlets to new. The important thing to realize here is that automatic translation from one set of cmdlets to the other is difficult. People code in PowerShell in different ways and it’s not always clear how to translate code to a new cmdlet. Some community-based projects do exist (here’s a new one that is spinning up), but any attempt to covert to SDK cmdlets must take the SDK foibles into consideration, like its fundamental disregard for the PowerShell pipeline.

But mostly time allowed people to share their knowledge about how to use SDK cmdlets to automate administrative tasks like user and group management. For instance, here’s a writeup I did about license management for Entra ID user accounts using the SDK, and here’s another covering how to create a license report for Entra ID user accounts.

What Will Happen Between Now and the Final AzureAD PowerShell Retirement

But time eventually runs out and we are now at the point where Microsoft will soon retire the AzureAD and MSOL modules. Here’s my understanding of the situation:

  • The licensing cmdlets from the AzureAD and MSOL modules do not work for tenants created after November 1, 2022. These tenants must use Graph APIs or SDK cmdlets to manage license assignments for Entra ID user accounts.
  • For all tenants, March 30, 2024 is the official deprecation date for the licensing cmdlets in the AzureAD and MSOL modules.
  • Apart from the cmdlets that assign or work with licenses, deprecation doesn’t mean “stop working.” Microsoft blocks the cmdlets that to Entra ID user accounts. This is in line with the warning posted on July 29, 2022, that “Customers may notice performance delays as we approach the retirement deadline,” The affected cmdlets are:
    • Set-MsolUserLicenseSet-AzureADUserLicense
    • New-MsolUser (where the creation of an account includes a license assignment)
The Set-AzureADUserLicense cmdlet stopped  working on June 30, 2023

AzureAD PowerShell retirement
Figure 1: The Set-AzureADUserLicense cmdlet stopped working on June 30, 2023
  • After March 30, 2024, the AzureAD and MSOL modules are deprecated and unsupported apart from security fixes. With the notable exception of the licensing cmdlets, Microsoft says that the modules will continue to function until March 30, 2025. At that point, Microsoft will retire the AzureAD and MSOL modules. Cmdlets from the two modules might still run, but no guarantees exist that they will be successful. In other words, scripts might fail without warning.

The Bottom Line About the AzureAD PowerShell Retirement

The AzureAD and MSOL modules are now on borrowed time. If you haven’t already started to upgrade scripts to use the Graph APIs or the Microsoft Graph PowerShell SDK, scripts that use these modules could encounter an unpleasant failure very soon. It’s time to get busy to make sure that all scripts are migrated to run using the SDK cmdlets before March 30, 2024.


The Office 365 for IT Pros eBook includes hundreds of examples of working with Microsoft 365 through PowerShell. We explain how to run Microsoft Graph API queries through PowerShell and how to use the cmdlets from the Microsoft Graph PowerShell SDK in a very practical and approachable manner.

]]>
https://office365itpros.com/2023/04/04/azuread-powershell-retirement/feed/ 18 59646
Azure AD Admin Center Moves to Microsoft Entra Admin Center https://office365itpros.com/2023/03/27/changes-in-microsoft-365/?utm_source=rss&utm_medium=rss&utm_campaign=changes-in-microsoft-365 https://office365itpros.com/2023/03/27/changes-in-microsoft-365/#comments Mon, 27 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59545

Example of Ongoing Changes in Microsoft 365

I guess we all knew it was coming (after all, Microsoft published message center notification MC477013 in December 2022), but the news that the Microsoft Entra admin center (Figure 1) will replace the Azure AD admin center from April 1, 2023 is yet another example of the ongoing and constant changes in Microsoft 365. Those changes range from a massive introduction of fundamental new functionality, like Microsoft 365 Copilot, to a small update to how something appears.

The Microsoft Entra admin center

Changes in Microsoft 365
Figure 1: The Microsoft Entra admin center – one of the many changes in Microsoft 365

In this instance, Microsoft portraits the replacement of the Azure AD admin center as a unification of its identity management platform (Azure AD) with its identity and access solutions. Another way of looking at the move is that it allows Microsoft to bring those identity and access solutions to the attention of some organizations who wouldn’t otherwise consider them. Every time you open the Entra admin center, identity governance and other solutions will be there to discover. To be fair to Microsoft, if you access Azure AD from the Microsoft 365 admin center, the link goes direct to the Azure AD section of the Entra admin center.

Microsoft says that the old Azure AD admin center will continue to function until May 2023. Azure customers who don’t use Microsoft 365 can manage Azure AD through the Azure portal.

Many Rebranding Campaigns

Microsoft is well known for its love of rebranding campaigns. Microsoft 365 has steadily embraced a huge ecosystem, including the subscription version of the Office apps, and we’ll probably have to rename the next version of the Office 365 for IT Pros eBook to use Microsoft 365 instead. Microsoft Purview is another example, albeit one that at least collected together a bunch of different compliance solutions under a common banner. Defender did the same for security solutions, and so on.

Sometimes, Microsoft makes changes for what appears to be no good reason. Take the announcement in MC532194 (March 23) that Teams now uses an “EA” indicator instead of “P” when users run the preview version of the software. I’m still wondering why “Early Access” is any better than “Preview.” The change appears to deliver zero added value except that it aligns with the nomenclature Microsoft uses in places like the Office Insider program. From my perspective, the change meant that we needed to update Chapter 15 in the Office 365 for IT Pros eBook and our article about Teams preview.

Naming Changes Affect the Wider Technical Community

Microsoft makes naming changes for its own reasons. I doubt that they take the wider community into consideration when they decide on these updates but the effect of a naming change or rebrand ripple through documentation and training. For instance, video training companies that have a program telling people how to use the Azure AD admin center must now update their collateral and perhaps even reshoot some or all of their video. That’s a big cost for the production company.

The same is true for books that cover Azure AD or any of the other topics affected by naming or branding changes. Switching references from the Azure AD admin center to the Entra admin center isn’t quite as simple as doing a search and replace. Microsoft often takes the opportunity to rename options in administrative consoles when they change things. Data lifecycle management is now the place in the Purview compliance portal that was once known as the location for the management of retention labels and policies. The justification is that the section of the portal now spans additional options such as adaptive scopes, policy lookup, and legacy Exchange mailbox retention policies and tags (both of which are still very useful).

Changes in Microsoft 365 Will Keep on Happening

I don’t expect Microsoft to poll the technical community before they change the name of anything inside Microsoft 365. It won’t happen and would be unreasonable. Microsoft will continue to make changes how and when they like, even if the outcome displeases some. Their decision to stop accepting inbound email from old and vulnerable on-premises Exchange servers to protect Exchange Online is a good example of a change that inflamed many opinions. However, we don’t get to vote.

Content producers like Office 365 for IT Pros simply need to be proactive and respond to Microsoft changes the best way we can. In that respect, being able to publish a complete new book every month is a major advantage, even if it takes a lot of hard work. Now back to the task of looking for all those references to the Azure AD admin center – a change that we’ll probably make in the May 2023 update.

]]>
https://office365itpros.com/2023/03/27/changes-in-microsoft-365/feed/ 7 59545
Microsoft Expands Multi-Factor Authentication Methods to Companion Apps https://office365itpros.com/2023/03/22/authenticator-lite-outlook/?utm_source=rss&utm_medium=rss&utm_campaign=authenticator-lite-outlook https://office365itpros.com/2023/03/22/authenticator-lite-outlook/#comments Wed, 22 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59524

Introducing Authenticator Lite

Without too much fuss, Microsoft introduced the preview of a new “surface” (way) for users to complete multi-factor authentication (MFA) challenges. The new method is a companion app for the Microsoft Authenticator app and is covered by Microsoft 365 roadmap item 122289 and is slated for roll-out in May 2023.

Azure AD already covers a variety of methods to satisfy MFA challenges. The methods are categorized from weak to strong in terms of their ability to resist attacks and conditional access policies can insist that a connection uses a certain strength of MFA response before it is accepted. “Authenticator lite” is rated as strong as the Authenticator app because it’s basically code taken from Authenticator and built into other Microsoft apps. In addition, Authenticator lite only supports push notifications with number matching and one-time codes, which are less likely to provoke MFA fatigue than the traditional “click here to approve” response.

Outlook Mobile Leads the Way

Outlook mobile (iOS 4.2309.0, Android 4.2308.0, or higher versions) is the first Microsoft 365 app to pick up the Authenticator Lite code. Some might ask why Microsoft choose Outlook as the test case. I think it’s because Outlook is likely the most heavily used mobile client. The last time Microsoft gave a number for Outlook mobile (April 2019), they reported that Outlook for iOS and Android had more than 100 million users. At that time, Office 365 reached 180 million monthly active users. Now Office 365 is up around 400 million monthly active users. Assuming Outlook mobile has kept pace, it has around 220 million monthly active users.

Building MFA responses into the most popular mobile client is a great way of making MFA easier for organizations to deploy. Microsoft wants customers to deploy MFA. They also want customers to use strong MFA responses and move away from methods like SMS text-based responses. The recent introduction of the Azure AD system-preferred authentication policy to force Azure AD to select the strongest available authentication method for a user when it issues a challenge is a pointer to the future. Who needs to resort to an SMS response when you can respond to a number challenge within Outlook? It makes absolute sense.

Update the Azure AD Authentication Methods Policy

If you’re interested in trying Authenticator Lite with Outlook mobile, the steps to make everything happen are covered in a Microsoft article. In summary:

First, use a Graph API PATCH request to update the Azure AD Authentication Methods Policy to update the companionAppAllowedState setting from disabled (the default) to enabled. The easiest way to do this is with the Graph Explorer (make sure to sign in with an administrator account because you’ll need to consent to the Policy.ReadWrite.AuthenticationMethod permission to update the policy. The relevant lines for the policy in my tenant look like those shown in Figure 1. The state is enabled and the policy is targeted at a group of users with an identifier of “all_users.” This is a special identifier that instructs Azure AD to apply the policy setting to all tenant users. If you want to limit the policy to a specific set of users, create a security group with those users as members and update the authentication methods policy with the group identifier.

Checking the settings of the Azure AD Authentication Methods policy

Authenticator Lite
Figure 1: Checking the settings of the Azure AD Authentication Methods policy

The updated policy might take a little time to become effective and people can respond to MFA challenges from Outlook. Only accounts enabled to use the Authenticator app (with the mode set to Push or Any) to respond to MFA challenges can use Authenticator Lite within Outlook, and responses are limited to number matching or one-time codes. It’s important to realize that if the Microsoft Authenticator app is present on a device, Outlook won’t attempt to use Authenticator Lite and instead refers all authentication challenges to the full Authenticator app.

It’s also important to realize that the code incorporated into Outlook supports fewer options than the full Authenticator app. For instance, it doesn’t support Self-Service Password Reset (SSPR). The Authenticator app is a more appropriate option for users who need functionality like handling MFA responses for other cloud services like Twitter and GitHub.

MFA Responses for the Masses

I like any action that reduces the friction of MFA deployment and operation for both organizations and users. Authenticator Lite falls into this category. Although I won’t use the new capability because I need the power of the full Authenticator app, I think that Authenticator Lite will meet the needs of most Microsoft 365 users when it comes to responding to MFA challenges.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/03/22/authenticator-lite-outlook/feed/ 1 59524
SharePoint Online Gets Closer to Azure AD https://office365itpros.com/2023/03/20/azure-ad-b2b-collaboration-spo/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-b2b-collaboration-spo https://office365itpros.com/2023/03/20/azure-ad-b2b-collaboration-spo/#comments Mon, 20 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59428

Azure AD B2B Collaboration and Guest Accounts for SharePoint Sharing

Two recent message center notifications highlight closer integration between SharePoint Online and Azure AD. MC526130 (11 March) says that new tenants created after March 31, 2023 will automatically enable the SharePoint Online integration with Azure B2B integration. Existing tenants aren’t impacted by this change. The associated update, also scheduled for roll-out in late March, is MC525663 (10 March). The news here is that SharePoint Online site sharing will use the Azure B2B Invitation manager instead of the legacy SharePoint Invitation Manager (Microsoft 365 roadmap item 117557).

Rationalization Around Azure AD

The two updates rationalize existing sharing methods with external users and focus on Azure AD as the driving force for managing invitations. The journey toward Azure AD B2B Collaboration started in 2021, so it’s been a while coming. The project makes a lot of sense for both customers and Microsoft (their gain is through reduced engineering expenses).

Ten years ago, it was reasonable for SharePoint to manage site sharing invitations. Today, when the site collection-based architecture is replaced by single-sites and most sharing occurs through Microsoft 365 groups and Teams, it’s illogical for SharePoint Online to have its own mechanism. 280 million monthly active Teams users create a lot of work for SharePoint.

Another factor is that site sharing with external users is a relatively uncommon action today. Most external users join groups or teams and gain access to the group-connected site. Although non-group connected sites do exist, they’re in the minority and some of those sites (like hub and communication sites) aren’t candidates for sharing with external people. And of course, even site owners might be blocked from sharing sites by a sensitivity label.

Time to Review Applicable Policies

Overall, I don’t think the change will disrupt many organizations. As Microsoft notes “You may want to review your Azure B2B Invitation Manager policies.” Two policies are worthy of note. The first is the Azure B2B Collaboration policy, which includes an allow or deny list (but not both) of domains.

The policy is now found under Collaboration restrictions in the External Identities section of the Azure AD admin center (Figure 1). It is commonly used to block sharing with consumer domains (deny list) or to restrict collaboration to a set of known domains belonging to partner organizations (allow list). If the organization already supports guest accounts, it’s likely that the collaboration policy already exists. Even so, changes like this are useful reminders of the need for regular review of any policy that affects how external people access tenant resources.

Azure AD B2B Collaboration policy settings
Figure 1: Azure AD B2B Collaboration policy settings

Azure AD cross-tenant access policies are a more powerful and flexible mechanism to control external access through both Azure B2B collaboration and Azure AD direct connect (used for Teams shared channels). Cross-tenant access policies are still relatively new and don’t need to be implemented unless required for a specific reason, so your tenant might not use them yet.

Although the Azure AD B2B Collaboration policy is likely to dominate for the immediate future, over time, I expect a slow transition to take advantage of the granular control available in cross-tenant access policies. When an organization changes over, SharePoint Online will take advantage. Leveraging advances made in Azure AD is an excellent reason for SharePoint Online to embrace Azure AD more fully.

Review Guest Accounts Too

Azure AD B2B collaboration works but that doesn’t mean that you don’t need to manage guest accounts. As more sharing happens, more guest accounts end up in your Azure AD. Some guest accounts are used once to share a document. Others are in ongoing use as guest members of groups and teams access shared documents. It’s a good idea to keep an eye on guest accounts and remove them as they become obsolete.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/03/20/azure-ad-b2b-collaboration-spo/feed/ 1 59428
Document Entra ID Conditional Access Policies with the IdPowerToys App https://office365itpros.com/2023/03/16/idpowertoys-ca-documentation/?utm_source=rss&utm_medium=rss&utm_campaign=idpowertoys-ca-documentation https://office365itpros.com/2023/03/16/idpowertoys-ca-documentation/#comments Thu, 16 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59457

Manual and Automatic Documentation of Conditional Access Policy Settings as PowerPoint Presentation

Windows has its Power Toys and now Microsoft’s identity management team is getting into the act with Identity Power Toys (idPowerToys), an app to help Azure Active Directory power users get work done. The initial release of the app is limited to a Conditional Access Documentator, a useful tool to read the configuration of conditional access policies fromEntra ID and generate documentation in the form of a PowerPoint presentation (using components from Syncfusion). The IdPowerToys GitHub repository is available for all to browse and contribute to.

Conditional access policies set conditions and criteria for Entra ID to examine inbound connections to decide if a connection should be accepted or rejected. A typical conditional access policy is one that requires accounts to use multi-factor authentication (MFA). The policy could even define that the authentication method used for the MFA response should be a certain strength. For instance, an SMS response is unacceptable but a response from the Microsoft Authenticator app is OK.

Only its creators love the GUI used to manage conditional access policies in the Microsoft Entra (Azure AD) admin center. It’s easy to make mistakes and people have been known to lock themselves out by implementing conditions that they can’t meet. It’s also easy to create conditions that make the daily interaction between people and apps miserable, such as cranking up the sign-in frequency for connections. Many different policies might exist in large enterprise tenants, and it can be hard to understand the flow that a connection traverses as Entra ID applies conditions from the set of policies. Examination of records in the sign-in log throws some light onto the situation but can be a drag.

The Conditional Access Documentator

Enter the Conditional Access Documentator, the first IdPowerToys app. The app is available online and supports two modes:

  • Automatic generation: IdPowerToys retrieves of conditional access policies using an enterprise app created in the tenant’s Entra ID and generates a PowerPoint presentation. You can opt to mask different elements of the output. For instance, if you choose to mask policy names, IdPowerToys generates its own version of the policy name based on what it does. If you choose to mask user names, IdPowerToys outputs their account identifier instead of their display name.
  • Manual generation: A tenant administrator runs a PowerShell command or uses the Graph Explorer to retrieve the JSON-formatted information about conditional access policies and pastes the results into a text box. IdPowerToys uses the information to create the PowerPoint file. Masking isn’t supported for manual generation.

An enterprise app is a registered Entra ID app owned by another tenant that creates an instance of the app in other tenants. Alongside the app instance, Entra ID creates a service principal to hold the permissions needed by the app. An administrator must grant consent before the app can use the permissions to access Entra ID to fetch the information about conditional access policies.

Some will be uneasy about granting an app permissions like Directory.Read.All (read information about accounts, groups, and other objects) and Policy.Read.All (read all policy information for the organization). However, as shown in Figure 1, the permissions are delegated, not application, which means that an account holding an administrator role must sign-into the app to use the permissions.

Permissions assigned to the IdPowerToys app
Figure 1: Permissions assigned to the IdPowerToys app

If you’re uneasy about creating an enterprise app with permissions, use the manual generation method and run the Invoke-GraphRequest cmdlet to fetch the data and output it to the clipboard. This command only works when run by an administrator:

Invoke-GraphRequest -Uri 'https://graph.microsoft.com/beta/policies/conditionalAccessPolicies' -OutputType Json | Set-Clipboard

Figure 2 shows the results retrieved from the Graph pasted into the IdPowerToys app.

Pasting conditional access policy settings into IdPowerToys to generate documentation manually
Figure 2: Pasting conditional access policy settings into IdPowerToys to generate documentation manually

In either case, the PowerPoint presentation generated to document conditional access policies is the same. For my tenant, which has 12 conditional access policies (not all in use), the app generated a 609 KB file with 13 slides (one title slide and one for each policy), divided into sets of enabled and disabled policies. Within a set, policies are sorted by last modified date, so the policy with the most recent modification appears first.

Figure 3 shows a presentation generated by IdPowerToys with details of a conditional access policy in the slide. This is a common policy to require MFA for guest access, with tweaks to require a certain authentication strength and to set the sign-in frequency to 90 days. You can see that the policy is enabled.

Figure 3: PowerPoint depiction of a conditional access policy

Visualize Conditional Access Policies Differently

Conceptually, generating documentation for conditional access policies isn’t difficult. Graph API requests exist to fetch the information and after that it’s a matter of parsing the conditions, actions, access controls, and session controls to output in your desired format. Some might prefer their documentation in Word. I think PowerPoint is just fine. IdPowerToys delivers documentation that just might help organizations visualize, clarify, and rationalize their conditional access policies, and that’s a good thing.


Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.

]]>
https://office365itpros.com/2023/03/16/idpowertoys-ca-documentation/feed/ 19 59457
Pragmatic and Practical Security is Better than Hard-line Security https://office365itpros.com/2023/03/14/azure-ad-sign-in-frequency-guests/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-sign-in-frequency-guests https://office365itpros.com/2023/03/14/azure-ad-sign-in-frequency-guests/#comments Tue, 14 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59388

An Unreasonable Azure AD Sign-in Frequency Creates a Barrier to Productivity

I had an unpleasant surprise this week when the security team for one of the companies where I have a guest account decided to improve tenant security. I strongly support any effort to improve tenant security, especially when the effort means better use of multi-factor authentication. It’s a topic I’ll cover during the TEC Europe 2023 tour in London, Paris, and Frankfurt in April. Registration for those events is now open.

It’s always important to take a pragmatic and practical view of security and not to implement anything that has a significant impact on user productivity. All change can impact users, but most of the time people learn to live with change and it’s not disruptive. Unfortunately, deciding to increase the user sign-in frequency for Azure AD accounts can be extraordinarily disruptive if you go too far.

Azure AD sign-in frequency is the period before a user must sign in again when attempting to access a resource, like opening a SharePoint Online document, creating a message with OWA, or accessing a Teams channel. By default, Azure AD uses a rolling 90-day window for its sign-in frequency. In other words, once you successfully sign-into a tenant, Azure AD won’t ask you to sign-in again for another 90 days.

Revoking User Account Access

Ninety days sounds like a long time, and it is. But this period needs to be viewed through the prism of how Azure AD and Microsoft 365 applications work. For example, in early 2022, Microsoft enabled Continuous Access Evaluation (CAE) for all tenants. CAE is a mechanism that allows Azure AD to notify applications of a critical change in the directory, such as an updated password. Applications that understand CAE, like SharePoint Online, revoke existing access for the account to require the user to reauthenticate.

The Microsoft 365 admin center also includes an option to sign users out of all current sessions (Figure 1) to force them to reauthenticate.

Forcing a user to sign out and reauthenticate
Figure 1: Forcing a user to sign out and reauthenticate

Of course, you might want to do more than sign a user out. In some cases, like employee departures, you might want to block future sign-ins. This is an operation that’s easily scripted with PowerShell. For example, this code:

  • Retrieves the identifier for an Azure AD user account.
  • Disables the account.
  • Sets a new password.
  • Revokes all refresh tokens.

$UserId = (Get-MgUser -UserId Lotte.Vettler@Office365itpros.com).Id
# Disable the account
Update-MgUser-UserId $UserId -AccountEnabled:$False
# Set a new password
$NewPassword = @{}
$NewPassword["Password"]= "!DoneAndDusted?"
$NewPassword["ForceChangePasswordNextSignIn"] = $True
Update-MgUser -UserId $UserId -PasswordProfile $NewPassword -AccountEnabled:$True
# Revoke refresh tokens
$Status = Invoke-MgInvalidateUserRefreshToken -UserId $UserId

It might take a little time for the full block to be effective because tokens must expire, and clients recognize the need for reauthentication, but it will happen.

How Conditional Access Can Make Guest Accounts Miserable

The reason I had a problem was that the security team updated the conditional access policies for guest users to enforce a 60-minute sign-in frequency (Figure 2). This change had a horrible effect. Guests switching to the tenant with Teams inevitably resulted in an MFA challenge. Opening a document stored in SharePoint Online or OneDrive for Business in that tenant brought an MFA challenge. My day was filled with MFA challenges, except when sending email to people in the tenant to complain about the new policy. Email isn’t affected by conditional access policies.

Setting the sign-in frequency in an Azure AD conditional access policy

Azure AD sign-in frequency for guest accounts set in a conditional access policy
Figure 2: Setting the sign-in frequency in an Azure AD conditional access policy

As Microsoft notes in their documentation, “Based on customer feedback, sign-in frequency will apply for MFA as well.” They understate the matter. Sign-in frequency does apply for MFA too.

I understand the motivation on the part of the security team. Forcing people to reauthenticate before they can access resources is a good thing. Using MFA is a good thing. Forcing MFA challenges every hour must be a brilliant change to make.

Only it isn’t. As an external person working with another company, the change made my productivity much worse, and I doubt that it added one iota to the overall security effectiveness of the tenant. The tenant did not use number matching and additional context for MFA challenges, so the constant MFA challenges were a great example of how user fatigue creeps in as I clicked and clicked again to say “yes, it’s me.” System-preferred authentication wasn’t used either, so while I used the Authenticator app, other guests might use relatively insecure SMS challenge/response.

Overall, the change made it unpleasant to work with the tenant and that’s bad. A one-hour sign-in frequency is just too rigid and strict. I don’t know of any other tenant (where I am a guest) that uses such a short frequency. Most tenants I know of use the 90-day default. Some use 7 days. The most security-conscious (before now) uses a 1-day frequency.

No Best Answer for All Tenants

In truth, I don’t know the best user sign-in frequency to use for either tenant or guest accounts. It all depends on the security posture that an organization wants to assume. But I can say that most tenants would be better off making sure that all accounts use MFA and eliminating the use of the less secure authentication methods before reducing the sign-in frequency. If you’re concerned about guest hygiene (in this case, how secure a guest account is), have a different and more restrictive conditional access policy for guest access while remembering the need to get work done through Azure B2B collaboration. And review guest accounts annually to remove unwanted and obsolete crud.

To me, bringing users along on the journey to better security is a better tactic than ramming heightened security down their throats. It’s always been that way.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/03/14/azure-ad-sign-in-frequency-guests/feed/ 2 59388
Azure AD Moves to Block OAuth App Hijacking https://office365itpros.com/2023/03/03/azure-ad-app-property-lock/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-app-property-lock https://office365itpros.com/2023/03/03/azure-ad-app-property-lock/#comments Fri, 03 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59307

Azure AD App Property Lock Feature Blocks Updates to App Credentials

In a relatively unpublicized move, the Azure AD development group has closed a hole exploited by attackers who add their own credentials to registered apps. The new app instance property lock feature (preview) allows developers to lock sensitive properties of apps. It’s intended for use by enterprise apps, which are the way that developers like Microsoft and Adobe install apps in other Azure AD organizations. The enterprise app stores app properties while the service principal created by Azure AD in the host organization holds the permissions assigned to the app in that organization. After provisioning the app into a new tenant, the developer can lock the app against change.

Why Attackers Go After OAuth Apps

In the past, attackers have been able to hijack an enterprise app by adding a credential like a X.509 certificate to the app. Unless the organization monitors the audit events created for application updates, the new credential will exist undetected and the attacker can use it to request Azure AD to issue an access token containing the permissions assigned to the app. Apart from its permissions, attackers don’t need any further access to the app. Instead, the attackers use the access token to access whatever data the permissions allow. In some cases, the attackers might access items in mailboxes; in others they might go after sensitive documents stored in SharePoint Online sites. Once they’ve compromised the target repository, the attackers can exfiltrate or wipe the data (potentially a Microsoft 365 “wiperware” attack).

Hijacking OAuth permissions assigned to apps is not a theoretical attack vector. It’s what was used in the Solarwinds campaign in 2021. The attackers generated an X.509 certificate and added it to Azure AD apps and used highly-permissioned apps to access data. Another example of OAuth app abuse is the September 2022 instance when attackers used an OAuth app to create an inbound connector to send spam.

Applying an Azure AD App Property Lock

The property lock feature allows developers to block any changes to some or all the sensitive properties for an app (the properties used in authentication flows). It’s important to emphasize that the property lock is not mandatory. Developers must apply it to their apps before the apps are used in other tenants.

You can lock properties for a registered app but cannot update enterprise apps created in your tenant by another organization (because an external organization owns the app). For instance, you cannot change the iOS accounts enterprise app used by Apple for some iOS device management, like the change needed to force the iOS mail app to use modern authentication.

To start, go to app registrations, select the app to lock and then access the authentication tab. The App instance property lock option is toward the bottom of the screen (Figure 1).

Accessing the app instance property lock feature for an app
Figure 1: Accessing the app instance property lock feature for an app

Click Configure and select the properties to lock (Figure 2).

electing the app properties to lock
Figure 2: Selecting the app properties to lock

Save the changes and the property lock is in force. Any subsequent attempt to update credentials will fail anywhere outside the home tenant.

Checking for App Credential Updates

Azure AD feeds audit information to the unified audit log, including events logged for app credential updates. Unfortunately, the information in the audit records follows an esoteric format that makes the data harder to interpret than it needs to be. Here’s a code snippet showing how to run the PowerShell Search-UnifiedAuditLog cmdlet to retrieve and report audit records for app credential changes.

$StartDate = (Get-Date).AddDays(-90)
$EndDate = Get-Date

[array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Formatted -ResultSize 5000 -Operations "Update application – Certificates and secrets management "
$Report = [System.Collections.Generic.List[Object]]::new() 
ForEach ($Record in $Records) {
 $AuditData = $Record.AuditData | ConvertFrom-Json
  $Mods = $AuditData.modifiedproperties.NewValue
  $ReportLine  = [PSCustomObject] @{
     Timestamp        = $Record.CreationDate
     User             = $AuditData.UserId
     AppName          = $AuditData.Target[3].Id
     Modified         = $AuditData.modifiedproperties.NewValue }
 $Report.Add($ReportLine)
}

The same information is available in the Azure AD audit log (Figure 3).

App credential update details in the Azure AD audit log
Figure 3: App credential update details in the Azure AD audit log

Attacks Don’t Stop When a Hole Closes

Although regrettable that the holes existed in the first place, it’s good that Microsoft is closing off one of the vulnerabilities exploited by attackers with the Azure AD App property lock. It’s an example of the chess game played out between the attackers and defenders around the protection of cloud services. Now that this hole is closing, attackers will consider their next move. Stay vigilant and keep checking the audit log to detect suspicious events!


Learn about protecting your Microsoft 365 tenant by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand features like the Azure AD app property lock and the most efficient ways to protect your data.

]]>
https://office365itpros.com/2023/03/03/azure-ad-app-property-lock/feed/ 2 59307
Comparing Azure AD Guest Accounts and Exchange Online Mail Contacts https://office365itpros.com/2023/03/02/mail-contacts-vs-guest-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=mail-contacts-vs-guest-accounts https://office365itpros.com/2023/03/02/mail-contacts-vs-guest-accounts/#comments Thu, 02 Mar 2023 01:00:00 +0000 https://office365itpros.com/?p=59163

Are Guest Accounts Better Than Mail Contacts?

During an online discussion following publication of my article about how to purge guest accounts with unredeemed invitations from Azure AD, Microsoft’s Jef Kazimer said that he sees many Microsoft 365 organizations using guest accounts instead of mail contacts because guest accounts have better lifecycle management, even if the guests never sign in.

That idea got me thinking. Exchange Online is the largest Microsoft 365 workload and some organizations create many thousands of mail contacts for different reasons. For instance, they might have contacts for people in partner organizations so that users can easily find those contacts in the Global Address List (GAL). Mail contacts also exist in Exchange Server and many of the contacts now in Exchange Online originated. Hybrid organizations can synchronize on-premises contacts to Azure AD, but the management of those objects must be done on-premises.

Understanding Mail Contacts

Before comparing mail contacts with Azure AD guest accounts, we need to understand what a mail contact is. Mail contact objects exist in both the Exchange directory (EXODS) and Azure AD. For example, to create a mail contact, you run the New-MailContact cmdlet:

New-MailContact -Name Jef.Kazimer -DisplayName "Jef Kazimer" -ExternalEmailAddress "Jef.Kazimer@contoso.com" -FirstName "Jef" -LastName "Kazimer"

This action creates a contact object in both Exchange Online and Azure AD. The Exchange object is what people think of when they think about a mail contact. The Azure AD object exists to hold properties unrelated to email processing. Because it uses mail contacts as addressable email recipients, all Exchange Online really cares about is the email address. Once an object has an email address, Exchange can route messages to it and allow the object to participate in distribution lists. The Get-MailContact cmdlet confirms the details of the new contact object:

Get-MailContact -Identity Jef.Kazimer | Format-Table DisplayName, ExternalEmailAddress

DisplayName ExternalEmailAddress
----------- --------------------
Jef Kazimer SMTP:Jef.Kazimer@contoso.com

The external directory object identifier stored in the mail contact points to the Azure AD object, which we can retrieve using the Get-MgContact cmdlet from the Microsoft Graph PowerShell SDK:

Get-MgContact -OrgContactId (Get-MailContact -Identity Jef.Kazimer).ExternalDirectoryObjectId | Format-Table displayName, proxyAddresses

DisplayName ProxyAddresses
----------- --------------
Jef Kazimer {SMTP:Jef.Kazimer@contoso.com}

The mail contact is a sparse object so far. To populate the other properties that you might want users to see in the GAL (Figure 1), you must run the Set-Contact cmdlet to update the Azure AD object:

Set-Contact -Identity Jef.Kazimer -StreetAddress "14, Preston Villas" -City "Bellevue" -StateorProvince "Washington" -PostalCode "98004" -Phone "+1 425-214-765" -MobilePhone "+1 425-214-705" -Pager $Null -HomePhone "+1 425-270-765" -Company "Contoso" -Title "Azure AD Guru" -Department "Information Technology" -Fax "+1 425-214-761" -Initials "JK" -Notes "Distinguished Person" -Office "Liberty Square" -CountryOrRegion "United States"
A fully-populated mail contact as seen by Outlook for Windows
Figure 1: A fully-populated mail contact as seen by Outlook for Windows

The Get-MgContact cmdlet reports the newly-populated properties as does the Get-ExoRecipient cmdlet. There are some exceptions and caveats:

  • Remember to include the PropertySet All parameter to force Get-ExoRecipient to retrieve the full set of properties.
  • Get-ExoRecipient doesn’t retrieve the street address because it’s not included in the GAL.
  • Get-MgContact uses compound properties to hold some information. For instance, to see the elements of a contact’s address, you must expand the properties stored in the Addresses property:
Get-MgContact -OrgContactId (Get-MailContact -Identity Jef.Kazimer).ExternalDirectoryObjectId | Select-Object -ExpandProperty Addresses


City     CountryOrRegion OfficeLocation PostalCode State      Street
----     --------------- -------------- ---------- -----      ------
Bellevue United States   Liberty Square 98004      Washington 14, Preston Villas

Managing Mail Contacts

A Set-MailContact cmdlet is available to update properties of the Exchange objects, including the set of custom attributes available for all mail-enabled objects. The Set-Contact cmdlet updates the information held in Azure AD contact objects such as the address data shown above.

When administrators manage mail contacts through the Microsoft 365 admin center or Exchange admin center, they can work with both Exchange Online and Azure AD object properties. The GUI hides the fact that the settings presented to the administrator come from two directories, much like it disguises the interaction between Azure AD and Exchange when managing mailbox-enabled user accounts.

Guest Accounts and Guest Mail Users

Now that we understand mail contacts, let’s discuss the relationship between Exchange Online and Azure AD guest accounts. Following the creation of a guest account, a background process creates a special type of mail user object with a RecipientTypeDetails setting of GuestMailUser based on the properties of the guest account. The mail user object allows:

  • Guest members of Outlook groups to participate in group conversations via email.
  • Mail routing to guest accounts.
  • Guest accounts to appear in the GAL and other Exchange address lists.

Guest mail user objects exist in the Exchange directory until the removal of their linked guest accounts from Azure AD. Although you can view guest mail user objects through the Exchange admin center, the GUI won’t allow you to update their properties.Changes must be made to the guest account using the Azure AD admin center or with a Graph API (including the Microsoft Graph PowerShell SDK cmdlets). You can update the Exchange-specific properties with the Set-MailUser cmdlet.

To see the set of guest mail user objects, run the Get-ExoRecipient cmdlet:

Get-ExoRecipient -RecipientTypeDetails GuestMailUser | Format-Table DisplayName, PrimarySmtpAddress, HiddenFromAddressListsEnabled

The last property is True (the default) if the guest account isn’t visible to Exchange address lists. Run the Set-MailUser cmdlet to update HiddenFromAddressListsEnabled to True to expose the object. Here’s an example:

Set-MailUser -Identity warren.gatland@o365maestro.onmicrosoft.com -HiddenFromAddressListsEnabled $False

Note that it takes at least a day before newly exposed objects show up in the offline address look (OAB).

Adding Guest Mail Users to Distribution Lists

Because the guest mail users are routable objects, they can be added to distribution lists. This example spells things out, but it’s possible to add a guest mail user to a distribution list by passing its display name or email address without going to the bother of fetching the object with Get-MailUser.

$GuestMailUser = Get-MailUser Get-MailUser -Filter {DisplayName -eq "Warren Gatland" -and RecipientTypeDetails -eq "GuestMailUser"}
Add-DistributionGroupMember -Identity "o365maestro Contacts" -Member $GuestMailUser.Name

Move to Guest Accounts or Stay with Mail Contacts

Getting back to the original point, Jef says that guest accounts have better lifecycle management. In other words, if an organization invests in creating guest accounts instead of mail contacts, they’ll benefit from the work Microsoft does to improve how Azure AD manages external identities.

There’s some truth here. An Azure AD guest account supports more properties, including custom security attributes and support dynamic Azure AD Groups and dynamic Azure AD administrative units. They’re a Microsoft 365 entity rather than being restricted to just Exchange Online. Azure AD development for external identities, including guest accounts, is active whereas I suspect the development effort for Exchange mail contacts entered an “only fix bugs” maintenance stage years ago. On the other hand, mail contacts are simple and effective and work across hybrid Exchange organizations.

If you’re a cloud-only organization, the choice exists to use either. If you decide to use Azure AD guest accounts, the existence of guest mail user objects smoothen the transition and make sure that address lists, distribution lists, an email routing continue working. Azure AD guest accounts are a better long-term bet, but that doesn’t mean that anyone should switch anytime soon.


Learn more about how the Microsoft 365 applications like Exchange Online and Azure AD really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2023/03/02/mail-contacts-vs-guest-accounts/feed/ 10 59163
Cleaning up Teams Premium Trial Licenses https://office365itpros.com/2023/02/09/remove-teams-premium-license/?utm_source=rss&utm_medium=rss&utm_campaign=remove-teams-premium-license https://office365itpros.com/2023/02/09/remove-teams-premium-license/#comments Thu, 09 Feb 2023 01:00:00 +0000 https://office365itpros.com/?p=59022

Remove Teams Premium Licenses from Azure AD User Accounts After 30-Day Trial Finishes

Microsoft makes a Teams Premium trial license to allow customers test whether the functionality available in Teams Premium is worth the $10/user/month cost. Some of the features, like meeting templates, might be less obviously worth the money. Others, like the advanced webinar functionality (like having a waitlist for webinar participants) might just be what you need. The trial allows you to try before you buy by testing all the features with up to 25 users for 30 days.

Once the 30-day period finishes, Microsoft automatically terminates the license validity and users lose access to the premium features. Even if you decide to go ahead with Teams Premium, it’s a good idea to clean up by removing the licenses from the user accounts that participated in the trial. This is easily done in the Microsoft 365 admin center by selecting the license, selecting all accounts holding the license and choosing Unassign licenses (Figure 1).

Removing the Teams Premium license from user accounts in the Microsoft 365 admin center

Remove Teams Premium licenses from Azure AD accounts
Figure 1: Removing the Teams Premium license from user accounts in the Microsoft 365 admin center

Remove Teams Premium Licenses with PowerShell

Given that we’re all learning how to manage licenses with the Microsoft Graph because of the imminent retirement of the Azure AD and MSOL modules, it’s good to know how to remove licenses. Let’s examine what’s needed to remove the Teams Premium trial licenses.

First, we must know the SKU identifier for the license. To do this, run the Get-MgSubscribedSku cmdlet and look through the set of licenses known to the tenant to find Teams Premium:

Get-MgSubscribedSku | Format-List SkuId, SkuPartNumber, ServicePlans

SkuId         : 36a0f3b3-adb5-49ea-bf66-762134cf063a

SkuPartNumber : Microsoft_Teams_Premium

ServicePlans  : {MCO_VIRTUAL_APPT, MICROSOFT_ECDN, TEAMSPRO_VIRTUALAPPT, TEAMSPRO_CUST...}

According to the Azure AD list of licenses and identifiers, the SKU identifier for Teams Premium is 989a1621-93bc-4be0-835c-fe30171d6463 rather than the 36a0f3b3-adb5-49ea-bf66-762134cf063a shown here. This is because the first value is for the paid license. The second is for the trial license. Both SKUs have the same part number and display name (which is why the license shown in Figure 1 is called Microsoft Teams Premium). It would be nice if Microsoft added a trial suffix for its trial licenses.

In any case, both SKUs include seven separate service plans. A service plan is a license for a piece of functionality that cannot be bought. Instead, it’s bundled into a product (SKU) like Teams Premium. Service plans allow administrators to selectively disable functionality enabled by a license. For instance, you could disable advanced virtual appointments without affecting the other elements in Teams Premium. Table 1 lists the service plans covered by Teams Premium.

Service plan identifierService plan nameDisplay name
85704d55-2e73-47ee-93b4-4b8ea14db92bMICROSOFT_ECDNMicrosoft Content Delivery Network
0504111f-feb8-4a3c-992a-70280f9a2869TEAMSPRO_MGMTMicrosoft Teams Premium Management
cc8c0802-a325-43df-8cba-995d0c6cb373TEAMSPRO_CUSTMicrosoft Teams Premium Branded Meetings
f8b44f54-18bb-46a3-9658-44ab58712968TEAMSPRO_PROTECTIONMicrosoft Teams Premium Advanced Meeting Protection
9104f592-f2a7-4f77-904c-ca5a5715883fTEAMSPRO_VIRTUALAPPTMicrosoft Teams Premium Virtual Appointment
711413d0-b36e-4cd4-93db-0a50a4ab7ea3MCO_VIRTUAL_APPTMicrosoft Teams Premium Virtual Appointments
78b58230-ec7e-4309-913c-93a45cc4735bTEAMSPRO_WEBINARMicrosoft Teams Premium Webinar
Table 1: Teams Premium service plans

PowerShell Code to Remove Teams Premium Licenses from Azure AD Accounts

Now that we know the SKU identifier, we can run some PowerShell to:

  • Find user accounts with the Teams Premium license. This is done using a lambda filter against the assignedLicenses property of each account.
  • Remove the license from those accounts.

Connect-MgGraph -Scope User.ReadWrite.All
Select-MgProfile Beta
# Populate identifier for target product (SKU)
$TeamsPremiumSku = "36a0f3b3-adb5-49ea-bf66-762134cf063a"
[array]$Users = Get-MgUser -filter "assignedLicenses/any(s:s/skuId eq $TeamsPremiumSku)" -All
If (!($Users)) { Write-Host "No Teams Premium Trial licenses found - exiting" ; break }
Write-Host ("Removing {0} Teams trial licenses from {1}..." -f $Users.count, ($Users.displayName -join ", "))

ForEach($User in $Users) {
  Try {
    $Status = Set-MgUserLicense -UserId $User.Id -RemoveLicenses $TeamsPremiumSku -AddLicenses @{}  }
  Catch {
    Write-Host "Error removing Teams Premium Trial license from {0}" -f $User.displayName }
}

Updated with an appropriate SKU identifier, the code will remove licenses for other Microsoft 365 products.

Remove Teams Premium Licenses to Avoid Confusion

It doesn’t matter if you leave expired licenses in place. They won’t affect how people use Microsoft 365. However, given that the paid-for and trial versions of the Teams Premium licenses have the same display name, it’s best to remove trial licenses to avoid potential future confusion.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/02/09/remove-teams-premium-license/feed/ 1 59022
How to Purge Guest Accounts with Unredeemed Invitations from Entra ID https://office365itpros.com/2023/02/07/entra-id-guest-accounts-unredeemed/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-guest-accounts-unredeemed https://office365itpros.com/2023/02/07/entra-id-guest-accounts-unredeemed/#comments Tue, 07 Feb 2023 01:00:00 +0000 https://office365itpros.com/?p=58988

Use PowerShell to Find and Remove Entra ID Guest Accounts Who Don’t Want to Join Your Party

Updated 5 September 2023

A January 30 post by Microsoft’s Jef Kazimer about using Azure Automation with Managed Identities to remove unredeemed guests from Entra ID (Azure AD) promised to be a good read. Jef is a Principal Program Manager in the Microsoft Entra organization. Apart from using Azure Automation (something that every tenant administrator should master), highlighting the Microsoft Graph PowerShell SDK V2.0 (currently in early preview) gave me another reason to read the article.

I have expressed some concerns about Microsoft’s plans for the V2.0 of the Microsoft Graph PowerShell SDK. Leaving those concerns aside, it’s always good to learn how others approach a problem, especially as I’ve recently covered similar ground in terms of how to decide to remove guest accounts using the SDK. The differences between the two methods of reviewing guest accounts is that Jef looks for instances where guest accounts never went through the invitation redemption process to fully validate their accounts. On the other hand, my script looks at how long it’s been since a guest signed into the tenant and the number of groups the account is a member of to determine “staleness.” Let’s consider how to review guest accounts based on unredeemed invitations.

Outlining the Process

On paper, the steps involved to find and remove guest accounts with unredeemed invitations are straightforward:

  • Find guest accounts that have not redeemed the invitations received to join the tenant.
  • Remove the accounts from Entra ID.

Jef’s article suggests that this should be a regular process executed by an Azure Automation job using a managed identity to sign into the Graph and run the necessary PowerShell commands. I agree and think this is a good way to make sure to clear out unwanted guest accounts periodically.

Where I disagree is the detail of how to find the guests. Let’s discuss.

The Need for Administrative Units

Jef uses a dynamic administrative unit (currently a preview feature) to manage guest accounts. While it’s certainly convenient to create a dynamic administrative unit and assign the user management role for the administrative unit to the managed identity, this approach is optional and creates a potential requirement for Entra ID Premium P1 licenses. If your organization has those licenses, using a dynamic administrative unit offers the advantage of reducing the scope for the managed identity to process Entra ID accounts.

In some organizations, using administrative units (both the standard and dynamic variants) could be overkill because user management is a task performed by one or two administrators. In larger organizations, granularity in user management can be a desirable aspect, which is why administrative units exist.

Finding Entra ID Guest Accounts with Unredeemed Invitations

The first step is to find the target set of guest accounts. The simplest way is to run the Get-MgUser cmdlet and filter accounts to look for guests:

Connect-MgGraph -Scope Directory.ReadWrite.All
Select-MgProfile Beta
[array]$Guests = Get-MgUser -Filter "userType eq 'Guest'" -All

The guest accounts we want are those that have the ExternalUserState property set to “PendingAcceptance.” In other words, Entra ID issued an invitation to the guest’s email address, but the guest never followed up to redeem their invitation. This amended call to Get-MgUser fetches the set of guest accounts with unredeemed invitations:

[array]$Guests = Get-MgUser -Filter "userType eq 'Guest' and ExternalUserState eq 'PendingAcceptance'" -All

Jef’s version uses the Get-MsIDUnredeemedInviteUser cmdlet from the MSIdentityTools module to find guest accounts with unredeemed invitations. It’s certainly worth considering using the MSIdentityTools module to manage Entra ID, but it’s also worth understanding how to do a job with the basic tools, which is what I do here.

Determining the Age of an Unredeemed Invitation

It would be unwise to remove any Entra ID guest accounts without giving their owners a little time to respond. Taking vacation periods into account, 45 days seem sufficient time for anyone to make their minds up. The loop to remove unredeemed guest accounts needs to check how long it’s been since Entra ID issued the invitation and only process the accounts that exceed the age threshold.

Our script can check when Entra ID created an invitation by checking the ExternalUserStateChangeDateTime property, which holds a timestamp for the last time the state of the account changed. The only state change for the accounts we’re interested in occurred when Entra ID created the invitations to join the tenant, so we can use the property to measure how long it’s been since a guest received their invitation.

This code shows how to loop through the set of guests with unredeemed invitations, check if their invitation is more than 45 days old, and remove the account that satisfy the test. To keep a record of what it does, the script logs the deletions.

[datetime]$Deadline = (Get-Date).AddDays(-45)
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($Guest in $Guests) {
  # Check Date
  [datetime]$InvitationSent = $Guest.ExternalUserStateChangeDateTime
  If ($InvitationSent -le $Deadline) {
     $DateInvitation = Get-Date($InvitationSent) -format g
     $DaysOld = (New-TimeSpan ($InvitationSent)).Days
     Try { 
        Remove-MgUser -UserId $Guest.Id
        $ReportLine = [PSCustomObject][Ordered]@{  
          Date        = Get-Date
          User        = $Guest.displayName
          UPN         = $Guest.UserPrincipalName
          Invited     = $DateInvitation
          "Days old"  = $DaysOld }
        $Report.Add($ReportLine)
      }
      Catch {
        Write-Error $_
      }
   } #End if
} #End Foreach Guest
Write-Host "Guest Accounts removed for" ($Report.User -Join ", ")

Figure 1 shows some data from the report generated for the deletions. In an Azure Automation scenario, you could create a report in SharePoint Online, send email to administrators, or post a message to a Teams channel to advise people about the removed accounts.

Old Entra ID guest accounts with unredeemed invitations
Figure 1: Old guest accounts with unredeemed invitations

Caveats Before Removing Entra ID Guest Accounts

The code works and stale guest account disappear to the Entra ID recycle bin. However, the danger exists that some of the accounts might be in active use. Take guest accounts created to represent the email addresses of Teams channels. These email addresses represent a connector to import messages into Teams channels. No one can sign into these non-existent mailboxes so no one  will ever redeem the guest invitations. However, the mail user objects created by Exchange Online for these guest accounts allow them to be included in distribution lists, added to address lists, and so on.

Another example is when a guest joins an Outlook group (a Microsoft 365 group whose membership communicates via email). Guest members of these groups do not need to redeem their invitation unless they intend to sign into the tenant to access Teams or SharePoint Online or another application that supports Azure B2B Collaboration. If you remove these guest accounts based on their invitation redemption status, some important email-based communication might fail, and that would be a bad thing.

One way around the issue is to mark Entra ID guest accounts used for these purposes by writing a value into an appropriate property. For instance, set the department to EMAIL. Here’s how to mark the set of guest accounts used to route email to Teams channels:

[array]$MailGuests = $Guests | Where-Object {$_.Mail -Like "*teams.ms*"}  
ForEach ($MG in $MailGuests) { Update-MgUser -UserId $MG.Id -Department "EMAIL" }

And here’s how to mark the guest members for an Outlook group using cmdlets from the Exchange Online management module:

[array]$Members = Get-UnifiedGroupLinks -Identity 'Exchange Grumpy Alumni' -LinkType Member
ForEach ($Member in $Members) { 
  If ($Member.RecipientType -eq "MailUser")  { Set-User -Identity $Member.Name -Department "EMAIL" -Confirm:$False }
}

After marking some guest accounts as exceptions, we can find the set of guest accounts to process with:

[array]$Guests = Get-MgUser -Filter "userType eq 'Guest'" -All | Where-Object {$_.ExternalUserState -eq "PendingAcceptance" -and $_.Department -ne "EMAIL"}

All of this goes to prove that setting out to automate what appears to be a straightforward administrative task might lead to unforeseen consequences if you don’t think through the different ways applications use the objects.

Using SDK V2.0

Coming back to using V2.0 of the Microsoft Graph PowerShell SDK, nothing done so far needs V2.0. The only mention of a V2.0-specific feature is the support for a managed identity when connecting to the Graph. The code used to connect is:

Connect-MgGraph -Identity

A one-liner is certainly convenient, but it’s possible to connect to a managed identity with the Graph SDK with code that is just a little more complicated. Here’s what I do:

Connect-AzAccount -Identity
$AccessToken = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com"
Connect-MgGraph -AccessToken $AccessToken.Token

Going from three lines to one is probably not a huge benefit!


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/02/07/entra-id-guest-accounts-unredeemed/feed/ 3 58988
Azure AD Introduces IPv6 Support https://office365itpros.com/2023/01/27/azure-ad-ipv6-support/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-ipv6-support https://office365itpros.com/2023/01/27/azure-ad-ipv6-support/#respond Fri, 27 Jan 2023 01:00:00 +0000 https://office365itpros.com/?p=58856

Azure AD IPv6 Connections Supported from March 31, 2023

The Azure AD development group certainly believes in keeping tenant administrators on their toes. Not content with releasing a steady stream of new functionality, Azure AD is refreshing its infrastructure by introducing support for IPv6 starting March 31, 2023. Given the size of the Microsoft 365 infrastructure, it’s impossible to put an exact date when support reaches a specific tenant.

As Microsoft says, this will allow customers to “reach the Azure AD services over IPv4, IPv6 or dual stack endpoints.” In other words, requests to Azure AD for authentication and other services from clients can travel over an IPv6 connection in addition to the current IPv4 connections. Microsoft stresses that they are not deemphasizing support for IPv4 in any way.

The change should be transparent from a user perspective. Most users don’t pay much attention to networking configuration and accept the default settings necessary to connect via Wi-Fi, cell network, or LAN. If problems happen, they’re more likely to surface for network and tenant administrators.

Conditional Access, Named Locations, and Azure AD IPv6

In its support page for the introduction of IPv6 to Azure AD, Microsoft specifically calls out the need to update any conditional access policies that apply restrictions using named locations. A named location allows a condition access policy to identify incoming traffic from a specific place based on a country (using GPS location or IP address) or a specific IPv4/IPv6 address range. The policy can then allow or block the connection. The Microsoft Entra admin center currently only supports IPv4 addresses for country identification.

After Azure AD supports IPv6, it creates the possibility that clients will present IPv6 addresses when they attempt to connect. If the conditional access policy doesn’t recognize the address as a permitted connection source, the client cannot connect.

Microsoft says that organizations should check conditional access policies to find those that use named locations and then update the named locations used by those policies to include the range of IPv6 addresses that clients will use. Figure 1 shows how to assign an IPv6 range to a named location in the Microsoft Entra admin center (or Azure AD admin center).

Adding an IPv6 address range for an Azure AD named location

Azure AD IPv6
Figure 1: Adding an IPv6 address range for an Azure AD named location

Obviously, it might take some effort to determine the full set of IPv6 addresses that clients might use, so it’s best to start this work as soon as possible.

Other Places Where IP Addresses Lurk

A change in originating IP address has consequences for other parts of an infrastructure. For instance, connection data captured by Azure AD will now contain IPv6 addresses. For instance, the unified audit log ingests information about user sign-ins from Azure AD. The audit records contain the IP address used by the client. Here’s what an audit record found by the Search-UnifiedAuditLog cmdlet holds:

RecordType   : AzureActiveDirectoryStsLogon
CreationDate : 24/01/2023 18:33:13
UserIds      : Jane.Smithoffice365itpros.com
Operations   : UserLoggedIn
AuditData    : {
                 "CreationTime": "2023-01-24T18:33:13",
                 "Id": "78bb9d6f-afc2-4ea7-ab7f-16fdb7423e00",
                 "Operation": "UserLoggedIn",
                 "OrganizationId": "a662313f-14fc-43a2-9a7a-d2e27f4f3478",
                 "RecordType": "AzureActiveDirectoryStsLogon",
                 "ResultStatus": "Success",
                 "UserKey": "eff4cd58-1bb8-4899-94de-795f656b4a18",
                 "UserType": "Regular",
                 "Version": 1,
                 "Workload": "AzureActiveDirectory",
                 "ClientIP": "78.17.97.20",
                 "ObjectId": "797f4846-ba00-4fd7-ba43-dac1f8f63013",

Audit records generated by Azure AD can go elsewhere. For instance, a connector is available to import the data into Microsoft Sentinel. The flow of data from Azure AD to other applications highlights the need to check that reports and analysis of this data is capable of processing IPv6 addresses.

All Change in Azure AD

March 2023 is going to be a big month for tenant administrators. Already, work had to be done to upgrade PowerShell scripts to remove old Azure AD and MSOL cmdlets that perform license management operations. These cmdlets will stop working when Microsoft 365 introduces a new license management platform on March 31. Now work must be done to check what IPv6 addresses might show up once Microsoft enables IPv6 support in the tenant. It’s all go inside Microsoft 365…


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2023/01/27/azure-ad-ipv6-support/feed/ 0 58856
Reporting Group Membership for Azure AD Guest Accounts with the Microsoft Graph PowerShell SDK https://office365itpros.com/2023/01/18/old-azure-ad-guest-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=old-azure-ad-guest-accounts https://office365itpros.com/2023/01/18/old-azure-ad-guest-accounts/#comments Wed, 18 Jan 2023 01:00:00 +0000 https://office365itpros.com/?p=58742

Finding Azure AD Guest Accounts in Microsoft 365 Groups

The article explaining how to report old guest accounts and their membership of Microsoft 365 Groups (and teams) in a tenant is very popular and many people use its accompanying script. The idea is to find guest accounts above a certain age (365 days – configurable in the script) and report the groups these guests are members of. Any old guest accounts that aren’t in any groups are candidates for removal.

The script uses an old technique featuring the distinguished name of guest accounts to scan for group memberships using the Get-Recipient cmdlet. The approach works, but the variation of values that can exist in distinguished names due to the inclusion of characters like apostrophes and vertical lines means that some special processing is needed to make sure that lookups work. Achieving consistency in distinguished names might be one of the reasons for Microsoft’s plan to make Exchange Online mailbox identification more effective.

In any case, time moves on and code degrades. I wanted to investigate how to use the Microsoft Graph PowerShell SDK to replace Get-Recipient. The script already uses the SDK to find Azure AD guest accounts with the Get-MgUser cmdlet.

The Graph Foundation

Graph APIs provide the foundation for all SDK cmdlets. Graph APIs provide the foundation for all SDK cmdlets. The first thing to find is an appropriate API to find group membership. I started off with getMemberGroups. The PowerShell example for the API suggests that the Get-MgDirectoryObjectMemberGroup cmdlet is the one to use. For example:

$UserId = (Get-MgUser -UserId Terry.Hegarty@Office365itpros.com).id 
[array]$Groups = Get-MgDirectoryObjectMemberGroup  -DirectoryObjectId $UserId -SecurityEnabledOnly:$False

The cmdlet works and returns a list of group identifiers that can be used to retrieve information about the groups that the user belongs to. For example:

Get-MgGroup -GroupId $Groups[0] | Format-Table DisplayName, Id, GroupTypes

DisplayName                     Id                                   GroupTypes
-----------                     --                                   ----------
All Tenant Member User Accounts 05ecf033-b39a-422c-8d30-0605965e29da {DynamicMembership, Unified}

However, because Get-MgDirectoryObjectMemberGroup returns a simple list of group identifiers, the developer must do extra work to call Get-MgGroup for each group to retrieve group properties. Not only is this extra work, calling Get-MgGroup repeatedly becomes very inefficient as the number of guests and their membership in groups increase.

Looking Behind the Scenes with Graph X-Ray

The Azure AD admin center (and the Entra admin center) both list the groups that user accounts (tenant and guests) belong to. Performance is snappy and it seemed unlikely that the code used was making multiple calls to retrieve the properties for each group. Many of the sections in these admin centers use Graph API requests to fetch information, and the Graph X-Ray tool reveals those requests. Looking at the output, it’s interesting to see that the admin center uses the beta Graph endpoint with the groups memberOf API (Figure 1).

Using the Graph X-Ray tool to find the Graph API for group membership

Azure AD Guest Accounts
Figure 1: Using the Graph X-Ray tool to find the Graph API for group membership

We can reuse the call used by the Azure AD center to create the query (containing the object identifier for the user account) and run the query using the SDK Invoke-MgGraphRequest cmdlet. One change made to the command is to include a filter to select only Microsoft 365 groups. If you omit the filter, the Graph returns all the groups a user belongs to, including security groups and distribution lists. The group information is in an array that’s in the Value property returned by the Graph request. For convenience, we put the data into a separate array.

$Uri = ("https://graph.microsoft.com/beta/users/{0}/memberOf/microsoft.graph.group?`$filter=groupTypes/any(a:a eq 'unified')&`$top=200&$`orderby=displayName&`$count=true" -f $Guest.Id)
[array]$Data = Invoke-MgGraphRequest -Uri $Uri
[array]$GuestGroups = $Data.Value

Using the Get-MgUserMemberOf Cmdlet

The equivalent SDK cmdlet is Get-MgUserMemberOf. To return the set of groups an account belongs to, the command is:

[array]$Data = Get-MgUserMemberOf -UserId $Guest.Id -All
[array]$GuestGroups = $Data.AdditionalProperties

The format of returned data marks a big difference between the SDK cmdlet and the Graph API request. The cmdlet returns group information in a hash table in the AdditionalProperties array while the Graph API request returns a simple array called Value. To retrieve group properties from the hash table, we must enumerate through its values. For instance, to return the names of the Microsoft 365 groups in the hash table, we do something like this:

[Array]$GroupNames = $Null
ForEach ($Item in $GuestGroups.GetEnumerator() ) {
   If ($Item.groupTypes -eq "unified") { $GroupNames+= $Item.displayName }
}
$GroupNames= $GroupNames -join ", "

SDK cmdlets can be inconsistent in how they return data. It’s just one of the charms of working with cmdlets that are automatically generated from code. Hopefully, Microsoft will do a better job of ironing out inconsistencies when they release V2.0 of the SDK sometime later in 2023.

A Get-MgUserTransitiveMemberOf cmdlet is also available to return the membership of nested groups. We don’t need to do this because we’re only interested in Microsoft 365 groups, which don’t support nesting. The cmdlet works in much the same way:

[array]$TransitiveData = Get-MgUserTransitiveMemberOf -UserId Kim.Akers@office365itpros.com -All

The Script Based on the SDK

Because of the extra complexity in accessing group properties, I decided to use a modified version of the Graph API request from the Azure AD admin center. It’s executed using the Invoke-MgGraphRequest cmdlet, so I think the decision is justified.

When revising the script, I made some other improvements, including adding a basic assessment of whether a guest account is stale or very stale. The assessment is intended to highlight if I should consider removing these accounts because they’re obviously not being used. Figure 2 shows the output of the report.

Report highlighting potentially obsolete guest accounts
Figure 2: Report highlighting potentially obsolete Azure AD guest accounts

You can download a copy of the script from GitHub.

Cleaning up Obsolete Azure AD Guest Accounts

Reporting obsolete Azure AD guest accounts is nice. Cleaning up old junk from Azure AD is even better. The script generates a PowerShell list with details of all guests over a certain age and the groups they belong to. To generate a list of the very stale guest accounts, filter the list:

[array]$DeleteAccounts = $Report | Where-Object {$_.StaleNess -eq "Very Stale"}

To complete the job and remove the obsolete guest accounts, a simple loop to call Remove-MgUser to process each account:

ForEach ($Account in $DeleteAccounts) {
   Write-Host ("Removing guest account for {0} with UPN {1}" -f $Account.Name, $Account.UPN) 
   Remove-MgUser -UserId $Account.Id }

Obsolete or stale guest accounts are not harmful, but their presence slows down processing like PowerShell scripts. For that reason, it’s a good idea to clean out unwanted guests periodically.


Learn about mastering the Microsoft Graph PowerShell SDK and the Microsoft 365 PowerShell modules by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

]]>
https://office365itpros.com/2023/01/18/old-azure-ad-guest-accounts/feed/ 2 58742
Achieving Consistency in Country Settings Across Azure AD and Exchange Online https://office365itpros.com/2023/01/09/azure-ad-user-country-settings/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-user-country-settings https://office365itpros.com/2023/01/09/azure-ad-user-country-settings/#comments Mon, 09 Jan 2023 01:00:00 +0000 https://office365itpros.com/?p=58612

Managing Azure AD User Country and Regional Settings

A question arose about why Exchange Online doesn’t synchronize country settings from Azure AD user accounts, leading to a situation where an Azure AD user account and its mailbox might have inconsistent values. Here’s an example where the Get-MgUser and Get-Recipient cmdlets report different country values for a user account:

Get-MgUser -UserId Sean.Landy@Office365itpros.com | Format-Table country, usagelocation

Country UsageLocation
------- -------------
Austria FR

Get-Recipient -Identity Sean.Landy@Office365itpros.com | Select-Object country*

CountryOrRegion
---------------
France

The technical reason for the apparent inconsistency is simple: Get-MgUser reads data for a user account from Azure AD while Get-Recipient reads information about a mailbox from EXODS, the Exchange Online directory. We’re dealing with two different objects stored in two different directories.

EXODS exists to manage mail-specific properties for mail-enabled objects, like mailboxes. EXODS also manages Exchange objects that aren’t in Azure AD such as public folders and dynamic distribution lists.

Dual Write Between Azure AD and EXODS

To ensure consistency across the two directories, Azure AD and EXODS use a dual-write process. In other words, when an application attempts to update an object, the write operation must succeed in both directories before Azure AD and EXODS commit the change.

However, this doesn’t happen for every property for every object in the two directories. Although the mailbox CountryOrRegion property receives the same value as the user account’s Country property when Exchange Online creates a new mailbox, synchronization doesn’t follow for further updates. Azure AD and EXODS synchronize updates to other elements of address information like the street address, city, and province made in either directory, but ignore changes to the Country property in Azure AD or the CountryOrRegion property in EXODS. Perhaps the reason is that the two properties have different names and purposes: One is specific to a country while the other can store a country or region name. In fact, EXODS doesn’t store a Country property for mailboxes.

All of which means that it is possible to update an Azure AD account with a new value for the country property without any effect on EXODS. For example, this command updates Azure AD without doing anything to EXODS:

Update-MgUser -UserId Sean.Landy@Office365itpros.com -Country "Ireland"

Likewise, the same is true of an update to EXODS with the Set-User cmdlet. Azure AD ignores this update:

Set-User -Identity Sean.Landy@Office365itpros.com -CountryOrRegion "United States"

In practical terms, the inconsistency might be irritating but it isn’t important. Azure AD is the directory of record for Microsoft 365 and applications should go to it for information about user accounts. The information stored in EXODS about mailbox owners is for informational purposes only. If you want everything to match, then you must create a mechanism (a PowerShell script most likely) to synchronize the properties you want to be consistent.

Azure AD Account Usage Location

Another potential inconsistency is the usage location assigned to an Azure AD account. In the example above, the usage location is FR (France) but the Country property says Austria. The usage location is where Microsoft delivers the service to the account and it’s important that it’s correct because Microsoft cannot deliver some elements of Microsoft 365 (mostly to do with encryption) in certain countries.

Life being what it is, the usage location set when creating an account can change. For instance, a user might relocate to work in an office in another country for a period. There’s no requirement to update the usage location for the account because this should reflect the user’s normal location. In addition, an account’s usage location isn’t associated with the tenant home location. The location (or datacenter region) for a tenant establishes where Microsoft delivers services to the tenant from and where tenant data resides. This can be a country-level datacenter (like France, Switzerland, or South Africa), or a regional datacenter (like the U.S. or Western Europe). Tenant accounts located in countries outside a datacenter location can access services delivered to the tenant. Multi-geo tenants are available should local data residency be necessary.

Mailbox Regional Settings

When you create a new Microsoft 365 account and license the account for Exchange Online, the mailbox does not inherit regional properties from the country or service location defined for the Azure AD account. This is deliberate because regional properties are personal to the user and define the language used to interact with the mailbox, its time zone, and the preferred date format. Different groups of people in the same country often use different regional settings. Examples include Welsh speakers in the United Kingdom and Flemish speakers in Belgium.

OWA applies default regional properties based on the tenant location the first time the mailbox owner signs in and creates a set of default folders. For example, mailboxes that use the English language have an Inbox folder, while mailboxes configured for French use Boîte de réception. Users can update regional settings for OWA through Outlook settings. (Figure 1). If they change the selected language, they have the option to rename the default folders.

Selecting regional settings for OWA

Azure AD user country settings
Figure 1: Selecting regional settings for OWA

Administrators can run the Set-MailboxRegionalConfiguration cmdlet to change the regional settings for a mailbox. In this example, the mailbox language, time zone, and date and time formats match the settings for a Dutch user working in the Netherlands. Notice the use of the LocalizeDefaultFolderName parameter, set to $True to force Exchange Online to create default folder names in Dutch for the mailbox:

Set-MailboxRegionalConfiguration –Identity 'Rob Young' –Language nl-NL 
–TimeZone 'W. Europe Standard Time' –DateFormat ‘d-M-yyyy’–TimeFormat 'HH:mm' 
–LocalizeDefaultFolderName:$True

Apart from the language, the time zone is the most important setting because it’s used by Microsoft 365 applications. For example, Teams displays the local time zone for other users when showing their details in profile cards. If your organization scripts the creation of new accounts, it’s a good idea to make sure that the code includes the configuration of an appropriate time zone setting for the mailbox.

Reporting Azure AD User Country and Regional Settings

It’s easy to audit the language settings of Azure AD accounts and mailboxes. Here’s some code to show how:

$Report = [System.Collections.Generic.List[Object]]::new()
[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All
ForEach ($User in $Users) {
  Write-Host ("Processing account {0}" -f $User.DisplayName)
  $RegionalSettings = $Null
  $RegionalSettings = Get-MailboxRegionalConfiguration -Identity $User.UserPrincipalName -ErrorAction SilentlyContinue
  $CountryOrRegion = (Get-User -Identity $User.UserPrincipalName -ErrorAction SilentlyContinue) | Select-Object -ExpandProperty CountryOrRegion
  If ($RegionalSettings) {
  $ReportLine = [PSCustomObject]@{ 
    User                   = $User.UserPrincipalName
    DisplayName            = $User.DisplayName
    Country                = $User.Country
    "Preferred Language"   = $User.PreferredLanguage
    "Usage Location"       = $User.UsageLocation
    "Country or region"    = $CountryOrRegion
    Language               = $RegionalSettings.Language.DisplayName
    DateFormat             = $RegionalSettings.DateFormat
    TimeFormat             = $RegionalSettings.TimeFormat
    TimeZone               = $RegionalSettings.TimeZone }
 $Report.Add($ReportLine) }
}

Figure 2 shows the output. This data is from a test tenant, but it illustrates how easy it is for inconsistencies to occur across the range of country settings available for accounts and mailboxes.

Azure AD user account and mailbox country and regional settings
Figure 2: Azure AD user account and mailbox country and regional settings

The most important element to get correct is the time zone because it affects the user experience. It would be easy to make sure that Country (Azure AD) and CountryOrRegion (EXODS) contain the same value, but aside from configuring values during account creation, you should leave regional settings alone as they’re a matter of personal choice.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2023/01/09/azure-ad-user-country-settings/feed/ 4 58612
Adding QR Codes to Microsoft Authenticator for Entra ID Guest Accounts https://office365itpros.com/2023/01/04/microsoft-authenticator-app-qr/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-authenticator-app-qr https://office365itpros.com/2023/01/04/microsoft-authenticator-app-qr/#comments Wed, 04 Jan 2023 01:00:00 +0000 https://office365itpros.com/?p=58395

Moving to a New Mobile Phone Means New Codes for the Microsoft Authenticator App

Moving to a new mobile device always involves a certain amount of hassle. The advent of mobile authenticator apps makes the move a little harder, especially when guest accounts on other tenants are involved.

In my case, I moved from an oldish iPhone 11 to a new iPhone 14. I was very happy with the 11 and used it since 2019. However, its battery showed signs of age and I fancied a change, which is all the reason I needed to get the 14.

Moving apps from an old iPhone to a new device is very easy. Minor hassles like making Outlook the default mail app for iOS and adding Teams to the pinned app list are easily overcome. It’s all the messing around with app passwords and authentication that causes the hassle.

Which brings me to the Microsoft Authenticator app. I am a strong proponent of multi-factor authentication and use the authenticator app to protect my Microsoft 365 and other accounts, including services like GitHub and Twitter. The app has a backup and recovery capability that I used to restore details of the accounts I use with authenticator. Unhappily (as noted in the support article), “Only your personal and non-Microsoft account credentials are stored, which includes your username and the account verification code that’s required to prove your identity.”

MFA Responses by Microsoft Authenticator App Need Device-Specific Credentials

For Microsoft school or work (Entra ID) accounts, the article explains that accounts that use push notifications (like MFA challenges) need additional verification to recover information. Push notifications require using a credential tied to a specific device. To restore accounts protected by MFA using the authenticator app on the new phone, this means that “you must scan a QR code given to you by your account provider.

The key to getting a new QR code for your Entra ID account is the Security info section of the My account page. After signing into your account, this section displays the sign-in methods used to access your account (Figure 1). This is the same kind of information that’s available when examining authentication methods for user accounts with the Microsoft Graph PowerShell SDK.

Listing sign-in methods for an Entra ID account
Figure 1: Listing sign-in methods for an Entra ID account

Note: If a user can’t access the My account page because they don’t have access to their old phone and therefore cannot respond to an MFA challenge, an administrator can temporarily downgrade the MFA requirement to SMS to allow the user to sign in and access the page.

Adding a QR Code for a New Device

Remember that the credential used by the Microsoft Authenticator app to respond to MFA challenges is device-specific. To generate a new QR code, click Add sign-in method and select Authenticator app from the list of options. You’ll then be told that you need to install the app, which is fine because it’s already on the device. Click Next to start the setup process and click Next again to see a new QR code for the app (Figure 2).

enerating a new QR code for the Microsoft Authenticator app
Figure 2: Generating a new QR code for the Microsoft Authenticator app

You can scan the code using Authenticator and once this happens, the connection between account, app, and credential works. The process includes a verification step to prove that the Authenticator app can use the credential.

After setting up Authenticator for a new device, you’ll have multiple Microsoft Authenticator entries in your sign-in methods list (one per device). It’s perfectly safe to remove the entries for devices that you no longer use.

Adding a QR Code for a Guest Account

Everything works very nicely for a full tenant account. Generating a QR code to allow Authenticator to satisfy MFA challenges for a guest account is a little more complicated. I have guest accounts in multiple Microsoft 365 organizations, mostly because I am a guest member of Teams in those organizations. Let’s assume that you see that a guest account shows up in Authenticator flagged with “Action required” (Figure 3). This means that Authenticator can’t satisfy challenges for this account because it doesn’t have the necessary credentials.

The Microsoft Authenticator app flags that action is needed to fix an account
Figure 3: The Microsoft Authenticator app flags that action is needed to fix an account

To secure the credentials for the account, the trick is to use the option to switch organizations via the icon in the top right-hand corner of the My Account page. This reveals the set of organizations that your account belongs to, starting with your account in the home tenant and then listing the organizations (aka host tenants) where you have a guest account (Figure 4).

Selecting an organization where an account is a guest
Figure 4: Selecting an organization where an account is a guest

Switching to another organization uses your account (the guest account in this case) to sign-into that organization. You can then use the Security Info page to go through the same steps to generate a new QR code and add it to the entry for the guest account in the Authenticator app. The Authenticator app should now be able to satisfy MFA challenges for the guest account when signing into the target organization.

Microsoft Authenticator App Restored to Good Health

Moving to a new iPhone isn’t something people do every day and it’s easy to forget how to renew credentials in different services. Getting new QR codes for the Authenticator app is in that category. Fortunately, the process isn’t quite as painful as I first anticipated after restoring the backup to my new phone and everything is now working as expected.

PS. If you use the Authenticator app on an Apple Watch, remember that from January 2023, the Authenticator app no longer supports WatchOS. Microsoft says that WatchOS is “incompatible with Authenticator security features.” I read that to mean that some of the changes Microsoft made recently to harden Authenticator against MFA fatigue like number matching and additional context just don’t work in the constrained real estate available for watch devices.

]]>
https://office365itpros.com/2023/01/04/microsoft-authenticator-app-qr/feed/ 6 58395
Adding New Azure AD Users to Groups Automatically https://office365itpros.com/2022/12/05/dynamic-group-membership/?utm_source=rss&utm_medium=rss&utm_campaign=dynamic-group-membership https://office365itpros.com/2022/12/05/dynamic-group-membership/#comments Mon, 05 Dec 2022 01:00:00 +0000 https://office365itpros.com/?p=58175

Dynamic Group Membership is the Obvious But Not the Only Option

A member of the Microsoft Technical Community asks if it’s possible to automatically add newly-created accounts to an existing group. The initial response offered by the community focused on dynamic groups – either dynamic distribution lists or dynamic Azure AD groups.

It’s a reasonable suggestion. Dynamic distribution groups are part of base Exchange Online functionality and don’t require any additional licenses. Dynamic Azure AD groups require Azure AD Premium P1 licenses for every account covered by dynamic membership. In both cases, the trick is to make sure that the query used by Exchange Online or Azure AD to determine group membership finds the new account.

Dynamic Group Membership for Exchange Online Mailboxes

It’s possible to create a dynamic distribution group based on a simple query like “all mailboxes” that will automatically include new accounts (if they have mailboxes). Figure 1 shows the UX in the Exchange admin center (EAC) to define the membership of a new dynamic distribution list.

Figure 1: Dynamic membership settings for all mailboxes

The list works and email sent to it arrives in the inbox of every mailbox in the tenant, including shared mailboxes. This is because the recipient filter generated by Exchange Online for the dynamic distribution group selects all mail-enabled objects with a recipient type of ‘UserMailbox’ and only filters out some system mailboxes.

A dynamic distribution list like this is said to use a “canned” recipient filter because Exchange Online generates the filter based on the choices the administrator makes when they create the new list. You can only edit canned filters through the EAC. Exchange Online gives greater flexibility through the support of custom recipient filters. These filters can only be created using PowerShell, but they’re much more flexible in terms of selecting the set of mail-enabled objects to address through the list. A simple custom recipient filter to find just user mailboxes is shown below together with a test with the Get-Recipient cmdlet to prove that the filter works.

$Filter = "{RecipientTypeDetails -eq 'UserMailbox'}"
Get-Recipient -RecipientPreviewFilter $Filter

Dynamic Group Membership for Azure AD User Accounts

Dynamic Azure AD groups can be used with Microsoft 365 groups and Teams. These groups use different membership filters (query rules) to find the set of target objects. Instead of mail-enabled objects like mailboxes, the query against Azure AD focuses on user accounts rather than mailboxes. However, the same capability exists in that it’s possible to create a dynamic Azure AD group that includes all user accounts, including those newly created.

Again, the key is to construct a query rule that finds all user accounts – of the right type. When Azure AD is used for a Microsoft 365 tenant, there are many non-interactive user accounts created to give identities to objects such as shared mailboxes and room mailboxes. These are all considered “member” accounts and it’s easy to build a rule to find all member accounts. However, you probably want a more refined version that finds just the accounts used by humans.

Azure AD doesn’t have a human filter, so we need to construct something that Azure AD can use to find matching accounts in its directory. One approach is to use licenses for the check. You could look for accounts assigned Office 365 E3 licenses but would have to check for accounts with F1 or E5 licenses too. An easy change is to look for accounts that have any license that has at least one enabled service. For instance, accounts with Office 365 E3 or E5 licenses with the Exchange Online, Teams, Planner, or SharePoint Online service would all match. Figure 2 shows a test of the rule against a “real” user account and some other user accounts belonging to room and shared mailboxes. You can see that the real account passes the validation test while the others do not.

Testing the membership rule for a dynamic Azure AD group to find all user accounts
Figure 2: Testing the membership rule for a dynamic Azure AD group to find all user accounts

Azure AD accounts used by shared mailboxes must be assigned licenses when they need more than 50 GB of mailbox storage or an online archive. These accounts satisfy the membership rule, but that’s perhaps not important. If it is, some tweaking of the membership rule is necessary to remove the shared mailbox accounts.

Dynamic Group Membership of Org-Wide Teams

If your organization is smaller than 10,000 accounts, new Azure AD accounts automatically join the org-wide teams in the tenant (a tenant can support up to five org-wide teams). Org-wide teams are a special form of dynamic Microsoft 365 group whose membership is controlled by Teams rather than Azure AD, so Azure AD Premium P1 license are not required.

The PowerShell Alternative to Manage Dynamic Group Membership

If you don’t want to use a dynamic object, it’s certainly possible to use standard distribution lists or Microsoft 35 groups. In this scenario, the tenant takes the responsibility for maintaining group membership. Usually, PowerShell is used to add new accounts to group membership. You don’t have to worry about removing deleted accounts from the group as this happens automatically following an account deletion.

To add a new user to a distribution list, use the Add-DistributionGroupMember cmdlet:

Add-DistributionGroupMember -Identity "All Tenant Mailboxes" -Member Lotte.Vetler@office365itpros.com

To add a new user account to a Microsoft 365 group, either run the Add-UnifiedGroupLinks cmdlet (from the Exchange Online management module) or the New-MgGroupMember cmdlet (from the Microsoft Graph PowerShell SDK):

Add-UnifiedGroupLinks -Identity "All Tenant Accounts" -LinkType Member -Links Lotte.Vetler@office365itpros.com

New-MgGroupMember -GroupId "107fe4dd-809c-4ec9-a3a1-ab88c96e0a5e" -DirectoryObjectId (Get-MgUser -UserId Lotte.Vetler@office365itpros.com).Id

If the tenant creates user accounts programmatically with PowerShell, these commands can be added to that script. If not, a background scheduled job could find accounts that don’t exist in group membership and add them. See this article for more information about group management with the Microsoft Graph PowerShell SDK.

Many Possibilities to Ponder

A simple question required a long answer. That’s because the questioner didn’t specify what type of group that they wanted to add new accounts to. In any case, it’s nice to be able to debate the possibilities and then settle on the best course of action to take.


Insight about the various options to manage dynamic group membership for new accounts doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/12/05/dynamic-group-membership/feed/ 3 58175
The Fuss About the Azure AD Tenant Creation Setting https://office365itpros.com/2022/11/29/azure-ad-tenant-creation/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-tenant-creation https://office365itpros.com/2022/11/29/azure-ad-tenant-creation/#comments Tue, 29 Nov 2022 01:00:00 +0000 https://office365itpros.com/?p=58083

Azure AD Tenant Creation is Useful

Updated: 14 December 2022

I really don’t know why so much fuss and bother erupted (mostly in Twitter) when a preview setting to control creation of new tenants appeared in the User settings section of the Azure AD admin center (Figure 1). The fact is that people have always been able to create new tenants. Developers, for instance, often take the opportunity to run the free Microsoft 365 tenant offered by Microsoft for development purposes. If you’re doing Graph-based development, you can keep the free tenant (complete with 25 Office 365 E5 licenses) going for as long as you want.

The setting to control if users can create new Azure AD tenants

Azure AD tenant creation
Figure 1: The setting to control if users can create new Azure AD tenants

Update: Microsoft formally documented the preview of the tenant creation control in message center notification MC485089 (14 Dec 2022). It is covered by Microsoft 365 roadmap item 109541 with general availability expected in March 2023.

Few users will find their way to the Azure AD admin center to create a new tenant. And if you restrict access to the administration portal using the setting in Figure 1, Azure AD blocks non-administrator access to the portal (Figure 2), so those that attempt to access the admin center cannot do very much.

Sorry! No access to the Azure AD admin center
Figure 2: Sorry! No access to the Azure AD admin center

Azure AD and Multiple Tenants

An important factor to consider is that Azure AD is a massive multi-tenant environment. A tenant is a logical division of work spanning user accounts, groups, applications, roles, and so on. A basic Azure AD tenant is free. The limitations that exist come through licensing.

Some organizations are perfectly happy with a single tenant; others will split work across multiple tenants, perhaps to accommodate operating units within the company or to respect geographical boundaries. From a Microsoft 365 perspective, a single tenant is the best option because it sets the foundation for easy collaboration and sharing across the entire organization. To enable data residency requirements, Microsoft 365 offers multi-geo support for Exchange Online, SharePoint Online, OneDrive for Business, and Teams.

Creating a New Azure AD Tenant

If users can create new tenants and have access to the Azure AD admin center, they can go to the overview section and select Manage tenants. They’ll see the set of tenants that their account can access, including the home tenant and tenants where they have guest membership. Selecting the Create option invokes a wizard to collect information about the new tenant. All that’s needed is:

  • An organization (tenant) display name. The name does not need to be unique.
  • An initial service domain. This is the sub-domain of onmicrosoft.com and must be unique.
  • The datacenter region to host the tenant.
  • The type of tenant. In this example, I use a regular Azure AD tenant rather than one used for Azure B2C.

In Figure 3, I’m creating a new Azure AD tenant called Office 365 for IT Pros. The wizard detects a problem with the service domain. I don’t know if someone else has a service domain called office365itpros.onmicrosoft.com, but I own office365itpros.com and the domain is registered to my Microsoft 365 tenant, so that might be where the problem lies. In any case, it’s easily fixed by choosing a different service domain. No relationship exists between the tenant display name and its service domain. And although Microsoft 365 uses the service domain for objects like Microsoft Online Email Routing Addresses (MOERA) and SharePoint Online site names, user principal names and user email addresses can use other domains registered for the tenant.

A problem with Azure AD tenant creation
Figure 3: A problem with Azure AD tenant creation

The user that creates a tenant becomes its first global administrator. This doesn’t involve creating a new member account in the tenant. Instead, Azure AD creates a guest account for the account that creates the tenant and assigns the global administrator role to the guest account.

Creating a new tenant takes just a few minutes. Once the tenant exists, you can sign in and begin working with the tenant. For instance, you can connect to the tenant with the Microsoft Graph PowerShell SDK.

Connect-MgGraph -TenantId Office365itpros2.onmicrosoft.com
Welcome To Microsoft Graph!

Get-MgOrganization | Format-Table DisplayName, VerifiedDomains

DisplayName            VerifiedDomains
-----------            ---------------
Office 365 for IT Pros {Office365itpros2.onmicrosoft.com}

Microsoft makes workload packs available for developer tenants to populate the tenant with objects like mailboxes and sites. A tenant created from the Azure AD admin center is bare-bones and completely separate to the tenant that the creating owner belongs to. No subscriptions or licenses are transferred. The only (tenuous) link connecting the two tenants is the guest account. Before any useful work can be done in the new tenant, the administrator must create objects like accounts, groups, apps, and configurations, and buy licenses and subscriptions.

A good reason to create a tenant is to have a baseline to compare settings against. Over time, a production tenant accrues updates and unless the organization practices good change management, it’s hard to know exactly what has been changed in different areas. A new tenant allows the organization to check the starting position and compare it to values in the production tenant. In addition, unlike developer tenants, which expire after 90 days if not used, tenants created in this manner don’t expire.

Azure AD Authorization Policy

Returning to the original point, all Azure AD tenants have a default authorization policy to hold the settings that control what users can do. These are the settings revealed in the Azure AD admin center. You can see the value of the settings through the Graph Explorer by running a query against https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy (Figure 4).

Viewing the default Azure AD authorization policy through Graph Explorer
Figure 4: Viewing the default Azure AD authorization policy through Graph Explorer

The policy shown in Figure 4 shows that the allowedToCreateTenants setting is False. This setting only applies to users. Administrators can still create tenants if they wish.

The authorization policy is also accessible via the Get-MgPolicyAuthorizationPolicy cmdlet. Running the cmdlet requires that the app has the Policy.Read.All permission. See this article for an explanation about how the SDK deals with permissions.

Get-MgPolicyAuthorizationPolicy | Select-Object -ExpandProperty DefaultUserRolePermissions | Format-List

AllowedToCreateApps                      : True
AllowedToCreateSecurityGroups            : True
AllowedToReadBitlockerKeysForOwnedDevice : True
AllowedToReadOtherUsers                  : True
AdditionalProperties                     : {[allowedToCreateTenants, True]}

To update the authorization policy, the app must hold the Policy.ReadWrite.Authorization permission. You can then create a hash table to hold the new settings and apply the settings by running the Update-MgPolicyAuthorizationPolicy cmdlet:

$RolePermissions = @{}
$RolePermissions["allowedToCreateTenants"] = $False
Update-MgPolicyAuthorizationPolicy -AuthorizationPolicyId "authorizationPolicy" 
-DefaultUserRolePermissions $RolePermissions
Get-MgPolicyAuthorizationPolicy | Select-Object -ExpandProperty DefaultUserRolePermissions | Format-List

AllowedToCreateApps                      : True
AllowedToCreateSecurityGroups            : True
AllowedToReadBitlockerKeysForOwnedDevice : True
AllowedToReadOtherUsers                  : True
AdditionalProperties                     : {[allowedToCreateTenants, False]}

Nothing Odd About Multiple Tenants

There’s nothing odd about having multiple Azure AD tenants, if you have good reason to run more than a single tenant. As noted above, Microsoft 365 runs best with a single tenant, but developers and other users might need access to their own space.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/11/29/azure-ad-tenant-creation/feed/ 3 58083
Creating New Azure AD User Accounts and Updating Passwords with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/11/28/azure-ad-account-creation/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-account-creation https://office365itpros.com/2022/11/28/azure-ad-account-creation/#comments Mon, 28 Nov 2022 01:00:00 +0000 https://office365itpros.com/?p=58066

Manage User Accounts with the New-MgUser and Update-MgUser Cmdlets

In March 2022, I wrote about the basics of Azure AD account management using the Microsoft Graph PowerShell SDK. One of the things that I left out of that article was Azure AD account creation. I omitted this detail because it was already covered in another article, where I compare creating an account using cmdlets from the old Azure AD module and the SDK. I’ll cover the basic points here

Connecting to the Microsoft Graph SDK

Before we can create or update accounts, we must connect to the SDK endpoint with the required permissions:

Connect-MgGraph -Scopes User.ReadWrite.All, Directory.ReadWrite.All
Select-MgProfile Beta

Password Profiles

The New-MgUser cmdlet creates a new account. To run New-MgUser, we need a password profile. A password profile is a Microsoft Graph resource that contains a password and associated settings. It can be as simple as a password with no settings, but a password profile can also include settings like ForceChangePasswordNextSignIn to force a user account to change their password after they next sign into Azure AD.

New-MgUser uses a hash table for the password profile. The example code shown below populates the hash table with a new password (generated using the GeneratePassword .NET method as a random 10-character string containing special characters, numbers, and upper- and lower-case letters). The ForceChangePasswordNextSignIn setting is True to force the new user to set a new password after they sign in.

Add-Type -AssemblyName 'System.Web'
$NewPassword = [System.Web.Security.Membership]::GeneratePassword(10, 3)
$NewPasswordProfile = @{}
$NewPasswordProfile["Password"]= $NewPassword
$NewPasswordProfile["ForceChangePasswordNextSignIn"] = $True

The hash table now contains values like this:

Name                           Value
----                           -----
Password                       4i_gb6OK?{
ForceChangePasswordNextSignIn  True

Creating a New Azure AD User Account with New-MgUser

To create the new account, run the New-MgUser cmdlet. It’s obviously important to include as many details as possible about the new user account, especially the settings exposed by Microsoft 365 in places like the user profile card or the Organization Explorer feature in Outlook and Teams.

# Azure AD Account Creation - the hard coded way
$DisplayName = "Jeff Atkinson"
$NewUser = New-MgUser -UserPrincipalName "Jeff.Atkinson@Office365ITPros.com" `
  -DisplayName "Jeff Atkinson (Information Technology)" `
  -PasswordProfile $NewPasswordProfile -AccountEnabled `
  -MailNickName Jeff.Atkinson -City NYC `
  -CompanyName "Office 365 for IT Pros" -Country "United States" `
  -Department "IT Operations" -JobTitle "GM Operations" `
  -BusinessPhones "+1 676 830 1101" -MobilePhone "+1 617 4466615" `
  -State "New York" -StreetAddress "1, Avenue of the Americas" `
  -Surname "Atkinson" -GivenName "Jeff" `
  -UsageLocation "US" -OfficeLocation "NYC"
If ($NewUser) { Write-Host ("Successfully added the {0} account" -f $NewUser.DisplayName) 
  } Else { Write-Host ("Failure adding the {0} account - exiting" -f $DisplayName); break }

The usage location is a two-character ISO-3166 country code to show where the account consumes services, and it’s important to set the value correctly so that the license assignment works properly. After creating a new account, you’ll need to assign it some licenses to allow access to Microsoft 365 services. See this article for more information.

The code to add a new account shown above is a one-off command. However, it’s the principal that counts and it is straightforward to take the code and amend it so that it uses parameters or input such as a CSV file (like that shown in Figure 1) holding details of new users. In the latter case, after loading the records into an array, you could then loop through the records to add each account. Here’s an example of doing just that:

CSV file to drive Azure AD account creation
Figure 1: CSV file to drive Azure AD account creation

# Azure AD account creation - driven by data imported from a CSV file
$Accounts = Import-CSV c:\temp\Accounts.CSV
ForEach ($Account in $Accounts) {
  $NewPassword = [System.Web.Security.Membership]::GeneratePassword(10, 3)
  $NewPasswordProfile = @{}
  $NewPasswordProfile["Password"]= $NewPassword
  $NewPasswordProfile["ForceChangePasswordNextSignIn"] = $True
  $MailNickname = $Account.First + "." + $Account.Surname
  $DisplayName = $Account.First + " " + $Account.Surname
  Write-Host ("Processing the {0} account" -f $DisplayName)
  $NewUser = New-MgUser -UserPrincipalName $Account.UserPrincipalName `
  -DisplayName $DisplayName `
  -PasswordProfile $NewPasswordProfile `
  -MailNickName $MailNickName -City $Account.City `
  -CompanyName $Account.Company -Country $Account.Country `
  -Department $Account.Department -JobTitle $Account.Title `
  -BusinessPhones $Account.Phone -MobilePhone $Account.Mobile `
  -State $Account.State -StreetAddress $Account.Street `
  -Surname $Account.Surname -GivenName $Account.First `
  -UsageLocation $Account.Location -OfficeLocation $Account.Office `
  -AccountEnabled
 If ($NewUser) { Write-Host ("Successfully added the {0} account" -f $NewUser.DisplayName) 
  } Else { Write-Host ("Failure adding the {0} account - exiting" -f $DisplayName); break }
}

Finishing up Azure AD Account Creation

To complete the account creation process, you might want to send email to the administrator accounts with details of the new account (Figure 2). This task is easily accomplished with a Graph method to create and send email (explained in this article).

Email notification about the creation of a new Azure AD user account

Azure AD account creation
Figure 2: Email notification about the creation of a new Azure AD user account

To help illustrate the flow of creating a new account complete with license assignment and email notification, I’ve uploaded a script to GitHub. The code is not a functional script because it contains once-off commands. Instead, it’s for you to play with and create your own version.

Updating a User Account with a New Password

To change an Azure AD account password, create a password profile as above and then run the Update-MgUser cmdlet. If you don’t want to force the user to create a new password after they sign in, make sure that the ForceChangePasswordNextSignIn setting in the password profile is false, and then run:

Update-MgUser -UserId Terry.Hegarty@Office365itpros.com -PasswordProfile $NewPassword

Updating a user’s password generates a continual access evaluation (CAE) event for CAE. This means that “enlightened” applications like the Office web apps learn about the existence of the new password and will force the user to reauthenticate with the new password to continue working.

Azure AD Account Creation Not Hard with the SDK

Creating a new Azure AD user account with the Microsoft Graph PowerShell SDK isn’t difficult. The hardest thing might be to come up with a good temporary password to assign to the account. Good luck if you’re moving scripts from the old Azure AD or MSOL modules before Microsoft deprecates these modules in 2023. It just takes a little time and maybe a lot of persistence.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/11/28/azure-ad-account-creation/feed/ 1 58066
How to Pause Membership Processing for Dynamic Group Membership https://office365itpros.com/2022/11/22/pause-membership-processing/?utm_source=rss&utm_medium=rss&utm_campaign=pause-membership-processing https://office365itpros.com/2022/11/22/pause-membership-processing/#comments Tue, 22 Nov 2022 01:00:00 +0000 https://office365itpros.com/?p=58033

New Pause Processing Toggle Appears in Entra ID Admin Center

Updated 22-Nov-2023

A recent Entra ID admin center update for Entra ID dynamic groups allows administrators to pause membership processing to resolve membership rules and identify group members. I can’t find any announcement about the change, and it’s not tagged as a preview, but a toggle is there to pause processing (Figure 1) and it works.

Pause processing for an Entra ID dynamic group

Pause membership processing
Figure 1: Pause processing for an Entra ID dynamic group

Switching the pause processing toggle back to off allows Entra ID to continue processing membership rules. The properties of a dynamic group tell you the current state of processing and when the last membership change happened. Common processing states for Entra ID dynamic groups are:

  • Succeeded: Entra ID has evaluated the membership query and the membership is up to date.
  • Evaluating: Entra ID is currently resolving the membership query to identify group members.
  • Processing: Entra ID is currently processing the membership.
  • Processing error: Entra ID was unable to evaluate the membership query.
  • Updates paused: An administrator has paused updates. The membership remains static until updates resume.
  • Not started: Entra ID has not yet started to evaluate the membership of a dynamic group.

Entra ID reassesses membership as demand on the service allows, with the goal of checking at least once daily. It’s therefore possible that Entra ID will not process changes made to user objects that bring them within the scope of a membership rule for up to 24 hours. My experience is that updates often occur earlier, but it’s wise to set this expectation.

Reporting Dynamic Membership Updates

To check the current situation with dynamic membership updates, we can use PowerShell to find all the dynamic groups in the tenant and report the timestamp for the last membership update, whether processing is enabled, and the current update status. Here’s how to do the job with the Microsoft Graph PowerShell SDK:

Connect-MgGraph -Scope Group.Read.All, GroupMember.Read.All
[array]$Groups = Get-MgBetaGroup -Filter "groupTypes/any(c:c eq 'DynamicMembership')" -All 
If (!($Groups)) { 
    Write-Host "No dynamic groups found"
} Else { 
   Write-Host ("Processing {0} dynamic groups" -f $Groups.count) }
$Report = [System.Collections.Generic.List[Object]]::new()
$Groups = $Groups | Sort-Object DisplayName
ForEach ($Group in $Groups) {
  $Options = $Group.ResourceProvisioningOptions -join ", "
  [array]$Members = Get-MgGroupMember -GroupId $Group.Id
  [array]$Owners = Get-MgGroupOwner -GroupId $Group.Id
  $DynamicData = Get-MgBetaGroup -GroupId $Group.Id -Property MembershipRuleProcessingStatus
  $DataLine = [PSCustomObject] @{
    Id              = $Group.Id
    DisplayName     = $Group.DisplayName
    Owners          = $Owners.Count
    Members         = $Members.Count
    ProcessingState = $Group.MembershipRuleProcessingState
    LastUpdate      = $DynamicData.MembershipRuleProcessingStatus.LastMembershipUpdated
    Status          = $DynamicData.MembershipRuleProcessingStatus.Status
    Options         = $Options }
  $Report.Add($DataLine)
}
$Report | Out-GridView

You can see that the code uses separate calls to the Get-MgBetaGroup cmdlet to fetch the property holding the membership rule processing status for the groups. For some reason, the original call to fetch a set of filtered groups fails if this property is included in the list to be retrieved. As revealed by the Graph X-Ray add-on, the same flow happens in the Entra ID admin center.

The code also includes calls to the Get-MgGroupOwner, Get-MgGroupMember, and Get-MgUser cmdlets to fetch the set of owners and members for each group. Although the Get-MgGroupOwner and Get-MgGroupMember cmdlets returns the set of owners and members respectively for a group, they return object identifiers instead of display names. While we can use the information to report counts, to report the owner names, we need to run Get-MgUser. See these articles for more information about using the Microsoft Graph PowerShell SDK to work with Entra ID user accounts and Entra ID Groups. Figure 2 shows the output of the report.

Figure 2: Reporting the membership processing state of Entra ID dynamic groups

Dynamic groups with paused membership updates show a last update of 1 January 2000. Most of the groups in Figure 2 have odd dates (1/1/0001). This situation occurred when I ran a script to pause membership processing for all dynamic groups. The next time Entra ID processes membership rules to validate group membership , it will update the date.

Dynamic Groups and Dynamic Distribution Lists

Entra ID dynamic groups and dynamic distribution lists are very different objects, but some people confuse the two or believe that the two objects are roughly the same. Apart from the requirement to have Entra ID Premium P1 licenses for Entra ID dynamic groups, the three biggest differences are:

  • Dynamic distribution lists don’t exist in Entra ID. They are an Exchange object.
  • Dynamic distribution lists support a wider set of member objects (any mail-enabled recipient).
  • Dynamic distribution lists support a wider set of properties for building custom membership filters (queries).

See this article for more information about the differences between the two types of dynamic group.

Dynamic Restrictions

Because of the processing load required to evaluate and process group membership, Entra ID restricts the number of dynamic groups and dynamic administrative units combined per tenant to 5,000. In December 2021, Microsoft changed the way that Exchange Online evaluates membership of dynamic distribution lists in a similar attempt to save resources.

Reasons to Pause Membership Processing

Although I appreciate Microsoft adding the extra flexibility in pausing membership processing, I’m struggling to find a good use case. One might be in a merger and acquisition scenario where the directory is in a state of flux, and you want consistency in dynamic group memberships for a period. Apart from that, I don’t know why Microsoft introduced the feature. However, it’s here now and available if you need it.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/11/22/pause-membership-processing/feed/ 5 58033
Using PowerShell to Manage Azure AD Custom Security Attributes https://office365itpros.com/2022/11/11/custom-security-attributes-ps/?utm_source=rss&utm_medium=rss&utm_campaign=custom-security-attributes-ps https://office365itpros.com/2022/11/11/custom-security-attributes-ps/#comments Fri, 11 Nov 2022 01:00:00 +0000 https://office365itpros.com/?p=57859

Microsoft Graph PowerShell SDK Cmdlets Support Custom Security Attributes

Updated 12-Sep-2023

Introduced in preview in December 2021, I’m still looking for a good way to use Azure AD custom security attributes. Microsoft recently updated conditional access policies to support an app filter based on custom security attributes. That’s a nice example of what’s possible, but it’s probably a scenario limited to tenants that need such a capability.

In my original commentary on custom security attributes, I wondered if they might replace Exchange Online custom attributes. So far, I see little sign that this will happen, if only because the preview implementation only supports user and service principal objects. Exchange Online supports custom attributes for all mail-enabled objects, meaning that these attributes are more flexible. Marking Microsoft 365 groups so that changes to their membership can be monitored is just one recent practical example of custom attributes in use.

Marking objects is one thing. Being able to find the marked objects is equally important. The cmdlets in the Exchange Online management PowerShell support server-side filtering against custom attributes to make it easy and fast to search against the attributes. It therefore seemed like a good thing to check how to search Azure AD objects using values stored in Azure AD custom security attributes.

Assigning and Finding Custom Security Attributes

Cmdlets in the Microsoft Graph PowerShell SDK that operate against Azure AD user accounts and service principals (for enterprise and registered applications) support the custom security attributes. Microsoft’s documentation explains the basics. For example, to add custom security attributes to a user object, populate a hash table containing the attribute names and values and use it as input to the Update-MgUser cmdlet.

$Attributes = @{
	CustomSecurityAttributes = @{
	  Employees = @{
           "@odata.type" = "#Microsoft.DirectoryServices.CustomSecurityAttributeValue"
           JobCode = 'Principal'
           DateOfHire = '2-Nov-1983'
           "EmployeeNumber@odata.type" = "#Int32"
           EmployeeNumber = '150847'
           Executive = $true
	   }
	}
}

Update-MgUser -Userid Tony.Redmond@office365itpros.com -BodyParameter $Attributes

In this case, the attributes come from a set called Employees (Figure 1) that contains attributes defined as string, Boolean, and integer data types. You can see in the PowerShell snippet how to define the data types for Boolean and integer attributes.

Custom Security Attributes in the Azure AD admin center
Figure 1: Custom Security Attributes in the Azure AD admin center

If you make a mistake with an attribute value, update the parameter with the correct value and run Update-MgUser again. To remove an attribute value, pass a blank value (something like ‘ ‘) rather than $Null. The lack of support for the $Null PowerShell variable is an SDK foible.

To check that the custom security attributes are in place, run the Get-MgUser cmdlet against the user account and fetch the CustomSecurityAttributes property:

$User = Get-MgUser -UserId Tony.Redmond@office365itpros.com -Property CustomSecurityAttributes

$EmployeeData = $User.customsecurityattributes.additionalProperties['Employees']

Although it’s simple to retrieve the property, complexity lurks because the attribute values are stored in a system dictionary object called additionalProperties. Multiple sets of custom security attributes can be assigned to an object, so additionalProperties holds a separate hash table for each set. In this instance, we’re only interested in attributes from the Employees set, so we extract them into a separate hash table to make it more convenient to access individual attribute values. Each attribute that we want to use is easily fetched by a keyed lookup against the hash table as shown below.

$EmployeeData

Key            Value
---            -----
@odata.type    #microsoft.graph.customSecurityAttributeValue
Executive      True
JobCode        Principal
LegalEntity    RA Ireland
DateOfHire     2-Nov-1983
EmployeeNumber 150847

$EmployeeData['JobCode']

I’m sure that the structure we’ve just navigated to find custom security attributes makes sense in terms of the way that Microsoft generates the cmdlets in the Microsoft Graph PowerShell SDK from the underlying Graph APIs. However, compared to the ease of access to data using other PowerShell cmdlets, it’s too complex and clunky.

Searching All User Accounts for an Attribute Value

This feeling is confirmed when trying to find users with a specific value stored in an attribute. This code finds all user member accounts in the tenant with at least one assigned license (to exclude accounts like those used for shared and room mailboxes). The code then loops through all users to find those with custom security attributes from the Employees set and checks if the job code attribute has a certain value.

[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All -Property CustomSecurityAttributes, Id, DisplayName
ForEach ($User in $Users) {
    If ($User.customsecurityattributes.AdditionalProperties['Employees'] -ne $Null) {
        $EmployeeData = $User.customsecurityattributes.AdditionalProperties['Employees']
        If ($EmployeeData['JobCode'] -eq "Principal") {
          Write-Host $User.DisplayName "is a Principal" }
    }
}

I can’t find a filter for the Get-MgUser cmdlet to search for a value in a single attribute. I’ll keep trying, but for now I’m left with the technique explained above.

Using Custom Security Attributes with Service Principals

The same approach applies to updating the service principal for an enterprise or registered app with a custom security attribute. This code searches to find a specific application and then updates two attributes. The only changes are in the cmdlets used and that the AppDepartment attribute supports the storage of multiple values. This means that we must identify that the attribute is a collection of strings and pass the strings in an array:

$App = Get-MgServicePrincipal -Filter "displayname eq 'Graph Microsoft 365 Groups Membership Report'"
$Attributes = @{
	CustomSecurityAttributes = @{
	  Applications = @{
           "@odata.type" = "#Microsoft.DirectoryServices.CustomSecurityAttributeValue"
           "AppLevel@odata.type" = "#Int32"
           AppLevel = "1"
           "AppDepartment@odata.type" = "#Collection(String)"
           AppDepartment = @( "IT" )
	   }
	}
}

Finding applications marked with a certain attribute value follows the same path as explained above. Here’s what I did to find applications marked with IT in the AppDepartment attribute:

[array]$Apps = Get-MgServicePrincipal -All -Property CustomSecurityAttributes, DisplayName, Id, AppId
ForEach ($App in $Apps) {
    If ($App.customsecurityattributes.AdditionalProperties['Applications'] -ne $Null) {
       $AppAttributes = $App.customsecurityattributes.AdditionalProperties['Applications']
       If ($AppAttributes['AppDepartment'] -eq "IT") {
          Write-Host $App.DisplayName "is an IT application" }
    }
}

Looking Forward to Change

I’m not writing off Azure AD custom security attributes (but if you want to store employee data, there are some standard attributes available for user objects). I’m sure that the Entra ID team has many plans to use these attributes in different ways and that the Microsoft Graph PowerShell SDK developers could make the attributes easier to work with. At least, I hope so.


Keep up to date with developments like Azure AD custom security attributes by subscribing to the Office 365 for IT Pros eBook. Our monthly updates make sure that our subscribers understand the most important changes happening across Office 365.

]]>
https://office365itpros.com/2022/11/11/custom-security-attributes-ps/feed/ 2 57859
Azure AD Conditional Access Policies Get App Filter https://office365itpros.com/2022/10/31/conditional-access-app-filter/?utm_source=rss&utm_medium=rss&utm_campaign=conditional-access-app-filter https://office365itpros.com/2022/10/31/conditional-access-app-filter/#respond Mon, 31 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57675

Custom Security Attributes Used for Conditional Access App Filters

In January 2022, I wrote about the introduction (in preview) of Azure AD custom security attributes. At the time, Microsoft positioned the new attributes as part of their Attribute-based Access Control initiative for Azure to give organizations the ability to manage resources at a fine-grained level. Not being an Azure expert, I tried the new custom security attributes out and felt that organizations would figure out ways to use them.

Lots of new stuff has happened recently with Azure AD conditional access policies, like the introduction of new checks for external user type and authentication strength. Now, Microsoft has added a filter for apps based on custom security attributes.

Mark Apps with Custom Security Attributes

The idea is simple. Organizations define custom security attributes to use to mark apps known to Azure AD. An app is an object and like any other Azure AD object, administrators can assign the app whatever custom attributes make sense. For instance, you could assign an attribute to indicate the department that uses an app or an attribute to mark an app as highly important. The point is that the custom attribute is then used by a filter (Figure 1) to identify apps that a conditional policy can allow or block access to.

 Defining an app filter for a conditional access policy
Figure 1: Defining an app filter for a conditional access policy

For now, app filters in conditional access policies can only use string custom security attributes, but you can select attributes from any attribute set defined in the organization. The app filter can be combined with any of the other controls available in a conditional access policy.

The value in this approach is that you don’t need to amend a conditional access policy to accommodate new or additional apps. Simply update the app with an appropriate value for the custom security attribute used by the app filter and the app immediately becomes within the policy scope. That’s a big advantage in large organizations that might have to manage hundreds (or conceivably, thousands) of applications.

Graph X-Ray in Windows Store

In other Azure AD news, the Graph X-Ray tool that exposes the Graph API calls made by (some parts of) the Azure AD admin center is now available in the Windows Store (Figure 2). I recommend this tool to anyone who’s getting acquainted with the Graph API calls used for objects like users and groups.

The Graph X-Ray tool in the Windows Store
Figure 2: The Graph X-Ray tool in the Windows Store

The Graph X-Ray tool helped us enormously when we upgraded the PowerShell examples using the soon-to-be-deprecated Azure AD module to Graph API calls or Microsoft Graph PowerShell SDK cmdlets for the 2023 edition of the Office 365 for IT Pros eBook. Sometimes you need just a little hint to understand what approach to take and the Graph X-Ray tool delivers more than its fair share of hints.

Cmd.Ms

From the same fertile mind as Graph X-Ray comes Cmd.ms, an elegantly simple idea that delivers great value. Microsoft 365, as you might have observed, spans a bunch of administrative portals and consoles and it’s sometimes difficult to remember the URI for a specific portal. You can go to the Microsoft 365 admin center and rely on the shortcuts available there to get you to the Teams admin center, Exchange admin center, SharePoint Online admin center, and so on, but what happens if you haven’t loaded the Microsoft 365 admin center or need to go somewhere that isn’t available as a shortcut? That’s where Cmd.ms comes in.

Essentially, Microsoft has defined a set of web shortcuts to the admin centers (Figure 3). Entering teams.cmd.ms brings you to Teams while admin.cmd.ms loads the Microsoft 365 admin center. It’s tremendously useful.

Cmd.ms shortcuts to Microsoft 365 web sites
Figure 3: Cmd.ms shortcuts to Microsoft 365 web sites

Cmd.ms add-ons are available for Edge, Chrome, and Firefox to provide autocomplete suggestions in the browser address bar.

The only issue I have is that Microsoft chose to use ad.cmd.ms to bring you to the Entra admin center and azad.cmd.ms to the Azure Active Directory admin center. I know Microsoft wants to emphasize the Entra brand, but it would be nice to have aad.cmd.ms used for Azure AD rather than azad.cmd.ms. It’s a small buggette.

Continued Evolution of Conditional Access

Returning to the original topic, there’s no doubt that Microsoft is putting a great deal of effort into improving the functionality of Azure AD conditional access policies. The recent batch of announcements underline this point. It’s all about erecting more efficient barriers to unauthorized access. Hopefully attackers can’t get into an Azure AD tenant. If they do, conditional access policies can help restrict their ability to compromise resources. That’s the logic underpinning the deployment of conditional access.

]]>
https://office365itpros.com/2022/10/31/conditional-access-app-filter/feed/ 0 57675
Azure AD Conditional Access Policies Add Check for External User Types https://office365itpros.com/2022/10/27/conditional-access-policy-external/?utm_source=rss&utm_medium=rss&utm_campaign=conditional-access-policy-external https://office365itpros.com/2022/10/27/conditional-access-policy-external/#comments Thu, 27 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57630

New Conditional Access Policy Settings to Exert Granular Control Over External Users

Building on their recent work to improve Azure AD conditional access policies by adding a control to require specific authentication strengths for connections, Microsoft has released another interesting control (in preview). You can now differentiate between the different kinds of external users that connect to your tenant in a feature that Microsoft calls “fine-grained Azure B2B access control.”

Azure AD recognizes different kinds of connections based on the authentication flow, so it’s able to focus on connections such as B2B Collaboration like guests accessing a SharePoint Online site or when an account authenticated in another tenant uses B2B Direct Connect to access a Teams shared channel. The differentiation between connection types allows Azure AD to apply conditional access to impose conditions on specific connections.

Adding Control for External Users

To try the new control out, I created a new conditional access policy. Under the assignments section, I chose to include specific users. This option has always been available, but now you get to pick from the different types of external users supported by Azure AD (Figure 1).

Defining the types of external users for a conditional access policy
Figure 1: Defining the types of external users for a conditional access policy

For most Microsoft 365 tenants, the interesting options are B2B Collaboration and B2B Direct Connect. Guest accounts created using Azure B2B Collaboration have been in use since mid-2016 to support external access to resources in Outlook Groups, Teams, SharePoint Online, OneDrive for Business, Yammer, and Planner. The Azure B2B Collaboration policy is available to control the creation of guest accounts using a block list of domains. Even with a policy in place, tenants end up with large numbers of guest accounts and need to do some pruning to remove obsolete guests.

External accounts that use B2B Direct Connect to access Teams shared channels (the only workload currently supported) don’t have a presence in the tenant directory. Instead, these accounts authenticate against their own directory and present the credentials to gain access to the resources in the host tenant. If the cross-tenant access policies configured in both tenants permit access, the accounts can work with the resources.

The external user control includes other account types used in more specific circumstances. The point is that a lot of flexibility exists in the control of inbound connections. For instance, you can restrict the control to specific Microsoft 365 tenants (Figure 2) using either the tenant identifier or a registered domain for the tenant to add it to the policy (if you don’t know the tenant identifier, you can find it using an online service).

Adding an external Azure AD domain to a conditional access policy
Figure 2: Adding an external Azure AD domain to a conditional access policy

The new control works alongside the other controls available in a conditional access policy. In this instance, I configured the policy to apply to Office 365 apps and to require multi-factor authentication to grant access.

Planning Conditional Access Policies

An Azure AD tenant can support up to 195 conditional access policies. It takes planning to make sure that you don’t create a set of conditional access policies that conflict with each other and that each policy serves a well-defined purpose. For instance, the new ability to control external connections from specific tenants might tempt administrators to create to create multiple policies to control external access for external access from specific tenants. This is a bad idea and will probably be a maintenance nightmare. Try to use the one policy to handle external access from all partner tenants as it’s likely that much the same kind of controls will apply to all.

To make sure that other policies didn’t interfere with testing, I put any policy relating to external access into report-only mode.

Testing the Control

To test that the new policy worked as expected, I signed into Teams using an account belonging to the tenant specified in the policy. I then opened a shared channel and was immediately promoted with an MFA challenge. After satisfying the challenge, the client connected to the shared channel and the account could post messages. Figure 3 shows the authentication and conditional access details for a sign-in processed by the conditional access policy.

Azure AD sign-in record tracks application of the conditional access policy
Figure 3: Azure AD sign-in record tracks application of the conditional access policy

One More Control for Connections

Conditional access policies are not a universal panacea for keeping a Microsoft 365 tenant safe and secure from attackers. However, correctly configured and deployed, conditional access policies can stop people who shouldn’t access tenant resources from getting in. The new find-grained external access control is helpful in this respect. Remember that conditional access is an Azure AD Premium feature and deploy it alongside Exchange Online authentication policies to gain maximum protection from attacker probes.


Stay updated with developments across the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. We do the research to make sure that our readers understand the technology.

]]>
https://office365itpros.com/2022/10/27/conditional-access-policy-external/feed/ 1 57630
Microsoft Hardens Authenticator App to Prevent MFA Fatigue https://office365itpros.com/2022/10/26/authenticator-app-mfa-fatigue/?utm_source=rss&utm_medium=rss&utm_campaign=authenticator-app-mfa-fatigue https://office365itpros.com/2022/10/26/authenticator-app-mfa-fatigue/#comments Wed, 26 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57643

Number Matching and Geographic Context Now GA for Authenticator App

Updated 20 February 2023

Eleven months after releasing the features to preview, Microsoft has made number matching and additional context generally available with the tag line of advanced Microsoft Authenticator security features. The capabilities are available for multi-factor authentication (MFA) flows now and will be available for passwordless flows soon.

In a nutshell, these features relieve the MFA fatigue some users experience when they process MFA challenges to sign into Microsoft 365 and other apps. Instead of blindly responding to a prompt or “simple approval” (which could be hijacked by an attacker – see MITRE Att&ck technique T1621), the user is forced to respond to the challenge by entering a matching number. This addresses the problem (as experienced in the recent Uber compromise) where an account holder responds to an MFA challenge without putting their brain in gear. MFA fatigue is a very real and current problem.

Additional context allows the Authenticator app to display information about the location of the sign-in and the app provoking the challenge. The extra information helps the user to understand if the sign-in that provoked the challenge is valid. Together, Microsoft says that number matching and additional context help organizations to “prevent accidental [user] approvals in Microsoft Authenticator.

New UI in Azure AD Admin Center

Tenants can roll the features out to all users or a targeted group, Microsoft has refreshed the UI in Authentication Methods section under Security in the Azure AD admin center (Figure1). You can also configure the settings with a Graph API request, but I wouldn’t bother. The Azure AD admin center does everything you need.

Settings for the Authenticator App in the Azure AD Admin Center
Figure 1: Settings for the Authenticator App in the Azure AD Admin Center

Microsoft planned to implement number matching for all Authenticator users in February 2023 but rescheduled the deployment date to May 8, 2023. At that point, Microsoft will remove the UI to enable or disable this feature from the Azure AD admin center. and all authentication challenges using the Authenticator app will require users to respond to generated numbers rather than the traditional Deny/Approve choice. This is part of Microsoft’s ongoing campaign to increase security by default across Microsoft 365.

Responding to a Non-Fatigued MFA Challenge

I found that it took about ten minutes before Azure AD implemented the updated settings in its challenges. The number challenge uses the same UI as the preview (Figure 2).

Azure AD issues a numeric MFA challenge
Figure 2: Azure AD issues a numeric MFA challenge

Figure 3 shows how the Microsoft Authenticator app (for iOS) prompts the user to enter the number requested by Azure AD. You can also see the additional geographic (based on the IP address of the device used for the sign-in) and application context presented to allow the user to judge if the sign-in is legitimate.

The Authenticator app (on iOS) prompts for the numeric challenge
Figure 3: The Authenticator app (on iOS) prompts for the numeric challenge

Speaking of Authenticator on iOS, Microsoft says that the app now uses App Transport Security (ATS) for improved privacy and data integrity between Authenticator and web services like the Microsoft 365 apps.

They also say that Authenticator on Android allows users to search their accounts and that this capability is coming to iOS “soon.” I use Authenticator for multiple Microsoft 365 tenants, my Microsoft consumer account, and applications like Twitter and GitHub, so searching will be a nice addition.

Changes Improve Authenticator’s Resistance to Attack

Why is number matching and additional context important for Authenticator? At the TEC 2022 conference, Alex Weinert, Microsoft VP for Identity Security, appealed for Microsoft 365 tenants to deploy multi-factor authentication more broadly (i.e., to increase the overall level of protection from the current 26.84% of user accounts). MFA protects more administrator accounts (34.15%), but that’s hardly a reason to celebrate.

During his TEC session, Alex discussed the updates now available for Authenticator and stressed how these made the app less susceptible to attack and less likely for its users to succumb to the human weakness seen in MFA fatigue. I imagine that with these updates, Microsoft now regards Authenticator as having the same authentication strength as Windows Hello and FIDO-2 keys.

The nice thing about the cloud is that changes like this roll-out without any intervention required on the part of tenants. It’s entirely in your hands to decide whether to take advantage and make MFA challenges more resistant to attack. It makes sense to do so.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/10/26/authenticator-app-mfa-fatigue/feed/ 5 57643
Report SSPR Status for Azure AD Accounts https://office365itpros.com/2022/10/20/azure-ad-sspr-accounts-not-enabled/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-sspr-accounts-not-enabled https://office365itpros.com/2022/10/20/azure-ad-sspr-accounts-not-enabled/#comments Thu, 20 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57562

Use Microsoft Graph PowerShell SDK Cmdlets to Report Accounts Not Yet Set Up for SSPR

A tweet by Nathan McNulty about the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet attracted my attention. The cmdlet generates a report about the registered authentication methods for Azure AD accounts. Nathan used the cmdlet to identify accounts that aren’t set up for self-service password reset (SSPR) by filtering the results to find only member accounts where the IsSSPRCapable property is set to False. SSPR is a premium Azure AD feature.

Get-MgReportAuthenticationMethodUserRegistrationDetail outputs filtered results, but two problems exist before the data is really usable. First, the default output for the cmdlet is user identifiers (GUIDs) instead of human-friendly display names for each account. Second, while the filter can isolate member accounts, it can’t refine the query further to drop accounts created for shared mailboxes, resource mailboxes, and other purposes. The first issue is resolved by explicitly selecting the userPrincipalName and userDisplayName properties for output; the second takes more work.

Exploring a Solution

One potential solution is illustrated below. The script uses the Get-MgUser cmdlet to find all accounts with at least one assigned license (the set of returned accounts can include those used for shared mailboxes). Information about account identifiers and display names are loaded into a hash table to make it possible to lookup an identifier very quickly. We can then loop through the set returned by Get-MgReportAuthenticationMethodUserRegistrationDetail and check each account against the hash table. If a match occurs, we know that we have a licensed account that isn’t currently enabled for self-service password result and can report that fact.

Although the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet can output user principal name and user display name properties, looking up the user account details against a table created by Get-MgUser allows us to drop the non-user accounts and lay the foundation for retrieving other data, as explained below. Here’s the code:

Connect-MgGraph -Scope Directory.Read.All, UserAuthenticationMethod.Read.All, AuditLog.Read.All
Select-MgProfile Beta

Write-Host "Finding licensed Azure AD accounts"
[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All
# Populate a hash table with the details
$UserTable = @{}
$Users.ForEach( { $UserTable.Add([String]$_.Id, $_.DisplayName) } )
Write-Host "Finding user accounts not capable of Self-Service Password Reset (SSPR)"
[array]$SSPRUsers = Get-MgReportAuthenticationMethodUserRegistrationDetail | Where-Object {$_.userType -eq 'member' -and $_.IsSSPRCapable -eq $False} | Select-Object Id, userDisplayName, userPrincipalName, DefaultMfaMethod, IsAdmin, IsMfaCapable, IsMfaRegistered, IsPasswordlessCapable, IsSSPRCapable         
Write-Host "Cross-checking against licensed users..."
[array]$NonSSPR = $Null
ForEach ($S in $SSPRUsers) {
  $DisplayName = $UserTable.Item($S.Id) 
  If ($DisplayName) {
     $NonSSPR += $DisplayName }
}
$PNonSSPR = ($NonSSPR.count/$Users.Count).toString("P")
Write-Host ("{0} out of {1} licensed accounts ({2}) are not enabled for Self-Service Password Reset" -f $NonSSPR.count, $Users.count, $PNonSSPR )
Write-Host ($NonSSPR -join ", ")

Only a list of account display names is output. When I ran the script in my tenant, the following output was generated:

Finding licensed Azure AD accounts
Finding user accounts not capable of Self-Service Password Reset (SSPR)
Cross-checking against licensed users...
23 out of 32 licensed accounts (71.88%) are not enabled for Self-Service Password Reset
Andy Ruth (Director), Ben James, Ben Owens (DCPG), Bruno Satlier, Chris Bishop, , Jackson Hoare, James Abrahams, Jeff Guillet, John C. Adams, Ken Bowers, Lotte Vetler, Marc Vigneau, Michael King, Paul Howett, Peter Bridges, Rene Artois, Sean Landy, Terry Hegarty, Tony Redmond (Office 365 for IT Pros), Vasil Michev (Technical Guru)…

Improving the Output

We can improve the output by including more information in the lookup table. A hash table is fast, but it’s limited to a key and a value, but the value can any PowerShell object. The hash table can then hold more information about each user. For example:

$UserTable = @{}
ForEach ($U in $Users) {
    $ReportLine  = [PSCustomObject] @{          
     Id                  = $U.Id
     DisplayName         = $U.DisplayName
     Department          = $U.Department
     Office              = $U.OfficeLocation  
     Country             = $U.Country
     }
    $UserTable.Add([String]$U.Id, $ReportLine) 
}

I’ve selected five properties for a user account. It’s easy to add more as necessary. With the hash table populated like this, we can grab the information from the PowerShell object in the value when a match occurs for an account and use it to build a nicer report.

ForEach ($S in $SSPRUsers) {
  $Data = $UserTable.Item($S.Id) 
  If ($Data) { # We found a match
     $ReportLine  = [PSCustomObject] @{  
       Id = $Data.Id
       DisplayName = $Data.DisplayName
       Department  = $Data.Department
       Office      = $Data.Office
       Country     = $Data.Country }
     $NonSSPRUsers.Add($ReportLine) }
}

Figure 1 shows the output of the report file.

Azure AD accounts that are not enabled for SSPR
Figure 1: A list of user accounts that don’t use SSPR

Checking Accounts Regularly

This is exactly the kind of check against user accounts that tenants might want to run regularly. A scheduled runbook executed by Azure Automation is a good way to process these kinds of operations and the code discussed here would move over easily to a runbook. In the interim, here’s the link to the full script in GitHub for you to improve and enhance it as you like.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/10/20/azure-ad-sspr-accounts-not-enabled/feed/ 7 57562
Updating Microsoft 365 User Accounts to use a New Domain https://office365itpros.com/2022/10/18/update-user-email-upns/?utm_source=rss&utm_medium=rss&utm_campaign=update-user-email-upns https://office365itpros.com/2022/10/18/update-user-email-upns/#comments Tue, 18 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57481

Update User Email Addresses and User Principal Names

A recent reader question asked about the best way to update a bunch of user accounts after the organization buys a new vanity domain and wants the domain used for email addresses and user principal names (sign-in addresses). This sometimes happens when a business goes through a rebranding exercise and ends up with a new name. The requirement to update email addresses and user principal names also occurs in tenant-to-tenant migrations.

Tenant-to-tenant migrations are a specialized kind of activity that’s usually managed with software built for this purpose. We won’t plunge into the challenges that these projects can encounter. Instead, we’ll focus on the scenario where someone in authority decides that all accounts should use different email addresses and user principal names.

Registered Domains

The first requirement is to add the domain to Office 365. Until this is done, you cannot use the domain. Once the domain is known to the tenant, it appears in the set of verified domains seen in the Microsoft 365 admin center (Figure 1).

Verified domains in a Microsoft 365 tenant.
Figure 1: Verified domains in a Microsoft 365 tenant

After verifying the domain for Microsoft 365, we can write some code to ask the administrator what domain to use. Here’s an example that uses the Get-MgOrganization cmdlet from the Microsoft Graph PowerShell SDK to fetch the verified domains:

Connect-MgGraph -Scopes Directory.Read.All, User.ReadWrite.All
# Get tenant information and the verified domains for the tenant
$TenantInfo = (Get-MgOrganization)
[array]$Domains = $TenantInfo.VerifiedDomains.Name
$DomainsList = $Domains -join ", "
Write-Host "Verified domains for this tenant:"
Write-Host "---------------------------------"
Write-Host ""
$Domains
Write-Host ""
$DomainToUse = Read-Host "What domain do you want to use for primary SMTP addresses and UPNs"
Write-Host ""
If ($DomainToUse -notin $Domains) {Write-Host ("The selected domain ({0}) is not in the set supported by the tenant ({1}). Please try again." -f $DomainToUse, $DomainsList); break }
$CompareDomain = "*" + $DomainToUse + "*"

Finding Mail Recipients

The next step is to find mail-enabled recipients that have email addresses that might need updating. This code finds user mailboxes, shared mailboxes, group mailboxes (for Microsoft 365 groups), distribution lists, and security-enabled distribution lists.

For each object, the code calculates a new primary SMTP address based on their existing address by swapping the existing domain for the new domain. A check makes sure that the new address isn’t already in use, and if it is, creates a new address by adding “.EXO” to the username. The code then checks if it’s necessary to update the user principal name for the Entra ID accounts used by user mailboxes and shared mailboxes. An account might already use the new domain, so the code checks the account’s current user principal name and updates it with the new domain if necessary.

The output is captured in a PowerShell list that’s exported to a CSV file.

If (!($DomainToUse)) {
   Write-Host "No domain to move to is defined. Please make sure that the $DomainToUse variable is defined"
   Break
} Else {
   Write-Host ("Processing accounts to move them to the {0} domain..." -f $DomainToUse)
}

[array]$Recipients = Get-Recipient -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox, GroupMailbox, MailUniversalDistributionGroup, MailUniversalSecurityGroup, DynamicDistributionGroup

$i = 0
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($R in $Recipients) {
     $i++
     If ($R.PrimarySmtpAddress.Split("@")[1] -ne $DomainToUse) { #Need to process this mailbox
      Write-Host ("Processing {0} {1} ({2}/{3})" -f $R.RecipientTypeDetails, $R.DisplayName, $i, $Recipients.Count)
      $NewUPN = $Null
      # Figure out new email address
      $NewAddress = $R.Alias + "@" + $DomainToUse
      # Check that the address is available
      $Status = Get-Recipient -Identity $NewAddress -ErrorAction SilentlyContinue
      # If we get a status the recipient address already exists, so create a new address
      If ($Status) { $NewAddress = $M.Alias + ".EXO@" + $DomainToUse }
      
      # Figure out if the account's user principal name needs to change
      If ($R.RecipientType -eq "SharedMailbox" -or $R.RecipientType -eq "UserMailbox") {
        $UPNDomain = $R.WindowsLiveId.Split("@")[1]
        If ($UPNDomain -ne $DomainToUse) { # New UPN needed
          $NewUPN = $R.WindowsLiveId.Split("@")[0] + "@" + $DomainToUse
          $Status = Get-MgUser -UserId $NewUPN -ErrorAction SilentlyContinue
          If ($Status) { # UPN already exists, so create a new one
            $NewUPN = $R.WindowsLiveId.Split("@")[0] + ".EXO@" + $DomainToUse }
          }
       }

      $ReportLine   = [PSCustomObject] @{ 
         DisplayName            = $R.DisplayName
         OldUPN                 = $R.WindowsLiveId
         NewUPN                 = $NewUPN
         PrimarySmtpAddress     = $R.PrimarySmtpAddress
         NewAddress             = $NewAddress
         Type                   = $R.RecipientTypeDetails
         Alias                  = $R.Alias
    }
    $Report.Add($ReportLine) }
}
$Report = $Report | Sort-Object Type
$Report | Export-CSV -NoTypeInformation c:\temp\MailObjects.Csv

Administrators can check the CSV to remove any mail-enabled recipients they don’t want to receive new email addresses (Figure 2).

Update User Email Addresses with a New Domain

The next step is reads in and processes an array of objects from the updated CSV file.

The code uses a Switch statement to check the object type and calls the appropriate cmdlet to assign the new primary SMTP address to the object. If the account used for a mailbox (user or shared) requires an update for its user principal name, we go ahead and do it.

The final step in the loop through the objects is to report what’s been done, noting the old and new SMTP address and the old and new user principal name.

# Process mail objects array to update primary SMTP addresses and UPNs as necessary
[array]$MailObjects = Import-CSV MailObjects.CSV
$Report = [System.Collections.Generic.List[Object]]::new()

Write-Host "Processing mail-enabled objects..."
$i = 0
ForEach ($M in $MailObjects)  {
   $i++
   Write-Host ("Processing {0} {1} ({2}/{3})" -f $M.Type, $M.DisplayName, $i, $MailObjects.Count)

   # Assign new primary SMTP Address
   Switch ($M.Type) {
      "DynamicDistributionGroup" { # Dynamic distribution list
        Set-DynamicDistributionGroup -Identity $M.PrimarySmtpAddress -PrimarySmtpAddress $NewAddress
     }
      "GroupMailbox" { # Microsoft 365 group
        Set-UnifiedGroup -Identity $M.PrimarySmtpAddress -PrimarySmtpAddress $NewAddress
     }
      "MailUniversalDistributionGroup" { # Distribution list
        Set-DistributionGroup -Identity $M.PrimarySmtpAddress -PrimarySmtpAddress $NewAddress
     }
      "MailUniversalSecurityGroup" { #Mail-enabled security group
        Set-DistributionGroup -Identity $M.PrimarySmtpAddress -PrimarySmtpAddress $NewAddress
     }
      "SharedMailbox" { # Shared mailbox
        Set-Mailbox -Identity $M.PrimarySmtpAddress -WindowsEmailAddress $NewAddress 
     }
      "UserMailbox" { # User mailbox
        Set-Mailbox -Identity $M.PrimarySmtpAddress -WindowsEmailAddress $NewAddress 
     }
    }

   # Update UPN if necessary
   If ($M.NewUPN) {  
     Update-MgUser -UserId $M.UPN -UserPrincipalName $M.NewUPN }

   $ReportLine   = [PSCustomObject] @{ 
          DisplayName            = $M.DisplayName
          OldUPN                 = $M.UPN
          NewUPN                 = $M.NewUPN
          OldPrimarySmtpAddress  = $M.PrimarySmtpAddress
          NewPrimarySmtpAddress  = $M.NewAddress
          Type                   = $M.Type
          Alias                  = $M.Alias
    }
    $Report.Add($ReportLine) 

} # End ForEach 
Write-Host "All done!"

Figure 3 shows an example of the report that allows administrators to check that the expected email addresses and user principal names are in place.

The updated accounts with new primary SMTP addresses and some new user principal names
Figure 3: The updated accounts with new primary SMTP addresses and some new user principal names

The User Issue

Updated user principal names take effect the next time users sign in. If you want to force the switchover, you could disconnect users from their current sessions by invalidating refresh tokens using the Graph revokeSignInSessions API. Invaliding access tokens forces users to reauthenticate and reconnect, and to do that, they must use their new user principal names.

Be aware that some issues exist when changing user principal names such as the need to set up the new user principal name on the Microsoft Authenticator app so that MFA challenges work It’s worthwhile reading through this Microsoft article to understand and test problems that users might encounter in your organization. Knowing what might happen and being prepared to fix the issues will ensure a smoother transition.

Any change to the way people sign-in is likely to cause some angst if it’s not communicated clearly so that everyone understands why the change is happening and what they must do to sign-in to access services.

Tidying Up Entra ID

The process outlined above takes care of the bulk of the work. If some Entra ID accounts that don’t have email addresses need to receive updated user principal names, you can do this with the Update-MgUser cmdlet from the Microsoft Graph PowerShell SDK.

Giving accounts new email addresses and user principal names isn’t a difficult technical challenge. The likely problems arise in preparation and communication. Isn’t that always the way?


Keep up with the changing world of the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. Monthly updates mean that our subscribers learn about new developments as they happen.

]]>
https://office365itpros.com/2022/10/18/update-user-email-upns/feed/ 15 57481
Reporting Who Made License Assignments https://office365itpros.com/2022/10/14/azure-ad-license-assignment-report/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-license-assignment-report https://office365itpros.com/2022/10/14/azure-ad-license-assignment-report/#comments Fri, 14 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57437

Who Performed an Azure AD License Assignment?

After writing about how to detect underused (and expensive) licenses assigned to Azure AD accounts, I was asked if it was possible to report who assigned a license to accounts. It’s a good question that stumped me for a moment. There’s no obvious off-the-shelf indication of who assigned licenses to accounts in any Microsoft 365 administrative interface.

Azure AD Audit Data

License assignment is an Azure AD activity. It’s therefore possible to find information about these actions in the Azure AD audit log by searching for “Change user license” events. Unfortunately, these events only note that some sort of license assignment occurred. It doesn’t tell you what happened to licenses in terms of additions, removals, or disabling service plans in licenses. For that information, you need to find a matching “Update user” event where the license assignment detail is captured in the Modified Properties tab (Figure 1).

Azure AD license assignment details in the audit log
Figure 1: Azure AD license assignment details in the audit log

Unfortunately, the Get-MgAuditLogDirectoryAudit cmdlet doesn’t report the same level of detail about license assignments, so the Azure AD audit log isn’t a good source for reporting.

License Assignment Records in the Unified Audit Log

Azure AD is a source for the Office 365 (unified) audit log and the information ingested into the Office 365 audit log is more comprehensive albeit formatted in such a way that the data isn’t easy to fetch. However, we can find enough data to write a PowerShell script to create a basic report that contains enough information to at least give administrators some insight into who assigns licenses.

To create the report, the script:

  • Ran the Search-UnifiedAuditLog cmdlet to retrieve audit records for the Change user license and Update User actions.
  • Create separate arrays for both types of event.
  • For each Change user license event, see if there’s a matching Update user record. If one is found, extract the license assignment information from the record.
  • Report what’s been found.

Here’s the script to prove that the concept works:

# Azure AD license assignment script
$StartDate = (Get-Date).AddDays(-90)
$EndDate = (Get-Date).AddDays(1)
Write-Host "Searching for license assignment audit records"
[array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Formatted -ResultSize 5000 -Operations "Change user license", "Update User" -SessionCommand ReturnLargeSet
If (!($Records)) { Write-Host "No audit records found... exiting... " ; break}

Write-Host ("Processing {0} records" -f $Records.count)
$Records = $Records | Sort-Object {$_.CreationDate -as [datetime]} -Descending
[array]$LicenseUpdates = $Records | Where-Object {$_.Operations -eq "Change user license."}
[array]$UserUpdates = $Records | Where-Object {$_.Operations -eq "Update user."}

$Report = [System.Collections.Generic.List[Object]]::new()

ForEach ($L in $LicenseUpdates) {
  $NewLicenses = $Null; $OldLicenses = $Null; $OldSkuNames = $Null; $NewSkuNames = $Null
  $AuditData = $L.AuditData | ConvertFrom-Json
  $CreationDate = Get-Date($L.CreationDate) -format s
  [array]$Detail = $UserUpdates | Where-Object {$_.CreationDate -eq $CreationDate -and $_.UserIds -eq $L.UserIds}
  If ($Detail) { # Found a user update record
     [int]$i = 0
     $LicenseData = $Detail[0].AuditData | ConvertFrom-Json
     [array]$OldLicenses = $LicenseData.ModifiedProperties | Where {$_.Name -eq 'AssignedLicense'} | Select-Object -ExpandProperty OldValue | Convertfrom-Json
     If ($OldLicenses) {
        [array]$OldSkuNames = $Null
        ForEach ($OSku in $OldLicenses) {
           $OldSkuName = $OldLicenses[$i].Substring(($OldLicenses[$i].IndexOf("=")+1), ($OldLicenses[$i].IndexOf(",")-$OldLicenses[$i].IndexOf("="))-1)
           $OldSkuNames += $OldSkuName
           $i++
         }
      $OldSkuNames = $OldSkuNames -join ", "
    }
    [array]$NewLicenses = $LicenseData.ModifiedProperties | Where {$_.Name -eq 'AssignedLicense'} | Select-Object -ExpandProperty NewValue | Convertfrom-Json
    If ($NewLicenses) {
        $i = 0
        [array]$NewSkuNames = $Null
        ForEach ($N in $NewLicenses) {
           $NewSkuName = $NewLicenses[$i].Substring(($NewLicenses[$i].IndexOf("=")+1), ($NewLicenses[$i].IndexOf(",")-$NewLicenses[$i].IndexOf("="))-1)
           $NewSkuNames += $NewSkuName
           $i++
         }
      $NewSkuNames = $NewSkuNames -join ", "
    }

  } # end if
  # Make sure output properties are strings
  [string]$NewLicensesOutput = $NewLicenses
  [string]$OldLicensesOutput = $OldLicenses
  [string]$NewSkuNamesOutput = $NewSkuNames
  [string]$OldSkuNamesOutput = $OldSkuNames
  $ReportLine   = [PSCustomObject] @{ 
     Operation      = $AuditData.Operation
     Timestamp      = Get-Date($AuditData.CreationTime) -format g
     'Assigned by'  = $AuditData.UserId
     'Assigned to'  = $AuditData.ObjectId 
     'Old SKU'      = $OldSkuNamesOutput
     'New SKU'      = $NewSkuNamesOutput
     'New licenses' = $NewLicensesOutput
     'Old licenses' = $OldLicensesOutput
  }
  $Report.Add($ReportLine)
}

$Report = $Report | Sort-Object {$_.TimeStamp -as [datetime]} 
$Report | Out-GridView

The output is sparse (Figure 2) but I reckon it is sufficient to understand what happens when a license assignment occurred. Events without any license detail appear to be when an administrator removes a license from an account or a service plan from a license.

Azure AD license assignment data extracted from the Office 365 audit log
Figure 2: License assignment data extracted from the Office 365 audit log

I didn’t bother attempting to parse out the license detail. The information returned by Azure AD includes all the licenses assigned to an account, so you’d end up with something like this for an account with three licenses. Splitting the individual licenses and disabled service plans out from this information is an exercise for the reader.

$NewLicenses.Split(',')
[SkuName=POWER_BI_STANDARD
 AccountId=a662313f-14fc-43a2-9a7a-d2e27f4f3478
 SkuId=a403ebcc-fae0-4ca2-8c8c-7a907fd6c235
 DisabledPlans=[]]
[SkuName=ENTERPRISEPACK
 AccountId=a662313f-14fc-43a2-9a7a-d2e27f4f3478
 SkuId=6fd2c87f-b296-42f0-b197-1e91e994b900
 DisabledPlans=[]]
[SkuName=TOPIC_EXPERIENCES
 AccountId=a662313f-14fc-43a2-9a7a-d2e27f4f3478
 SkuId=4016f256-b063-4864-816e-d818aad600c9
 DisabledPlans=[]]

Principle Proved

In any case, the answer to the question is that it’s possible to track and report Azure AD license assignments by using the audit log to extract events relating to these actions and parsing the information in the events. The resulting output might not be pretty (but could be cleaned up), but it’s enough to prove the principal.


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/10/14/azure-ad-license-assignment-report/feed/ 16 57437
Making Sure Apps Can Run Exchange Online Management Cmdlets https://office365itpros.com/2022/10/13/exchange-online-powershell-app/?utm_source=rss&utm_medium=rss&utm_campaign=exchange-online-powershell-app https://office365itpros.com/2022/10/13/exchange-online-powershell-app/#comments Thu, 13 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57424

Using the Exchange.ManageAsApp Permission with Exchange Online PowerShell

Updated 7 December 2022

With the addition of support for managed identities in V3.0 of the Exchange Online management PowerShell module, developers might be more interested in creating Azure Automation runbooks that use the Exchange Online cmdlets to process data like mailboxes. In this discussion, when I refer to a managed identity, I mean a system-assigned managed identity working within an Azure Automation Account. Essentially, a managed identity is a service principal used to access Azure resources that Azure manages automatically. No access is available to the credentials for the managed identity. Like the service principals for other apps, managed identity service principals can hold permissions to allow them access to resources like apps.

As an example, it’s now easy to connect to Exchange Online in a runbook with a command like:

Connect-ExchangeOnline -ManagedIdentity -Organization office365itpros.onmicrosoft.com 

Exchange Online connects using the managed identity owned by the Azure Automation account that’s executing the runbook.

As noted above, before it can do anything interesting after connecting, the managed identity needs permissions. The essential permission for Exchange Online is Exchange.ManageAsApp, which allows an app to run Exchange Online cmdlets as if the app was an administrator account. Service principals for registered apps and managed identities both need this permission to do useful work with Exchange Online cmdlets.

Some Background

In November 2020, Microsoft announced the deprecation of the Outlook REST API. This was part of a wider effort to move developers away from legacy APIs to the Graph. Microsoft also considers Exchange Web Services (EWS) to be a legacy API, but in this instance, the Exchange team focused on the Outlook REST API, which the Graph Outlook Mail API replaces.

At the same time, Microsoft said that they “removed the Exchange app permission from the Azure portal.” The Exchange.ManageAsApp permission is one of the permissions in the Office 365 Exchange Online API. Microsoft’s action didn’t remove the ability to assign the permission to apps in the Azure AD admin center. It just made the process a little harder.

Assigning Exchange.ManageAsApp

To assign the Exchange.ManageAsApp permission to a registered app, select the app in the Registered Apps blade. Go to API permissions to add a permission as normal. When Azure AD displays the range of permissions to select from, click the APIs my organization uses tab, and then type Office 365 Exchange Online into the search box. Azure AD will find the Office 365 Exchange Online API (Figure 1). Note the application identifier shown here. We’ll need this later.

Finding the Office 365 Exchange Online API
Figure 1: Finding the Office 365 Exchange Online API

Now browse the set of permissions in the Office 365 Exchange Online API and select Exchange.ManageAsApp (Figure 2). Make sure that you’ve selected application permissions and click Add permission. When you return to the app details, consent to the assignment, just like you’d do for a Graph API permission.

Adding the Exchange.ManageAsApp permission
Figure 2: Adding the Exchange.ManageAsApp permission

The registered app can now run Exchange Online cmdlets as an administrator. That’s all well and good, but what about a managed identity?

Managed Identities are Different

Unlike registered apps, managed identities show up under the enterprise apps section of the Azure AD admin center. Open enterprise apps and apply a filter to find managed identities (Figure 3).

Selecting managed identities in the Azure AD admin center
Figure 3: Selecting managed identities in the Azure AD admin center

Azure AD lists the Azure automation accounts with managed identities. Select the automation account you want to work with. When you access its permissions, Azure AD tells you that: “The ability to consent to this application is disabled as the app does not require consent. Granting consent only applies to applications requiring permissions to access your resources.” In other words, you can’t assign an API to an automation account, or rather the service principal for the managed identity, through the Azure AD admin center.

Instead, you can do the job with PowerShell using cmdlets from the Microsoft Graph PowerShell SDK. Here’s how:

  • Note the name of the automation account used with the managed identity. In this example, the account name is “ExoAutomationAccount.”
  • Connect to the Graph with the AppRoleAssignment.ReadWrite.All permission.
  • Run the Get-MgServicePrincipal cmdlet to populate a variable with the service principal for the automation account. The filter passed to the cmdlet contains the name of the automation account.
  • Populate a variable with details of the Office 365 Exchange Online enterprise app. Microsoft installs this app for tenants to allow administrative apps to manage Exchange. The app id for the Office 365 Exchange Online app is always 00000002-0000-0ff1-ce00-000000000000.
  • Find the Manage Exchange As Application role in the set held by the Exchange Online application. This role holds the Exchange.ManageAsApp permission, so any app holding the role can use the permission.
  • Create the parameters to assign the role to the managed identity.
  • Use the New-MgServicePrincipalRoleAssignment cmdlet to assign the role.

Connect-MgGraph -Scopes AppRoleAssignment.ReadWrite.All
Select-MgProfile Beta
$ManagedIdentityApp = Get-MgServicePrincipal -Filter "displayName eq 'ExoAutomationAccount'"
$ExoApp = Get-MgServicePrincipal -Filter "AppId eq '00000002-0000-0ff1-ce00-000000000000'"
$AppPermission = $ExoApp.AppRoles | Where-Object {$_.DisplayName -eq "Manage Exchange As Application"}
$AppRoleAssignment = @{
"PrincipalId" = $ManagedIdentityApp.Id
"ResourceId" = $ExoApp.Id
"AppRoleId" = $AppPermission.Id
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ManagedIdentityApp.Id -BodyParameter $AppRoleAssignment

The new role assignment is effective immediately. If you make a mistake, you can remove the assignment with the Remove-MgServicePrincipalAppRoleAssignment cmdlet. Here’s how:

[Array]$SPPermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ManagedIdentityApp.Id
$Role = $ExoApp.AppRoles | Where-Object {$_.DisplayName -eq "Manage Exchange As Application"}
$Assignment = $SpPermissions | Where-Object {$_.AppRoleId -eq $Role.Id}
Remove-MgServicePrincipalAppRoleAssignment -AppRoleAssignmentId $Assignment.Id -ServicePrincipalId $ManagedIdentityApp.Id

Administrator Role

The final step is to make sure that Exchange Online recognizes the automation account which hosts the managed identity as an Exchange administrator. This is done by assigning the Exchange Administrator role to the automation account’s app in the Azure AD admin center. Figure 4 shows how to add the assignment of the Exchange administrator role to the app owned by an automation account.

Making sure that the Managed Identity can act as an Exchange administrator
Figure 4: Making sure that the Managed Identity can act as an Exchange administrator

If you don’t assign the Exchange administrator role to the automation account’s app, you’ll see an error telling you that the role assigned to the app isn’t supported in this scenario when you execute the runbook. For example:

The role assigned to application 415e4ba8-635f-4689-b069-22dea1fcfdb3 isn’t supported in this scenario

Assignment a Small Pain

Perhaps Microsoft under-estimated the continuing need to assign the Exchange.ManageAsApp permission to apps when they made their November 2020 announcement. Although it’s a pain to have to go to PowerShell to assign the permission, it’s something that only needs to happen once, so it’s not too bad. I have other more serious things to moan about inside Microsoft 365.


Learn more about how the Microsoft 365 ecosystem really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/10/13/exchange-online-powershell-app/feed/ 10 57424
Microsoft Introduces Authentication Strength for Conditional Access Policies https://office365itpros.com/2022/10/10/authentication-strength-ca-policies/?utm_source=rss&utm_medium=rss&utm_campaign=authentication-strength-ca-policies https://office365itpros.com/2022/10/10/authentication-strength-ca-policies/#comments Mon, 10 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57394

Allows CA Policies to Differentiate Between MFA Methods

Building off yesterday’s discussion about Azure AD authentication methods and the discussion at the TEC 2022 conference about the need to do better with MFA, Microsoft released an important improvement to MFA effectiveness this week by enhancing conditional access policies with authentication strength for MFA challenges.

Last year, Microsoft added number matching and additional context to the Authenticator app to help address the issue of MFA fatigue. This is when people mindlessly respond to MFA prompts without registering what they’re doing, something that attackers can exploit to compromise user accounts. However, even if people pay attention to MFA prompts, there’s no doubt that SMS-based challenges deliver weaker protection than other methods.

Expanding Conditional Access Policies

Conditional access (CA) policies operate by applying rules to connections to determine if a user can connect to the requested resource. For example, can they access an Office 365 application like OWA. Combined with authentication policies, CA policies can severely limit the ability of an attacker to compromise user accounts and stop incidents like the OAuth exploit against Exchange Online recently reported by the Microsoft 365 Defender Research Team.

CA policies have been able to insist that accounts use MFA for many years. Up to now, one kind of MFA has been as good as another. Microsoft now differentiates the strength of authentication gained through the available methods (Figure 1).

Azure AD authentication methods (source: Microsoft)
Figure 1: Azure AD authentication methods (source: Microsoft)

SMS is graded at medium level and its usability is high because most people have smartphones. I’m not quite sure why it shows up as medium availability. Microsoft defines this as “an indication of the user being able to use the authentication method, not of the service availability in Azure AD”. Most people I know are very able to use SMS given that it’s a messaging capability in general use since the mid-1990s.

In any case, Microsoft acknowledges the problems with SMS when it responds to an authentication challenge, and they want to encourage people to use more secure methods. In reality, this means that Microsoft wants people to use their Authenticator app, Windows Hello, or FIDO2 key.

Using Authentication Strength in CA Policies

To test the new capability, I created a CA policy to control access to Office 365 and set the policy to grant access based on the authentication strength of the user connection. The default strength is multifactor authentication, meaning any of the traditional methods like SMS will satisfy the condition. I selected the next step up, requiring the use of passwordless MFA (Figure 2).

electing authentication strength in a Conditional Access policy
Figure 2: Selecting authentication strength in a Conditional Access policy

The strongest method is phishing-resistant multifactor authentication. Using a FIDO2 key satisfies this requirement. At TEC 2022, Alex Weinert, Microsoft’s VP for Identity Security, said that the Authenticator app will meet this requirement “soon.”

Note the warning about cross-tenant access settings. These are the Azure AD Direct Connect policies that underpin Teams shared channels. A cross-tenant access policy setting controls if your tenant accepts the multifactor authentication performed by the home tenants of external users who participate in shared channels in your tenant. You should accept those claims to allow external users to continue to collaborate even if they don’t measure up to the authentication strength required for tenant users.

Effect of Authentication Strength

The effectiveness of authentication strength was immediate. Users configured to use the authenticator app continued have access while those who used SMS were allowed to connect and told to select a new authentication method (Figure 3).

A user with SMS-based MFA is invited to upgrade their authentication strength
Figure 3: A user with SMS-based MFA is invited to upgrade their authentication strength

In Figure 3, Azure AD shows that a FIDO2 key is the only available method. This was because the user account had the authenticator method but it needed to be fully configured. Once this was done, the user could connect successfully.

Like any other authentication failure due to a CA policy, details of the failed connection are in the Azure AD sign-in log (Figure 4).

Azure AD audit log failure event due to authentication strength failing a CA policy test
Figure 4: Azure AD audit log failure event due to authentication strength failing a CA policy test

Heading to the Sunny Highlands of Secure MFA

It will be interesting to see how many organizations try to move users away from SMS-based MFA to more secure authentication methods. Just because Microsoft wants this to happen is no reason why it will in the real world. Some customers will love the new capability and rush to embrace it, but I suspect that the real challenge that needs to be fought first is to increase the current percentage of Azure AD accounts protected by MFA from 26.64% to well north of 50%. After killing basic password authentication and pausing for a breath, moving to really secure MFA might be the next hill to climb.


Stay updated with developments across the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. We do the research to make sure that our readers understand the technology.

]]>
https://office365itpros.com/2022/10/10/authentication-strength-ca-policies/feed/ 5 57394
Deep Dive into Entra ID Authentication Methods https://office365itpros.com/2022/10/07/authentication-methods-scripts/?utm_source=rss&utm_medium=rss&utm_campaign=authentication-methods-scripts https://office365itpros.com/2022/10/07/authentication-methods-scripts/#respond Fri, 07 Oct 2022 01:00:00 +0000 https://office365itpros.com/?p=57366

Managing Authentication Methods for an Entra ID User Account with PowerShell

Microsoft product manager Merill Fernando (of Graph X-Ray fame) posted an interesting tweet about a script he wrote to remove all the authentication methods from a user account. Entra ID supports a wide range of authentication methods (Figure 1) ranging from the classic username/password combination to using the Microsoft Authenticator app.

Entra ID Authentication Methods (source: Microsoft).
Figure 1:Entra ID Authentication Methods (source: Microsoft)

At the recent TEC conference, Microsoft VP for Identity Security Alex Weinert made a passionate plea for more Microsoft 365 tenants to secure their accounts with MFA. It’s shocking that only 26.64% of all user accounts use MFA. The figure for accounts holding an administrative role is higher at 34.15%, but that’s still poor. We need to do a better job of moving accounts to the right-hand methods shown in Figure 1.

Scripting Authentication Methods

Merill acknowledges that the script “is not pretty” because the Microsoft Graph does not currently support a way to find the default authentication method for an account. In short, the script attempts to delete an authentication method and if it fails it assumes that the method (like the Microsoft Authenticator app) is the default and leaves it to the last. You can only remove the default authentication method from an account if it’s the last and only method.

In any case, it’s a good script to have around just in case you need to reset an account. I’m not sure how often you’d want to do this, but I guess you might. All contributions to the admin toolbox are gratefully received.

Authentication Methods and the Microsoft Graph PowerShell SDK

Merill’s script uses cmdlets from the Microsoft Graph PowerShell SDK. I like the PowerShell SDK a lot, but sometimes it goes overboard in terms of the number of cmdlets it uses. I think this is due to the way that Microsoft generates the SDK modules and cmdlets from Graph APIs using a process called AutoRest. It’s nice to have a way to generate code automatically, but sometimes human intelligence could do better. Usually, Microsoft generates a new version of the SDK monthly, but sometimes errors creep in and several versions appear in a month (this just happened when versions 1.12 had several minor updates (current version is 1.12.3).

For instance, every authentication method has a separate cmdlet to add (New), update, and remove it from an account. The set of cmdlets used to remove methods in Merill’s script is:

  • Remove-MgUserAuthenticationFido2Method
  • Remove-MgUserAuthenticationEmailMethod
  • Remove-MgUserAuthenticationMicrosoftAuthenticatorMethod
  • Remove-MgUserAuthenticationPhoneMethod
  • Remove-MgUserAuthenticationSoftwareOathMethod
  • Remove-MgUserAuthenticationTemporaryAccessPassMetho
  • Remove-MgUserAuthenticationWindowHelloForBusinessMethod

Seven different cmdlets (you can’t remove the classic password method with one of these cmdlets), or 21 when you add the others for adding and updating methods. It would be simpler all round if the SDK consolidated everything so that we had one cmdlet to add, one to update, and one to remove authentication methods. However, I suspect that because separate API requests exist for each method, we are condemned to work with a confusing mass of cmdlets.

Reporting Authentication Methods

I decided that it would be a good idea to find out what authentication methods are in use. Microsoft makes this information available in the Entra ID admin center, but it’s no fun to simply accept what Microsoft wants to deliver in an admin portal. Instead, if we understand how the technology works, we can adapt it for our own purposes. For instance, I want to focus on tenant accounts rather than including guest accounts in the mix, and I want to extract some information about each authentication method to include in the report.

I already have a script to create an Authentication Method Report for Entra ID and another script to report administrator accounts that aren’t protected with MFA, but there’s always room for another (and this version extracts a little more information about each authentication method, like the phone number used for SMS challenges). Here are the important bits of the code (the full script is available from GitHub):

Write-Host "Finding licensed user accounts"
[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All
If (!($Users)) { Write-Host "No licensed users found... exiting!"; break }

$i = 0
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($User in $Users) {
 $i++
 Write-Host ("Processing user {0} {1}/{2}." -f $User.DisplayName, $i, $Users.Count)
 $AuthMethods = Get-MgUserAuthenticationMethod -UserId $User.Id
 ForEach ($AuthMethod in $AuthMethods) {
  $P1 = $Null; $P2 = $Null
  $Method = $AuthMethod.AdditionalProperties['@odata.type']
  Switch ($Method) {
     "#microsoft.graph.passwordAuthenticationMethod" {
       $DisplayMethod = "Password"
       $P1 = "Traditional password"
     }
     "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod" {
       $DisplayMethod = "Authenticator" 
       $P1 = $AuthMethod.AdditionalProperties['displayName']
       $P2 = $AuthMethod.AdditionalProperties['deviceTag'] + " " + $AuthMethod.AdditionalProperties['phoneAppVersion'] 
     }
     "#microsoft.graph.fido2AuthenticationMethod" {
       $DisplayMethod = "Fido 2 Key"
       $P1 = $AuthMethod.AdditionalProperties['displayName']
       $P2 = Get-Date($AuthMethod.AdditionalProperties['createdDateTime']) -format g
     }
     "#microsoft.graph.phoneAuthenticationMethod" {
       $DisplayMethod = "Phone" 
       $P1 = "Number: " + $AuthMethod.AdditionalProperties['phoneNumber']
       $P2 = "Type: " + $AuthMethod.AdditionalProperties['phoneType']
     }
    "#microsoft.graph.emailAuthenticationMethod" {
      $DisplayMethod = "Email"
      $P1 = "Address: " + $AuthMethod.AdditionalProperties['emailAddress']
     }
    "#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod" {
      $DisplayMethod = "Passwordless"
      $P1 = $AuthMethod.AdditionalProperties['displayName']
      $P2 = Get-Date($AuthMethod.AdditionalProperties['createdDateTime']) -format g
    }
  }
  
  $ReportLine   = [PSCustomObject] @{ 
     User   = $User.DisplayName
     Method = $DisplayMethod
     Id     = $AuthMethod.Id
     P1     = $P1
     P2     = $P2 
     UserId = $User.Id }
  $Report.Add($ReportLine)
 } #End ForEach Authentication Method
} #End ForEach User

The code doesn’t include choices for every possible authentication method because examples aren’t available in my tenant. It’s easy to update the code to handle a method like the temporary pass. Figure 2 shows the output generated by the script.

Listing authentication methods found for Entra ID user accounts.
Figure 2: Listing authentication methods found for Entra ID user accounts

One thing that puzzles me is why my account has multiple methods listed for the Microsoft Authenticator app. Both relate to my iPhone 11, but Entra ID might have created the second record after I renamed the phone. It’s something to look at when the time is available.

You can analyze the data to get further insights. For instance:

Write-Host ""
Write-Host "Authentication Methods found"
Write-Host "----------------------------"
Write-Host ""
$Report | Group-Object Method | Sort-Object Count -Descending | Select Name, Count
Authentication Methods found
----------------------------

Name          Count
----          -----
Password         33
Phone            21
Email            11
Authenticator     5
Fido 2 Key        2
Passwordless      1

The other scripts show how to deal with other aspects of reporting that might be important to you, like checking accounts for administrative roles, date of last sign-in, and so on. The nice thing about PowerShell is its flexibility. Cut and paste from different scripts to create a new take and meet your requirements. That’s a great capability to have.


Learn more about how Entra ID and the Microsoft 365 applications really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/10/07/authentication-methods-scripts/feed/ 0 57366
Detect Underused Entra ID Accounts (with Expensive Licenses) https://office365itpros.com/2022/09/29/underused-accounts-report/?utm_source=rss&utm_medium=rss&utm_campaign=underused-accounts-report https://office365itpros.com/2022/09/29/underused-accounts-report/#comments Thu, 29 Sep 2022 01:00:00 +0000 https://office365itpros.com/?p=57256

Update the Microsoft 365 Licensing Report Script to Find Underused Accounts

In October 2021, I wrote about how to use the Microsoft Graph PowerShell SDK to create a licensing report for a Microsoft 365 tenant. That report lists the licenses assigned to each user account together with any disabled service plans for those licenses. It’s a valuable piece of information to help tenants manage license costs.

But we can do better. At least, that’s what some readers think. They’d like to know if people use their assigned licenses so that they can remove expensive licenses from accounts that aren’t active. One way to approach the problem is to use the Microsoft 365 User Activity Report script to identify people who haven’t been active in Exchange Online. SharePoint Online, Teams, OneDrive for Business, and Yammer over the last 180 days. The report already includes an assessment of whether an account is in use, so all you need to do is find those who aren’t active and consider removing their licenses.

Another solution to the problem is to update the licensing report script. To do this, I made several changes to the script (the updated version is available from GitHub).

Filtering for Licensed Accounts

The first change is to the filter used with the Get-MgUser cmdlet. The new filter selects only member accounts that have licenses. Previously, I selected all member accounts, but now we’re interested in chasing down underused licensed accounts. Here’s the command I used:

[Array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All -Property signInActivity | Sort-Object DisplayName

The filter applied to Get-MgUser finds member accounts with at least one license. The command also retrieves the values of the signInActivity property for each account. This property holds the date and time for an account’s last interactive and non-interactive sign-ins. Here’s what the data for an account looks like:

LastNonInteractiveSignInDateTime  : 27/09/2022 13:04:58
LastNonInteractiveSignInRequestId : bcd2d562-76f0-4d29-a266-942f7ee31a00
LastSignInDateTime                : 11/05/2022 12:19:18
LastSignInRequestId               : 3f691116-5e0a-4c4c-a3a9-aecb3ae99800
AdditionalProperties              : {}

The last non-interactive sign-in might be something like a synchronization operation performed by the OneDrive sync client or a sign-in using an access token for the user account to another Microsoft 365 app. I’m not too interested in these sign-in activities as I want to know about licensed accounts that aren’t taking full advantage of their expensive licenses. Hence, we focus on the timestamp for the last interactive sign-in.

Update: Microsoft now supports a timestamp for the last successful sign in for Entra ID accounts. The LastSignInDateTime property can capture an unsuccessful sign-in, so using the new lastSuccessfulSignInDateTime property is a better choice in most situations. However, Entra ID only captures data for the property from December 1, 2023.

Calculating How Long Since an Account Sign-in

To detect an underused account, we need to define how to recognize such an account. To keep things simple, I define an underused account as being more that hasn’t signed in interactively for over 60 days. An account in this category costs $23/month if it holds an Office 365 E3 license while one assigned an E5 license costs $38/month. And that’s not taking any add-on licenses into account. At $30/month, we’ve already paid $60 for an underused account when it matches our criterion.

The script checks to see if any Entra ID sign-in information is available for the account (i.e., the account has signed in at least once). If it does, we extract the timestamp for the last interactive sign-in and compute how many days it is since that time. If not, we mark the account appropriately.

# Calculate how long it's been since someone signed in
  If ([string]::IsNullOrWhiteSpace($User.SignInActivity.LastSignInDateTime) -eq $False) {
    [datetime]$LastSignInDate = $User.SignInActivity.LastSignInDateTime
    $DaysSinceLastSignIn = ($CreationDate - $LastSignInDate).Days
    $LastAccess = Get-Date($User.SignInActivity.LastSignInDateTime) -format g
    If ($DaysSinceLastSignIn -gt 60) { $UnusedAccountWarning = ("Account unused for {0} days - check!" -f $DaysSinceLastSignIn) }
  }
  Else {
    $DaysSinceLastSignIn = "Unknown"
    $UnusedAccountWarning = ("Unknown last sign-in for account")
    $LastAccess = "Unknown"
  }

Note that it can take a couple of minutes before Entra ID updates the last interactive timestamp for an account. This is likely due to caching and the need to preserve service resources.

Reporting Underused Accounts

The last change is to the output routine where the script now reports the percentage of underused accounts that it finds. Obviously, it’s not ideal if this number is more than a few percent.

I usually pipe the output of reports to the Out-GridView cmdlet to check the data. Figure 1 shows the output from my tenant. Several underused accounts are identified, which is what I expect given the testing and non-production usage pattern within the tenant. Another advantage of Out-GridView is that it’s easy to sort the information to focus in on problem items as seen here.

Highlighting underused accounts with licenses
Figure 1: Highlighting underused accounts with licenses

Customizing the Output

Seeing that the script is PowerShell, it’s easy to adjust the code to meet the requirements of an organization. Some, for instance, might have a higher tolerance level before they consider an account underutilized and some might be more restrictive. Some might like to split the report up into departments and send the underused accounts found for each department to its manager for review. It’s PowerShell, so go crazy and make the data work for you.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/09/29/underused-accounts-report/feed/ 7 57256
Checking Audit Logs for Consent Permission Grants https://office365itpros.com/2022/09/23/consent-permission-grants/?utm_source=rss&utm_medium=rss&utm_campaign=consent-permission-grants https://office365itpros.com/2022/09/23/consent-permission-grants/#comments Fri, 23 Sep 2022 01:00:00 +0000 https://office365itpros.com/?p=56999

Looking for Consent Permission Grants for High-Priority Permissions

This week, I wrote about applications with high-priority permissions, defined as Microsoft Graph and other permissions that attackers could exploit to access, update, and exfiltrate data. For example, if an app holds the Mail.ReadWrite application permission, it can read and write all mailboxes in the tenant. The script generates a report that’s posted to a Teams channel to allow administrators to review the applications holding the specified permissions.

Illicit Consent Permission Grants

If you examine the information returned by Entra ID (Azure AD) for an app, you’ll see that although we can figure out the permissions assigned to the app, but Entra ID doesn’t tell you who consented to the permission and when they consented. This could be an important sign that an attacker has managed to achieve an illicit consent grant, defined as occurring when:

the attacker creates an Azure-registered application that requests access to data such as contact information, email, or documents. The attacker then tricks an end user into granting that application consent to access their data either through a phishing attack.”

An illicit consent grant for access to an individual user’s data is bad. One that results in an administrator granting consent to an application for a high-priority permission that the attacker can subsequently leverage could be catastrophic.

Checking Audit Records for Consent Permission Grants

One way to discover the last time when an adjustment occurred to app permissions is to search the Entra ID audit logs for records for the Consent to application action, filtering the set to find those matching the service principal identifier for an app. I didn’t do this in the script described in the article, Let’s explore how a consent check might work.

First, let’s assume that the script has run and detected an application holding some high-priority permissions. Its properties might look like this:

DisplayName        : MalwareExample
ServicePrincipalId : 6df52e04-63b2-4007-af69-40430ee5a1d1
Publisher          : Office 365 for IT Pros
Permissions        : Mail.ReadWrite, Mail.Send
SPType             : Application
CreatedDate        : 12/09/2022 22:41
RecentApp          : True

To scan the Entra ID audit logs for any consent granted records for this app, we could use a command like this to see if an audit record exists. The search goes back 30 days.

[array]$AuditRecords = Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'Consent to application' AND result eq 'Success' AND targetResources/any(tr:tr/id eq '$($app.serviceprincipalid)')" -top 1

If an audit record is found, it will look like this:

ActivityDateTime     : 12/09/2022 21:42:49
ActivityDisplayName  : Consent to application
AdditionalDetails    : {User-Agent, AppId}
Category             : ApplicationManagement
CorrelationId        : 005cc13f-9fd5-4b95-89ce-19802a7a785f
Id                   : Directory_005cc13f-9fd5-4b95-89ce-19802a7a785f_72CWK_111329857
InitiatedBy          : Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuditActivityInitiator1
LoggedByService      : Core Directory
OperationType        : Assign
Result               : success
ResultReason         :
TargetResources      : {6df52e04-63b2-4007-af69-40430ee5a1d1}
UserAgent            :
AdditionalProperties : {}

We can see that the consent was granted a minute after the creation date for the app. That could be a suspicious sign, but it might also be the result of granting permissions immediately after creating an app.

The InitiatedBy property is a complex object. Parsing it out, we can eventually discover who granted consent.

$AuditRecords.InitiatedBy.user.UserPrincipalName
Admin@Office365itpros.com

Unfortunately, that’s about all we can find from the audit log using the Get-MgAuditLogDirectoryAudit cmdlet. Some additional information is available in the Entra ID admin center (Figure 1).

Audit Log detail for a Azure AD consent permission grant
Figure 1: Audit Log detail for a consent permission grant

Entra ID sends its audit data to the Microsoft 365 audit log and you can also search there using a command like this:

[array]$records = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date).AddDays(1) -Formatted -ResultSize 5000 -Operations "Consent to application"

The Office 365 audit log stores information for 90 days (for accounts with Office 365 E3 licenses) or 365 days (accounts with Office 365 E5 licenses). If you don’t find audit records in Entra ID checking the Office 365 audit log can deliver a result. The downside of using the Microsoft 365 audit log is that it’s likely going to be slower to find any records because there’s more data to search and a specific search filter isn’t available as it when using Get-MgAuditLogDirectoryAudit to check Entra ID audit records.

The audit data is useful information that could help identify any problematic consent grants that might turn out to be illicit, but the data are only effective if people pay attention to permissions granted to apps, especially the high-profile permissions.

Updating Code to Check for Consent Permission Grants

Now that we know how to query the Entra ID audit logs to find records for consent grants for an app, it would be easy to update the script to include the check in the code. The hardest part is probably the update to include the audit information in the HTML body of the message to post to Teams. I’ll leave the script update as an exercise for the reader!

The key point is that Azure apps shouldn’t be left unsupervised. Whatever method you choose to check these apps, make sure it happens regularly and that someone is responsible for reviewing the reports and other outputs to detect any problems.


Learn more about how the Office 365 applications really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/09/23/consent-permission-grants/feed/ 8 56999
Updating Extension Attributes for Entra ID Registered Devices with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/09/06/entra-id-registered-devices/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-registered-devices https://office365itpros.com/2022/09/06/entra-id-registered-devices/#comments Tue, 06 Sep 2022 01:00:00 +0000 https://office365itpros.com/?p=56830

Registered Devices and Entra ID (Azure AD)

Updated 8 September 2023

According to Microsoft, the goal for Entra ID registered devices (workplace joined devices) is “to provide your users with support for bring your own device (BYOD) or mobile device scenarios. In these scenarios, a user can access your organization’s resources using a personal device.” Personally, I haven’t paid registered devices much attention over the years. Other topics occupied my time, and apart from going through the joining process to allow the organization to manage the device, ignored their existence.

Devices occupy their own area in the Entra ID admin center (Figure 1). The details displayed for each device are those gathered when the device registers with Entra ID. This accounts for some of the funky default device names generated by Windows. Entra ID doesn’t update devices records with details of O/S upgrades, so many of my devices appear to run Windows 10 when they’ve long since acquired Windows 11. The Entra ID admin center concentrates mainly on organizing device identities, which is what you’d expect from a directory.

Entra ID registered devices in the Entra ID admin center
Figure 1: Entra ID registered devices in the Entra ID admin center

Setting Extension Attributes for Entra ID Registered Devices

In any case, I thought that there might be some way to exploit the registered devices in Entra ID, similar in concept to the way that Exchange administrators often use custom attributes to mark mailboxes (here’s an example of using custom attributes to drive the membership of dynamic distribution groups).

This led me to the Graph API for Devices and a note in that page about using extension attributes. Organizations commonly use Entra ID extension attributes to store extra information about user objects. They’re also available for device objects, and it’s convenient to be able to use the extension attributes to store information that help administrators know who uses a device. Fifteen extension attributes (ExtensionAttribute1 through ExtensionAttribute15) are available.

It seemed to make sense to use the extension attributes to make the entries for registered devices more useful. I decided to populate six of the extension attributes with information about the user who registered a device. It’s not always the case that the registered owner is still the person who uses a device, but there’s a high probability that it is, especially in BYOD scenarios.

To test the theory, I wrote a script using the Microsoft Graph PowerShell SDK to:

  • Find all registered devices with the Get-MgDevice cmdlet.
  • For each device, extract the identifier for the user’s account. This is stored in an odd manner in the device record (at least, Microsoft could make it much simpler to find and use the identifier).
  • Use the Get-MgUser cmdlet to check the identifier against Entra ID and retrieve user details if a match is successful. The lookup fails if the user is no longer in Entra ID or their account belongs to another tenant (Entra ID can register devices for guest users).
  • Run Update-MgDevice to populate the extension attributes when we have an account match.

Connect-MgGraph -Scopes Directory.ReadWrite.All, Device.Read.All
[array]$Devices = Get-MgDevice -All

ForEach ($Device in $Devices) {
  If ($Device.PhysicalIds.count -gt 0) {
    Foreach ($X in $Device.PhysicalIds) { If ($X.SubString(0,10) -eq "[USER-GID]") { $UserGuid = $X } }
    $UserId = $UserGuid.substring(11,36)
    If ($UserId) { #We found a user identifier - try to resolve it against Entra ID
       [array]$User = Get-MgUser -UserId $UserId -ErrorAction SilentlyContinue }
       If ($User) { # Found a user in Entra ID
         Write-Host ("Device {0} owned by {1}" -f $Device.DisplayName, $User.DisplayName)
         $Attributes = @{
          "ExtensionAttributes" = @{
            "extensionAttribute1" = $User.DisplayName
            "extensionAttribute2" = $User.UserPrincipalName
            "extensionAttribute3" = $User.MobilePhone
            "extensionAttribute4" = $User.Department 
            "extensionAttribute5" = $User.City
            "extensionAttribute6" = $User.Country }
         }  | ConvertTo-Json
      Update-MgBetaDevice -DeviceId $Device.Id -BodyParameter $Attributes 
      }
       Else { Write-Host ("Device {0} owned by unknown user {1}" -f $Device.DisplayName, $UserId ) }
  } # End If Device PhysicalsId
} #End Foreach

Using Extension Attributes for Entra ID Registered Devices

After populating the device attributes, their values are available through the Entra ID admin center (Figure 2).

Populated extension attributes for an Entra ID registered device
Figure 2: Populated extension attributes for an Entra ID registered device

Even better, it’s easy to apply a filter against the extension attributes to find a subset of devices. In this example, I find all devices where the value of extensionAttribute6 is “Ireland.”

[array]$IrelandDevices = Get-MgDevice -Filter "extensionAttributes/extensionAttribute6 eq 'Ireland'" -CountVariable IrelandCount -ConsistencyLevel eventual

Custom Attributes for All

Even those running device management software like Intune might find value in being able to assign custom values to registered devices through PowerShell. The possibilities are endless. At least, that’s what I’ve heard.


Learn about exploiting Entra ID (Azure AD) and PowerShell by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

]]>
https://office365itpros.com/2022/09/06/entra-id-registered-devices/feed/ 43 56830
Microsoft Sets Out to Block Unmanaged Azure AD Guest Accounts https://office365itpros.com/2022/09/05/azure-ad-unmanaged-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-unmanaged-accounts https://office365itpros.com/2022/09/05/azure-ad-unmanaged-accounts/#comments Mon, 05 Sep 2022 01:00:00 +0000 https://office365itpros.com/?p=56856

Eliminating the Need for Azure AD Unmanaged Accounts

The language used in Microsoft’s September 2 announcement that tenants should “Say goodbye to unmanaged Azure AD accounts for B2B collaboration” created some confusion. The problem is that Microsoft never quite explained what unmanaged (or “viral”) Azure AD accounts are in their post. Some folks might be confused about what their initiative is all about.

The blog refers to people who used self-service sign-up to create Azure AD guest accounts “by validating ownership of their work email address when their domain is not verified in Azure AD.” This causes a problem because “users would create accounts in a tenant not managed by the IT department of their organization.”

Managed and Unmanaged Tenants

Azure AD is composed of many tenant directories. A managed tenant is one that has a global administrator (the manager) created to support a service like Microsoft 365 or Dynamics 365. All Microsoft 365 organizations have a managed Azure AD tenant.

When Microsoft introduced Azure B2B Collaboration in 2016, they created the ability of external users to sign up to be guest members in managed tenants using the email address of the external users to validate their existence. A guest account exists in the directory of the tenant where the guest accesses some resources, like documents in SharePoint Online or a team. Azure AD also attempts to link the guest account to the user’s real account in the directory of their source tenant. Some of these guests came from email domains that didn’t use Azure AD, and Microsoft uses unmanaged tenants based on the users’ email domains to store their accounts.

Let’s take a practical example. I add the email address of an external user to the membership of a Microsoft 365 group or team. This action causes Azure AD to create a guest account and generate an invitation to the external user to redeem the invitation and confirm their email address. The user receives the invitation by email and accepts it. Azure AD is now happy that the user is real and marks the guest account as having accepted the invitation. The external user can then use their guest account to participate in the group or guest and all is well.

This scheme works until the organization that owns the email domain decides to use Azure AD because they want to use a service like Microsoft 365. At that point, the organization must take over the unmanaged tenant and its unmanaged accounts. This process is well-known and documented, but it interferes with the smooth onboarding of organizations into services.

No More Azure AD Unmanaged Accounts

What’s happening now is that Microsoft is removing the need to create unmanaged accounts and tenants by removing the ability of external users to validate using email addresses. Instead, if an external user doesn’t come from:

  • Another Azure AD tenant.
  • A directory that federates with Azure AD, like Google.
  • Consumer Microsoft Services (MSA).

Microsoft will either use a one-time password (OTP) to validate their email address or require the user to create a consumer account using their email address. Microsoft stresses that unmanaged Azure AD accounts used by guest accounts already present in customer organizations will continue to work. The new redemption process (Figure 1) only applies to new guest accounts.

Azure AD B2B Collaboration invitation redemption flow (source: Microsoft)

Azure AD unmanaged accounts
Figure 1: Azure AD B2B Collaboration invitation redemption flow (source: Microsoft)

Cleaning up Azure AD Unmanaged Accounts

Microsoft’s post indicates that some tenants have thousands of unmanaged Azure AD accounts in their directories. As noted above, these accounts will continue to work, but if you want to clean them up (essentially to force people with unmanaged accounts to revalidate to Azure AD), Microsoft has a set of tools to help.

After reading the documentation, I tested the procedure on my tenant. Some PowerShell configuration is necessary. You must install:

In addition, before you run the Get-MsIdUnmanagedExternalUser cmdlet to find unmanaged (viral) accounts, you must import the msidentity.microsoft.graph module. Here’s what I did to run the code in my tenant:. As you can see, three accounts were identified.

Import-Module msidentitytools,microsoft.graph	

Connect-MgGraph -Scope User.Read.All
Select-MgProfile Beta
Get-MsIdUnmanagedExternalUser

Id                                   DisplayName                    Mail                   UserPrincipalName
--                                   -----------                    ----                   -----------------
39cac377-02cc-4919-ad44-d9f1a7cc5eae Glen Weaver                    gweaver@gwdevelop.com gweaver_gedevelop.com#EX...
3e97b38b-6031-4501-bdba-4d05fff67ec6 Michael Conroy                 michaeld@conroycons.com  michaeld_conroycons.com#EXT...
94687a75-7a3e-4001-b15e-7fc91cc7ac4e Norbert Platz                  n.platz@devs.de n.platz@devs.de#EX...

As you might expect, the three accounts belonged to email domains that didn’t use Azure AD. I had created the accounts in September 2016, soon after the introduction of Azure B2B Collaboration support for what was then Office 365 Groups (now Microsoft 365 Groups). The ExternalUserState property of each account was set to Accepted, meaning that the users had redeemed their invitation to be a guest user in my tenant.

To force the unmanaged accounts to go through Microsoft’s new redemption process, you run Get-MsIdUnmanagedExternalUser again and pipe the results to Reset-MsIdExternalUser. This action causes Azure AD to reissue the invitation to the email address for each account and reset the ExternalUserState property to PendingAcceptance. 

Get-MsIdUnmanagedExternalUser | Reset-MsIdExternalUser

Id                                   InviteRedeemUrl
--                                   ---------------
d325b1e4-c6d8-4d24-b384-05bd145abf6f https://login.microsoftonline.com/redeem?rd=https%3a%2f%2finvitations.microsoft...
bb1112fc-c0b1-4b0e-a43b-dfd0914c8345 https://login.microsoftonline.com/redeem?rd=https%3a%2f%2finvitations.microsoft...

It’s up to each external user to decide if they wish to redeem their invitation, and if they do, they must use the new redemption process. If a guest chooses not to redeem their invitation, you can consider removing their account after a reasonable period.

Not Too Much to Complain About

The advent of cross-tenant access policies means that guest accounts and Azure B2B Collaboration is less important than they were once. We all learn with experience, and it seems that Microsoft has learned that unmanaged tenants and unmanaged (or viral) accounts are not as good an idea as they seemed to be in 2016.

I can’t see a downside in what Microsoft is doing. They allow tenants to leave unmanaged guest accounts alone if they want to, and tools are available if an organization decides to move these accounts to a managed status. Apart from some minor disruption for those being asked to go through the invitation redemption process again, there’s not much to complain about.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2022/09/05/azure-ad-unmanaged-accounts/feed/ 1 56856
Use Graph Explorer to Sign into Microsoft 365 Tenants as a Guest https://office365itpros.com/2022/08/29/graph-explorer-guest-access/?utm_source=rss&utm_medium=rss&utm_campaign=graph-explorer-guest-access https://office365itpros.com/2022/08/29/graph-explorer-guest-access/#comments Mon, 29 Aug 2022 01:00:00 +0000 https://office365itpros.com/?p=56726

And How to Block this Access

I recently noted that the Graph Explorer utility has some useful new features. Well, here’s another feature to consider that might be useful some day: you can sign into the Graph Explorer as a guest user in a tenant.

When you start Graph Explorer, you can run sample commands that operate against dummy data or sign into a tenant to use real data. Up to now, you sign in with a tenant account to access the data in that tenant, just like you’d sign into OWA or the Microsoft 365 admin center.

Signing into Graph Explorer as a Guest

However, if you add the name of a tenant where you have a guest account to the Graph Explorer URI, the tool will sign into that tenant. For example, the “normal” URI for the Graph Explorer is:

https://developer.microsoft.com/en-us/graph/graph-explorer

To sign into another tenant with a guest account, add the service domain or the tenant identifier. For example:

https://developer.microsoft.com/en-us/graph/graph-explorer?tenant=o365maestro.onmicrosoft.com

or

https://developer.microsoft.com/en-us/graph/graph-explorer?tenant=163e0495-8f47-46df-a823-685b61cc8d89

If you know a tenant’s domain, but not its service domain or tenant identifier, you can use this website to look up the tenant identifier.

When you sign in using the Graph Explorer, you can use your regular account. Azure AD will go through the normal sign-in process for the target tenant, including enforcement of multi-factor authentication as dictated by that tenant, and if your account is recognized as a guest, you’ll connect. To validate that you’re using a guest account, run the sample “my profile” query and you’ll see that the user principal name shown for the account belongs to a guest. For instance, Figure 1 shows that Chris.Bishop@office365itpros.com is connected to the O365Maestro tenant using the guest account Chris.Bishop_office365itpros.com#EXT#@o365maestro.onmicrosoft.com.

Connecting to the Graph Explorer with a guest account
Figure 1: Connecting to the Graph Explorer with a guest account

Guest accounts are limited in what they can do when connected to a tenant. In many cases, attempts to run queries such as listing all users or all groups in the tenant result in:

    "error": {
        "code": "Authorization_RequestDenied",
        "message": "Insufficient privileges to complete the operation.",

Which is a nice way of saying that although your account is a valued guest in the organization, that’s not an invitation to poke around and look for information. Other requests, such as anything to do with a mailbox, see errors like:

"error": {
        "code": "MailboxNotEnabledForRESTAPI",
        "message": "The mailbox is either inactive, soft-deleted, or is hosted on-premise.",

Guest accounts do have mailboxes, but they are special cloud-only mailboxes created and managed by the Microsoft 365 substrate to store compliance records like those captured for Teams chats and channel conversations.

Blocking Access

Although the Graph Explorer enables limited access to tenant data for guest accounts, you might not like the idea of guests connecting like this. Three solutions exist. First, you can block user access to the Graph Explorer Azure AD app. Open the Azure AD admin center, go to enterprise applications, and search for Graph Explorer. Open the app’s properties and update the Enabled for users to sign in setting to Off (Figure 2) and save the new app settings.

Block the Graph Explorer app to stop people using the app
Figure 2: Block the app to stop people using the Graph Explorer

This is a crude but effective mechanism that blocks all access to the Graph Explorer, including to administrators. Anyone attempting to access the app encounters the error:

AADSTS7000112: Application 'de8bc8b5-d9f9-48b1-a8ad-b748da725064'(Graph Explorer) is disabled.

Second, you can assign specific users and groups to the app. The Assignment required slider is visible in Figure 2. When set to Yes, administrators must explicitly allow users and groups access to the app (through the Users and groups menu option on the left-hand side). If a user who doesn’t have an assignment attempts to use the app, they get the following error when they try to sign in:

AADSTS50105: Your administrator has configured the application Graph Explorer ('de8bc8b5-d9f9-48b1-a8ad-b748da725064') to block users unless they are specifically granted ('assigned') access to the application. The signed in user 'Chris.Bishop@office365itpros.com' is blocked because they are not a direct member of a group with access, nor had access directly assigned by an administrator. Please contact your administrator to assign access to this application.

Conditional Access Block

Conditional access (CA) policies offer the most precise way to control access. A simple CA policy to block access to the Graph Explorer app for guest users (Figure 3) does the trick.

A Conditional Access policy to block guest access to the Graph Explorer
Figure 3: A Conditional Access policy to block guest access to the Graph Explorer

Tenant users can continue to sign in and use the Graph Explorer, but guests run into the CA block (Figure 4).

The CA policy blocks a guest from signing into the Graph Explorer
Figure 4: The CA policy blocks a guest from signing into the Graph Explorer

We can also confirm the effectiveness of the CA policy by searching the Azure AD audit logs to look for sign ins to the Graph Explorer app. Here’s how to do it with the Microsoft Graph PowerShell SDK:

Connect-MgGraph -Scopes "AuditLog.Read.All","Directory.Read.All"
Select-MgProfile Beta
[array]$Records = Get-MgAuditLogSignIn -Filter "(appdisplayname eq 'Graph Explorer' and signInEventTypes/any(t: t eq 'interactiveUser'))" -Sort "createdDateTime DESC"

$Records | Format-Table createddatetime, userprincipalname, ConditionalAccessStatus

CreatedDateTime     UserPrincipalName                          ConditionalAccessStatus
---------------     -----------------                          -----------------------
28/08/2022 15:25:24 chris.bishop@office365itpros.com           success
28/08/2022 15:15:52 tony.redmond@office365itpros.com           success
28/08/2022 15:01:56 warren.gatland@o365maestro.onmicrosoft.com failure

Unknown User Case for Guest Access

After noodling on this subject for a few days, I still haven’t come up with a good use case why the Graph Explorer supports guest access. I suppose it’s a good thing and I’m sure that an Azure AD development engineer put forward an excellent case to justify the feature, but I know many will disagree. Now if I could use this access to update the photo for my guest account (possible with Azure AD PowerShell but not with the Graph), I’d have a good use case!


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/08/29/graph-explorer-guest-access/feed/ 4 56726
The Odd Azure AD Selected Visibility is Not Allowed Problem https://office365itpros.com/2022/08/19/azure-ad-admin-center-issues/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-admin-center-issues https://office365itpros.com/2022/08/19/azure-ad-admin-center-issues/#comments Fri, 19 Aug 2022 01:00:00 +0000 https://office365itpros.com/?p=56571

Azure AD Admin Center Doesn’t Respect Sensitivity Label Settings

Last June, I tested the preview of nested dynamic Azure AD groups and encountered an odd “Per label policy, the selected visibility is not allowed” error when attempting to create new groups in the Azure AD admin center. Pressure of time forced me to ignore the problem and create the groups I wanted with PowerShell, but time allowed me this week to return to the problem.

It didn’t take long to reproduce the problem and track down the root cause (Figure 1).

Failed to create group because "the selected visibility is not allowed"
Figure 1: Failed to create group because “the selected visibility is not allowed”

Visibility Set to Private for New Microsoft 365 Groups

I used the Graph X-Ray tool to look at the PowerShell generated by the Azure AD admin center when it adds new Microsoft 365 groups. Here’s what Graph X-ray reported:

$params = @{
	DisplayName = "Viva Topics Management"
	MailEnabled = $true
	SecurityEnabled = $true
	GroupTypes = @(
		"Unified"
	)
	Description = "People who manage Viva Topics"
	MailNickname = "VivaTopicsManagement"
	AssignedLabels = @(
		@{
			LabelId = "e42fd42e-7240-4df0-9d8f-d14658bcf7ce"
		}
	)
	Visibility = "private" }}

I copied the command and ran it interactively and saw this error:

New-MgGroup -BodyParameter $params
New-MgGroup : Property visibility is not compliant with the assigned label.
At line:18 char:1
+ New-MgGroup -BodyParameter $params
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: ({ body = Micros...ftGraphGroup1 }:<>f__AnonymousType1`1) [New-MgGroup
   _Create1], RestException`1
    + FullyQualifiedErrorId : Request_BadRequest,Microsoft.Graph.PowerShell.Cmdlets.NewMgGroup_Create1

Changing the command to set the visibility property in the parameters to “Public” allowed the command to run successfully and create the group. This is what I expected because the container management settings for the sensitivity label chosen for the new group sets its visibility to Public.

The root cause is that the command generated by the Azure AD admin center sets the access type for the new group incorrectly. Instead of reading the group’s access type (visibility) from the sensitivity label, the command uses “Private” for the value. This means that the command works for any group created with a sensitivity label that sets the access type to Private but fails for public groups.

The Azure AD admin center UI doesn’t include a field to allow the visibility to be selected for a new group, so some overhaul of the UI is needed to display the visibility inherited when a sensitivity label is selected. In addition, Microsoft’s documentation for creating a new group in the Azure AD admin center doesn’t mention visibility at all, so there’s no hope in interpreting the error message.

Inconsistent Microsoft 365 Group Management

I’m unsure of how many new Microsoft 365 groups are created in the Azure AD admin center. My feeling is that most administrators create new groups through the Microsoft 365 admin center or a workload-specific portal like the Teams admin center or SharePoint Online admin center, or even a client like OWA or Teams. All these interfaces (and PowerShell) respect the container management controls imposed by sensitivity labels. If the Azure AD admin center was heavily used, I’m sure Microsoft would have heard about the problem before I reported it on August 15.

In any case, this is not the only example of inconsistency between the Azure AD admin center and the workload portals. Take the security enabled property for a group. This is set to $True by the Azure AD admin center and $False by the Microsoft 365 admin center. That doesn’t sound too serious, but it means that groups not created in the Azure AD admin center can’t be used for purposes like group-based license management. This is where you manage license assignments by allocating them to members of a group. It’s a convenient way to manage licenses (Figure 2).

Group-based license management in the Azure AD admin center
Figure 2: Group-based license management in the Azure AD admin center

The security enabled property isn’t exposed in the Azure AD admin center UI, so if you want to update a group to make it available for group-based license management, you need to use PowerShell. The steps are simple using the group management cmdlets from the Microsoft Graph PowerShell SDK. The first command finds the group to use. The second updates its SecurityEnabled property.

$Group = (Get-MgGroup -Filter "DisplayName eq 'HR Working Group'")
Update-MgGroup -GroupId $Group.Id -SecurityEnabled:$True

After the Update-MgGroup cmdlet runs, you should be able to use the group for group-based license management.

Small But Irritating Issues

Neither of the issues described here are earthshattering. Both can be worked around by competent tenant administrators who understand how Microsoft 365 works. The problem is that issues like this cause grief to inexperienced administrators and complicate the learning curve for cloud services. That’s a great pity.


Learn more about how the Office 365 applications really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/08/19/azure-ad-admin-center-issues/feed/ 1 56571
Microsoft Announces New Yammer Administrator Role https://office365itpros.com/2022/08/12/yammer-administrator-role/?utm_source=rss&utm_medium=rss&utm_campaign=yammer-administrator-role https://office365itpros.com/2022/08/12/yammer-administrator-role/#respond Fri, 12 Aug 2022 01:00:00 +0000 https://office365itpros.com/?p=56486

Now Available in Azure AD

On August 9, Microsoft announced the addition of the Yammer administrator role to Azure AD. Like the other workload-specific administrator roles such as Exchange administrator, Teams administrator, and SharePoint administrator, the new role helps to avoid a proliferation of user accounts assigned the all-powerful Global administrator role. Microsoft says that a user assigned the “Yammer admin role can manage all aspects of the Yammer service, long with modifying Yammer communities without becoming an owner or member of that community.” That’s a long-winded way of saying that accounts holding the Yammer administrator role can manage Yammer.

Interestingly, the Yammer administrator role works for all kinds of Yammer networks. When I first read about the role, I assumed that it was part of Native mode Yammer networks, which is where Yammer embraces Azure AD and the Microsoft 365 ecosystem fully, instead of the older non-native mode networks. Because the new role supports non-native networks, Microsoft can use it in their external Yammer networks such as the one used by the Microsoft Information Protection team for customer communications.

Assigning Yammer Administrators

The easiest way to assign an Azure AD administrative role is through the Azure AD admin center (Figure 1).

Yammer administrator assignments in the Azure AD admin center
Figure 1: Yammer administrator assignments in the Azure AD admin center

You can also assign Azure AD administrative roles with PowerShell, as described in this article. The identifier for the Yammer administrator role is efc777ab-ffb8-4c71-809c-7d1ff399ff54.

Auditing Administrator Assignments

Assigning users to the Yammer administrator role creates an audit event. To find the events in the audit log, you can search using the Microsoft Purview compliance portal or with PowerShell. For example:

$StartDate = (Get-Date).AddDays(-7); $EndDate = (Get-Date).AddDays(1)
[array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Formatted -ResultSize 5000 -Operations "add member to role"
If ($Records) {
 ForEach ($Record in $Records) {
   $AuditData = $Record.Auditdata  | convertfrom-json
   [string]$UserName = $AuditData.ObjectId
   [string]$AdminRole = $AuditData.ModifiedProperties[1].NewValue
   If ($AdminRole -eq "Yammer Administrator") {
     Write-Host ("User {0} added to role {1} at {2}" -f $UserName, $AdminRole, $Record.CreationDate ) }
 }}
User Sean.Landy@office365itpros.com added to role Yammer Administrator at 11/08/2022 13:08:01
User Ben.James@Office365itpros.com added to role Yammer Administrator at 10/08/2022 18:02:35

Using the Yammer Administrator Role

It can take a couple of hours for Yammer to synchronize details of new role assignments from Azure AD. When this happens, the role assignees will see the Edit network admin settings option in their Settings menu (Figure 2). This brings up the normal Yammer configuration page to allow the user to amend network settings.

The Yammer administrator option shows up in the Yammer client UI
Figure 2: The Yammer administrator option shows up in the Yammer client UI

A clear distinction exists between accounts holding the Yammer administrator role (treated as verified admins) and those which gain administrative permission for Yammer through another route, like being a tenant administrator (Figure 3). The differences between the different kinds of Yammer admins are explained in this article. Existing holders of the Yammer verified admin role do not automatically receive the Azure AD role. If you want the two sets to match up, you’ll need to assign existing verified admins to the Azure AD Yammer administrator role.

Yammer administrators
Figure 3: Yammer administrators

It’s interesting that Microsoft choose to present the information in this fashion instead of showing all administrators as equal and hiding the complexities of revoking their access (if necessary) behind the scenes.

Bit by Bit, Yammer Becomes More Integrated

Ten years and more after its acquisition by Microsoft, Yammer is steadily becoming more integrated into the Microsoft 365 ecosystem. It’s just a pity that everything seems to take so long. Perhaps Yammer’s focus really is shifting to Viva. That wouldn’t be a bad thing, even if it slows down progress for the traditional browser client and backend.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2022/08/12/yammer-administrator-role/feed/ 0 56486
How to Report Entra ID Admin Accounts Not Protected by MFA https://office365itpros.com/2022/07/06/entra-id-admin-roles-no-mfa/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-admin-roles-no-mfa https://office365itpros.com/2022/07/06/entra-id-admin-roles-no-mfa/#comments Wed, 06 Jul 2022 01:00:00 +0000 https://office365itpros.com/?p=55934

Using the Graph APIs Instead of MSOL Cmdlets

As regular readers of this blog know, I am keen that Microsoft 365 tenants protect user accounts with multi-factor authentication (MFA), especially user accounts with Entra ID admin roles. Despite all the promises made by security vendors about products to protect your tenants, the single most effective step that an organization can take is to make sure that accounts use MFA to sign into Microsoft 365. Some years ago, Microsoft reported that MFA blocks 99.9% of account compromise attacks. That statistic remains unquestioned.

Over the years, I’ve written several scripts to help tenant administrators understand the use of MFA within user accounts. The original 2018 article focused on reporting the enablement of accounts to use MFA. I followed up in 2019 with an article explaining how to find unprotected accounts that hold an administrative role. The downside of both articles is that the PowerShell code described in the text uses cmdlets from the old Microsoft Online Services (MSOL) module, which Microsoft is in the process of deprecating. The code still works, but the articles are good examples of advice you can find on the internet that is degrading and will soon be obsolete, as discussed yesterday.

Microsoft would like everyone to rewrite their PowerShell scripts to use Graph API requests or the cmdlets in the Microsoft Graph PowerShell SDK. The unavailability of equivalent API support undermined Microsoft’s aspiration. It’s been possible to report the authentication methods used by Entra ID accounts, but replicating a report showing administrative accounts and their MFA status has been harder.

Graph Registration Details

Enter the Microsoft Graph userRegistrationDetails resource type. This is a beta API that returns a list of authentication methods for users in a manner that’s easier to process than before. Two requests are available:

  • List: Returns the authentication methods for every user account in the organization. This isn’t as useful as it seems because the data returned includes guest accounts and unlicensed member accounts used for purposes like room mailboxes.
  • Get: Returns the authentication methods for a single user account. In practice, this API is much more useful.

The authentication methods data returned for a user account is shown below. In this case, the account is not MFA-enabled.

Name                           Value
----                           -----
userPrincipalName              Andy.Ruth@office365itpros.com
defaultMfaMethod               none
isMfaCapable                   False
isSsprCapable                  False
@odata.context                 https://graph.microsoft.com/beta/$metadata#reports/authenticationMethods/userRegistrationDetails/$entity
isSsprEnabled                  False
id                             fdc6b121-44b8-4262-9ca7-3603a16caa3e
methodsRegistered              {email}
isMfaRegistered                False
isPasswordlessCapable          False
isSsprRegistered               True
userDisplayName                Andy Ruth (Director)

The Microsoft Graph PowerShell SDK includes the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet (you’ve got to love the automatically generated cmdlet names!). If you run the cmdlet without any parameters, you get the same data as returned by the List API. To return the data for an individual account, include a filter to specify their User Principal Name. For example:

Get-MgReportAuthenticationMethodUserRegistrationDetail -Filter "UserPrincipalName eq 'Sean.Landy@office365itpros.com'" | Fl

DefaultMfaMethod      : mobilePhone
Id                    : 08dda855-5dc3-4fdc-8458-cbc494a5a774
IsMfaCapable          : True
IsMfaRegistered       : True
IsPasswordlessCapable : False
IsSsprCapable         : False
IsSsprEnabled         : False
IsSsprRegistered      : True
MethodsRegistered     : {mobilePhone}
UserDisplayName       : Sean Landy
UserPrincipalName     : Sean.Landy@office365itpros.com
AdditionalProperties  : {}

Building a Report of Entra ID Admin Roles

Knowing how to get information about an individual account, we can consider how to check all user accounts paying special attention to those holding one or more administrative roles. I took these steps, using a mixture of Graph API requests and cmdlets from the Microsoft Graph PowerShell SDK:

  • Connect to the Microsoft Graph SDK. You’ll need to specify the UserAuthenticationMethod.Read.All and AuditLog.Read.All permissions.
  • Select the beta profile (Select-MgProfile Beta) to ensure that the Graph retrieves the registration information.
  • Run Get-MgDirectoryRole to find the set of available roles. Note: this cmdlet reports the set of administrative roles assigned in the tenant. There are usually a bunch of unassigned roles that don’t show up. The full set of roles defined in Entra ID can be found by running Get-MgDirectoryRoleTemplate | Select-Object DisplayName, Id | Sort-Object DisplayName. Don’t use role template identifiers as an input to Get-MgDirectoryRoleMember as they won’t work.
  • For each role, run Get-MgDirectoryRoleMember to find the current holders of the role.
  • Create an array of accounts that hold administrative roles.
  • Run Get-MgUser to find the set of licensed user accounts (it’s reasonable to assume that administrative accounts have at least one license).
  • For each account, get the authentication methods. You can use the Graph API request or the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet.
  • Check if the account holds administrative roles and if so, fetch the roles held by the account.
  • Generate a report in an Excel worksheet (using the Import-Excel module).
  • Output a warning message if the script detects any unprotected administrative accounts (Figure 1).

Highlighting unprotected Entra ID accounts with administrative roles.

Entra ID admin roles.
Figure 1: Highlighting unprotected Entra ID admin roles

The Excel worksheet (Figure 2) is particularly useful in terms of being able to slice and dice the data to generate whatever report you need. For instance, you can see that many of the accounts listed use mobile phones (SMS messages) for the second authentication method. The Microsoft authenticator app is a better option, so you could pull the data about accounts currently using mobile phones to encourage them to move to the authenticator app.

Viewing details of Azure AD accounts and MFA methods in Excel
Figure 2: Viewing details of Entra ID admin roles for accounts

Download Script from GitHub

You can download the full script to report Entra ID admin roles and unprotected accounts from GitHub. Remember that this is code written to demonstrate a principal instead of an off-the-shelf solution. The code is basic PowerShell and can be altered to fit your needs. Enjoy

——————-

So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.!

]]>
https://office365itpros.com/2022/07/06/entra-id-admin-roles-no-mfa/feed/ 22 55934
Imminent Deprecation of Azure AD PowerShell Modules Creates Knowledge Gap in Documentation https://office365itpros.com/2022/07/05/azure-ad-powershell-knowledge/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-powershell-knowledge https://office365itpros.com/2022/07/05/azure-ad-powershell-knowledge/#comments Tue, 05 Jul 2022 01:00:00 +0000 https://office365itpros.com/?p=55878

Microsoft and Other Documentation Needs Updating

Microsoft announced their intention to retire the Azure AD Authentication Library (ADAL) and Azure AD Graph API in June 2020. A consequence of this decision meant the retirement of the Azure AD PowerShell modules, including the now very old Microsoft Online Services (MSOL) module. Even though Microsoft has pushed the retirement date out to June 30, 2023, the writing is on the wall for these modules.

Tenants will feel the first effect on March 31, 2023, when Microsoft 365 moves to a new license management platform. At that time, the PowerShell cmdlets for license assignment will stop working. Microsoft’s guidelines for converting from the old cmdlets to the Microsoft Graph PowerShell SDK include the blunt phrase that “there is currently no tool to automatically convert scripts.” In other words, it’s time to get coding, testing, and preparing to switchover. Good documentation is at a premium during conversions, and that’s an issue right now.

With two years’ warning, we can hardly plead a lack of awareness when the change happens., but with time running out, I don’t detect any great pressure. Maybe people will change when license management scripts and products stop working, or users report strange errors. It’s odd.

The Problem Lurking in Microsoft Documentation

One thing that might not be helping is the continued use of Azure AD and MSOL PowerShell examples in Microsoft documentation. After all, if the official documentation gives implicit approval to these modules, why bother changing? And to be fair, apart from license management, all the cmdlets will continue to work past the retirement date. There just won’t be any support or future updates.

Take the documentation to delete or restore user mailboxes in Exchange Online. This includes four references to the old Remove-MsolUser cmdlet as the text explains to readers how to remove an Azure AD user account permanently from the Azure AD recycle bin (Figure 1).

Microsoft documentation recommends the use of the obsolete Remove-MsolUser cmdlet

Azure AD PowerShell
Figure 1: Microsoft documentation recommends the use of the obsolete Remove-MsolUser cmdlet

It would be more impactful if the documentation used Microsoft Graph PowerShell SDK cmdlets or Graph API requests. For example, here’s how to use a Graph API request to retrieve the list of deleted Azure AD accounts in the recycle bin:

$Uri = "https://graph.microsoft.com/V1.0/directory/deletedItems/microsoft.graph.user"
[array]$DeletedUsers = Invoke-MgGraphRequest -Uri $Uri -Method Get
ForEach ($Account in $DeletedUsers.Value) { Write-Host $Account.displayname, $Account.id }
… select a user and then
Remove-MgDirectoryDeletedItem -DirectoryObjectId <Guid for deleted account>

This is an example where using a Graph API request is easier than the equivalent Microsoft Graph PowerShell SDK cmdlet (Get-MgDirectoryDeletedItem – see this example). The point is that if Microsoft documentation featured methods that customers can use in the future instead of the soon-to-be-deprecated modules, it would encourage tenant administrators to adopt those methods.

To be fair to Microsoft, they have tons of pages to update with new examples. However, it’s something that I think should happen sooner rather than later to nudge people along the path to where they should go.

The Problem with Azure AD Examples Across the Wider Internet

Much the same issue exists across the wider internet. Think of the average administrator who wants to find how to accomplish a task using the Azure AD PowerShell cmdlets. They’ll probably start by searching the internet to see how others did the same thing, and they’ll find many examples of old code. There’s always a big caveat about code you find on the internet: don’t trust anything until after fully testing the code. This advice still holds, but now we’re in a situation where the code that someone finds on August 20 to perform automated license assignment with PowerShell won’t work a week later.

I accept that the other cmdlets in the Azure AD and MSOL modules will continue to work after Microsoft retires the modules, but my point is still valid: examples based on soon-to-be-deprecated modules have a short shelf life.

You can’t expect blog writers to go back and revise every post with a reference to an Azure AD or MSOL cmdlet. Some might update some posts, but in general, it won’t happen. Nor should it. A blog post is a snippet of knowledge captured at a point in time rather than a definite statement about how something works that remains current. What’s different about this situation is that many posts face accelerated degeneration to a point where their content is no more than an interesting look back into the past.

Things Will Improve Over Time

Time heals many things. In this case, as time progresses and old blog posts decay, people will post new information and insights to renew the corpus of knowledge available on the internet. The Office 365 for IT Pros team is keenly aware of the issue and has generated several articles to help, including:

And of course, we’ve just released the 2023 edition of the Office 365 for IT Pros eBook containing over 250 examples of the Microsoft Graph PowerShell SDK cmdlets in action. In fact, we replaced every instance of using the Azure AD PowerShell cmdlets with the except of connecting to another tenant to update your guest account photo. The permissions model used by the Graph is completely different to the permissions granted when someone connects to Azure AD with Connect-AzureAD, and that’s why we had to leave that example. Over time, we hope to find a workaround and be able to remove the last vestige of Azure AD PowerShell.

]]>
https://office365itpros.com/2022/07/05/azure-ad-powershell-knowledge/feed/ 2 55878
Microsoft Previews Nested Dynamic Azure AD Groups https://office365itpros.com/2022/06/08/dynamic-azure-ad-group-members/?utm_source=rss&utm_medium=rss&utm_campaign=dynamic-azure-ad-group-members https://office365itpros.com/2022/06/08/dynamic-azure-ad-group-members/#comments Wed, 08 Jun 2022 01:00:00 +0000 https://office365itpros.com/?p=55392

Including Members from Other Groups in Membership of Dynamic Groups

Until recently, Dynamic Azure AD Groups have not supported the ability to include members from other groups in their membership (aka, nested groups). You can construct membership rules to include the same accounts in a dynamic group, but it’s easier to say, “include the members from groups 1, 2, and 3” if those groups already exist and include the necessary accounts.

In a June 6 announcement, Microsoft introduced a preview feature to allow the membership rules for dynamic Azure AD groups to use the memberOf attribute. In essence, memberOf instructs Azure AD to extract the membership of one to up to 50 groups and include the individual members of those groups in the dynamic membership.

Creating a New Azure AD Dynamic Group

Apparently, the preview feature is available worldwide. I had no success using it in the Azure AD admin center. Any attempt to create a new group (of any type) generated the error: “per label policy, the selected visibility is not allowed” (Figure 1). No doubt this is due to some configuration I have tweaked, but the error message is obscure, to say the least. (Update: I discovered the root cause of the problem, which Microsoft say they will fix).

Azure AD fails to create a group

per label policy, the selected visibility is not allowed
Figure 1: Azure AD fails to create a group

But where the will exists, you get the job done, and PowerShell came to the rescue. I created the new dynamic group with the following command. You can see that the membership rule is that the membership comes from any user members in the specified groups.

$Group = New-MgGroup -DisplayName "System Innovation" -Description "Dynamic group containing system innovators" -MailEnabled:$True -SecurityEnabled:$False -MailNickname SystemInnovators -GroupTypes "DynamicMembership", "Unified" -MembershipRule "user.memberOf -any (group.objectId -in ['ef4af711-bf83-4ba1-81be-fd98f4098d12',' d6279df7-2eff-4566-ba93-22aa9320385b','b07c7e05-10e0-47a4-acca-767621ac8ddc'])" -MembershipRuleProcessingState "On"

The groups added were:

  • A Microsoft 365 group with assigned membership.
  • A Microsoft 365 group with dynamic membership.
  • A distribution list with a fixed membership.

Microsoft’s documentation doesn’t include any reference to using distribution lists, but as Azure AD treats distribution lists like other groups, it seemed like they should work. After all, you can run the Get-MgGroupMember cmdlet (or Get-AzureADGroupMember if you still haven’t converted from the soon-to-be-deprecated module) against a distribution list and Azure AD is happy to list the members. And as it turns out, you can include the membership of distribution lists in dynamic Azure AD groups. After an hour or so, Azure AD resolved the rule and built the membership of the new dynamic group, including the removal of any duplicates (Figure 2).

Membership of the new dynamic Azure AD group
Figure 2: Membership of the new dynamic Azure AD group

Preview Limits

During the preview, a dynamic group can have up to 50 groups in its membership, and each tenant can have up to 500 dynamic groups that use the memberOf attribute in their membership rule. If you add security groups to the membership of a dynamic group, Azure AD includes only the direct members of the security group in the dynamic group’s membership.

In addition, Microsoft says that you can’t use a dynamic group that uses the memberOf attribute to define the membership of another group that also uses memberOf. The old and well-proven adage to keep it simple (stupid) rings loud and clear. Don’t nest groups inside groups and don’t over-complicate things. Perhaps more complicated arrangements might be possible in the future, but for the preview, don’t give Azure AD complex membership rules to resolve. For more information on including groups within the membership of dynamic groups, read Microsoft’s documentation.

Another issue is that the memberOf attribute can’t be used with other rules. For instance, let’s assume that you assemble a set of users drawn from the membership of several other group. You can’t add another filter to select people whose accounts match another attribute, such as the department or country.

For now, the rules editor doesn’t work for this type of dynamic group, nor does the other Validate Rules preview feature which allows administrators to check the effectiveness of a membership rule against an account that they know should be in a group’s membership (Figure 3).

Azure AD can't validate membership of a dynamic group
Figure 3: Azure AD can’t validate membership of a dynamic group

Dynamic Teams Work Too

I updated the group’s properties to enable it for Teams. Support for dynamic teams has been around since 2018, but it’s always wise to check. The good news is that the dynamic membership for the team appears as expected (Figure 4).

Teams membership roster for the dynamic Azure AD group
Figure 4: Teams membership roster for the dynamic Azure AD group

Solid Update

There’s no doubt that this is a good change. Anything that adds to the flexibility and capability of dynamic Azure AD groups is a good thing. The bad thing is that Microsoft requires Azure AD Premium P1 for dynamic groups (Exchange Online dynamic distribution lists don’t need additional licenses). The guidance is:

This feature requires an Azure AD Premium P1 license or Intune for Education for each unique user that is a member of one or more dynamic groups. You don’t have to assign licenses to users for them to be members of dynamic groups.

It would be nice if dynamic groups were included in Office 365 E3, but life is cruel sometimes…


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2022/06/08/dynamic-azure-ad-group-members/feed/ 6 55392
Guest Accounts Can’t Update Their Photos with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/06/07/azure-ad-guest-account-photo/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-guest-account-photo https://office365itpros.com/2022/06/07/azure-ad-guest-account-photo/#respond Tue, 07 Jun 2022 01:00:00 +0000 https://office365itpros.com/?p=55373

Upgrading Scripts to Use New Cmdlets

Microsoft plans to deprecate the Azure AD and Microsoft Online Services (MSOL) PowerShell modules in late 2022 or early 2023. Apart from the license management cmdlets, the other cmdlets in these modules will continue to work but will be unsupported. Eventually, the cmdlets will stop working, so the time is ripe for upgrading scripts and seeking new ways of getting things done, like how to manage Azure AD guest accounts.

In most cases, it’s possible to upgrade scripts by replacing Azure AD cmdlets with cmdlets from the Microsoft Graph PowerShell SDK. As we prepare for the launch of the Office 365 for IT Pros (2023 Edition) eBook, we’re going through all the Azure AD and MSOL code examples in the book to replace as many as possible with either Microsoft Graph API queries or SDK cmdlets. Microsoft publishes a useful cmdlet map to help developers match old cmdlets with suitable replacements.

Sometimes, it’s not yet possible to replace a cmdlet because Microsoft doesn’t yet provide a direct equivalent in the Graph. In these instances, we’re leaving the older code in place because it will continue to work. When a suitable replacement is available, we’ll update the book with new Graph-based code.

It’s Good to Use Photos with Azure AD Accounts

We recommend that tenant administrators add photos for all Azure AD accounts, both regular user accounts and guest accounts. Having a face to recognize makes it easier to appreciate who’s involved in sharing a document or participating in a channel conversation in Teams. Tenant administrators are busy people, and even if they devote time to “guest hygiene” (cleaning up unwanted or obsolete guest accounts), they might not get around to adding photos for guest accounts via the Azure AD admin center or PowerShell. This is why it’s good if guest accounts can update their own photos.

In April 2021, I wrote about how to use cmdlets from the Azure AD PowerShell module to update the photo for your Azure AD guest account in another Microsoft 365 tenant. It’s a relatively straightforward procedure that’s facilitated by the way the Azure AD module works. Once you have a connection to a tenant, you can work with accounts and other objects the signed-in account can access. In this instance, your guest account.

Time moves on and it was time to upgrade the example showing how guests can upload their own photos. Unhappily, although the Set-MgUserPhotoContent cmdlet is available to replace the Set-AzureADUserThumbNailPhoto cmdlet, the technique of connecting to a target tenant with a guest account to update the account photo doesn’t work. At least, it doesn’t work unless the target tenant meets specific criteria.

Experimenting with the Microsoft Graph PowerShell SDK

I experimented with several target tenants where I have guest accounts to see what’s possible. The Connect-MgGraph cmdlet is happy to connect to a tenant and you can sign in with your guest account. At this point, things go wrong. Once you connect with the Azure AD module, you can update the guest account as described in the post referenced above.

However, the Microsoft Graph takes a more restrictive approach to permissions (or scope). Administrators must grant consent to the service principal used for interactive sessions with the Microsoft Graph PowerShell SDK for the permissions to interact with user accounts. In this case, consent must be in place for the User.ReadWrite.All permission before it’s possible to update a user account (or guest account) with a photo. Interactive sessions with the PowerShell SDK use delegated permissions, so even though the permission is User.ReadWrite.All (implying access to all mailboxes), the Graph constrains the scope of the permission to the signed-in user.

Our renowned technical editor, Vasil Michev, thought that he had solved the problem and published a note to that effect. Unhappily, further investigation proved that using the Microsoft Graph PowerShell SDK to connect to a target tenant to update the photo for a guest account only works if the service principal for the Microsoft Graph PowerShell enterprise app (application id 14d82eec-204b-4c2f-b7e8-296a70dab67e) has consent for the User.ReadWrite.All permission.

The Service Principal Question

Meeting these requirements means that someone has run Connect-MgGraph at some time in the past in the target tenant. This action creates the service principal if it’s not already known to Azure AD. If the service principal doesn’t exist in the target tenant, Connect-MgGraph cannot proceed until an administrator signs in to create the service principal (Figure 1). After the creation of the service principal, it can receive consent to use permissions, including User.ReadWrite.All.

Azure AD prompts to create the service principal for the Microsoft Graph PowerShell SDK

Azure AD Guest Account
Figure 1: Azure AD prompts to create the service principal for the Microsoft Graph PowerShell SDK

Although these conditions might exist for some tenants, there’s no guarantee that the service principal exists and holds the permission. For example, connecting to the Microsoft tenant with a guest account reveals that the User.Read permission is available, but the User.ReadWrite.All permission is not.

Disconnect-MgGraph
Connect-MgGraph -TenantId 72f988bf-86f1-41af-91ab-2d7cd011db47
Welcome To Microsoft Graph!
Get-Mgcontext

ClientId              : 14d82eec-204b-4c2f-b7e8-296a70dab67e
TenantId              : 72f988bf-86f1-41af-91ab-2d7cd011db47
CertificateThumbprint :
Scopes                : {openid, profile, User.Read, email}
AuthType              : Delegated
AuthProviderType      : InteractiveAuthenticationProvider
CertificateName       :
Account               :
AppName               : Microsoft Graph PowerShell
ContextScope          : CurrentUser
Certificate           :
PSHostVersion         : 5.1.22000.653
ClientTimeout         : 00:05:00

In a nutshell, it’s possible to use the Microsoft Graph PowerShell SDK to update photos for guest accounts in other tenants, but only when the conditions are exactly right.

That Permissioned Service Principal

In closing, let me note once again the cumulative nature of the service principal used by the Microsoft Graph PowerShell SDK. If an administrator consents to a permission for use with the Graph SDK, that permission remains assigned to the service principal unless an administrator removes it. Over time, permissions accrue, and the service principal becomes highly permissioned. This makes it easy for tenant administrators to run SDK cmdlets in interactive sessions, but it’s possibly not what you want to happen. On the upside, interactive sessions use delegated permissions rather than application permissions, so the Graph won’t allow the signed-in user to access data that they couldn’t otherwise open. Which is nice to know.

]]>
https://office365itpros.com/2022/06/07/azure-ad-guest-account-photo/feed/ 0 55373
Don’t Give Up on Azure AD Guest Accounts https://office365itpros.com/2022/06/06/azure-ad-guest-accounts-valuable/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-guest-accounts-valuable https://office365itpros.com/2022/06/06/azure-ad-guest-accounts-valuable/#comments Mon, 06 Jun 2022 01:00:00 +0000 https://office365itpros.com/?p=55362

Azure B2B Collaboration Likely to be Dominant for Immediate Future

The introduction of shared channels in Teams is a big deal, as is the advent of Azure AD Direct Connect, the vital underpinning that enables tenants to accept the credentials granted to accounts in other Microsoft 365 tenants. Cross-tenant access policies control who can share channels in your organization and who can share channels in other organizations.

Some might have missed the news that cross-tenant access settings can also control Azure B2B collaboration (guest accounts). This is also a big step forward because it addresses the need some tenant administrators have expressed to be able to control the organizations where their users can join groups using Azure AD guest accounts. Control over inbound guests has been available with the Azure AD B2B Collaboration policy for several years, so adding outbound control is welcome.

Sharing with Teams

Last week, Microsoft posted about the ways to collaborate externally using Teams. The descriptions of Azure AD Direct Connect, Azure B2B Collaboration, and external federation (one-to-one chat and calls with people in other organizations) were accurate, and the information was well-timed. Many Microsoft 365 tenants are figuring out their external collaboration strategy and wondering where to put their effort over the coming years,

I’ve heard a few commentators say that Azure AD guest accounts now have limited usefulness. The theory is that everyone will move to shared channels. I think that’s overstating the case more than a little. Shared channels are very convenient, especially in their accessibility. There’s no need to switch to another tenant to access information. Shared channels are right there, listed by your favorite Teams client alongside the other teams and channels from your home tenant.

For now, shared channels are only sharable with accounts from other Microsoft 365 tenants. Shared channels will reveal their full potential when they support access from Microsoft Services Accounts (MSAs), a feature that Microsoft is working on.

Azure AD Guest Accounts Still Super-Valuable

But even when that happens, I think Azure AD guest accounts still continue to offer a lot of value. Switching to another tenant can slow access down a tad, but switching performance is much faster now than it used to be (even if it’s not one of the improvements listed in Microsoft’s latest news about Teams performance), and I think I am now immune to the need to switch to a tenant to collaborate with people in that organization. Muscle memory is a great thing and it’s one of the reasons why many of the teams I use feature lots of Azure AD guest accounts (Figure 1).

Team with multiple Azure AD guest accounts in its membership
Figure 1: Azure AD Guest Accounts are a big part of a many teams

Once added to a tenant, a guest has full access to the teams and groups they are a member of. Within a single team, they can access up to 200 regular channels and, if added as a member, they can participate in another 30 private channels. A shared channel has its own roster of members and if a team supports multiple shared channels, the channel owner must share with external users in each channel.

Most of the external organizations I work with have teams with multiple channels. Some are channel-happy and explore the limits set by Teams. Others are more restrained. Even so, the teams usually have several channels to support discussions about different topics. Private channels don’t seem to be popular but are present and I use some in other tenants. Shared channels might be a better choice than private channels in many cases, especially when MSA support is available.

The Question of Guest Hygiene

Mention guest hygiene and you’re probably thinking about the mess unwelcome guests can make in your house. Microsoft says that using Azure B2B Collaboration means that organizations should implement “a guest hygiene process to remove guest accounts when no longer needed.” In other words, instead of remaining passive and letting Azure AD guest accounts accumulate over time, organizations should review old guest accounts and figure out if they should remain.

A simple check against age will often highlight unused guest accounts. If you have Azure AD Premium P2 licenses, Microsoft offers a more sophisticated account review process. No matter what approach you take, it’s a good idea to run an annual review to clean out old accounts.

Overall, it’s likely that Azure AD guest accounts will remain the foundation for most external collaboration based on Microsoft 365 groups and teams. Shared channels will nibble away and take some of the work, but it won’t take over from Azure AD guest accounts in the immediate future.

]]>
https://office365itpros.com/2022/06/06/azure-ad-guest-accounts-valuable/feed/ 2 55362
Why Teams Sometimes Won’t Allow External Users In https://office365itpros.com/2022/05/26/teams-blocks-external-users/?utm_source=rss&utm_medium=rss&utm_campaign=teams-blocks-external-users https://office365itpros.com/2022/05/26/teams-blocks-external-users/#comments Thu, 26 May 2022 01:00:00 +0000 https://office365itpros.com/?p=55245

Teams Blocks External Users as Guests and From Sharing Channels

A reader asked why Teams blocks external users. In this case, they had difficulties adding a new guest account to a team’s membership. Anytime they attempted to add the guest by typing in their email address, Teams responds with “we didn’t find any matches” (Figure 1).

Teams won't add a new guest
Figure 1: Teams won’t add a new guest

The error text isn’t very useful, and Microsoft could improve it. What it means is that Teams couldn’t match the email address of the external user against the set permitted for the team.

The usual problem is that something blocked guest access for the team. This can happen because:

  • The organization blocks guest access for all teams.
  • The organization uses sensitivity labels to control guest access, and the label assigned to the team blocks guests.
  • If the organization doesn’t use sensitivity labels, administrators can block guest access for a specific team by updating the Azure AD directory settings for the Microsoft 365 group (this is what sensitivity labels do when they block access).
  • The user attempting to add the guest doesn’t have the necessary permission. Normally, team owners can add guests, but the organization can restrict this capability to administrators.

If guests can join other teams, no organization-wide block on guests is present. If one is, administrators can lift it by updating the Microsoft 365 Groups settings in the Microsoft 365 admin center (Figure 2).

Organization setting allowing guests to join Teams and Microsoft 365 Groups
Figure 2: Organization setting allowing guests to join Teams and Microsoft 365 Groups

Container Management Blocks

If the organization uses sensitivity labels for container management, the block might be present because the team inherited the setting from its sensitivity label, so it’s the next thing to check. Go to the Information protection section of the Microsoft Purview Compliance portal and check the label assigned to the team. Its settings (or maybe just the description – Figure 3) will tell you if the label blocks guest members.

Sensitivity label settings could block guest access
Figure 3: Sensitivity label settings could block guest access

Not all organizations use sensitivity labels for container management. The block on guest access can be applied using PowerShell, so you’d need to check the group settings to make sure that they permit guest access (or not).

Finally, check the External collaboration settings under External identities in the Azure AD admin center to check that someone hasn’t restricted the ability of group owners to add guests.

Azure AD B2B Collaboration Blocked Domains

While discussing External collaboration settings, we should cover a related issue, which is when group owners can’t add a guest account because the Azure AD B2B collaboration policy blocks the guest’s domain. When this happens, Teams accepts the external email address, but then fails when it attempts to create the guest account (Figure 4).

Teams can't add a guest from a blocked domain
Figure 4: Teams can’t add a guest from a blocked domain

The solution is to amend the Azure B2B collaboration policy to remove the block on the domain. If this isn’t possible, the external person can never become a guest using an email address from the blocked domain.

Can’t Share a Shared Channel

Teams displays the unhelpful error text as a catch-all for multiple conditions. Teams flags the same error if you attempt to share a shared channel with an external user from another Microsoft 365 tenant when cross-tenant access settings don’t allow access from the external user’s domain (Figure 5).

Teams can't add an external user to a shared channel because no trust exists
Figure 5: Teams can’t add an external user to a shared channel because no trust exists

The same kind of logic applies. You asked Teams to share a channel. It checked the set of domains it can share channels with and found that the requested domain isn’t in the set, so issued the “we didn’t find any matches” error.

In this case, the solution is to amend the cross-tenant access settings in your tenant to allow inbound access for external users from the other domain, and to ask the administrator of the other domain to permit outbound access to your domain. Cross-tenant access works on a mutual trust basis, so you can’t share a channel with someone from another unless their tenant is happy for this to happen.

Take Your Time

After making any changes, it’s important to be patient and allow the changes to replicate within Azure AD and Teams. Eventually (after about 24 hours), the planets align, and permissions are in place, and you’ll be able to add external users as guests to team memberships or share channels with people in other tenants.


Learn about managing guest access for Teams and Microsoft 365 Groups and the rest of Office 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

]]>
https://office365itpros.com/2022/05/26/teams-blocks-external-users/feed/ 4 55245
Graph X-Ray Tool Helps PowerShell Developers Master the Graph https://office365itpros.com/2022/05/23/graph-x-ray-powershell/?utm_source=rss&utm_medium=rss&utm_campaign=graph-x-ray-powershell https://office365itpros.com/2022/05/23/graph-x-ray-powershell/#comments Mon, 23 May 2022 01:00:00 +0000 https://office365itpros.com/?p=55170

Even in First Release, Graph X-Ray Proves Its Worth

When Microsoft decided to build the administrative tools for Exchange Server 2007 around PowerShell, they realized that it would take time for administrators to become accustomed to PowerShell. Sensibly, Microsoft included a cmdlet logging facility in the Exchange Management Console (EMC) to allow administrators to see the PowerShell code used to execute different actions, such as creating a new mailbox. Cmdlet logging gave administrators prototype code to build scripts around and it’s still the best learning tool I have encountered in a Microsoft server product.

Roll on sixteen years and cmdlet logging doesn’t exist in the modern Exchange Admin Center (EAC). Many, including me, have moaned at Microsoft about this deficiency. One response is that EAC is no longer built on PowerShell, which makes it very difficult to generate and display PowerShell code for administrators to copy and reuse. It’s a great pity.

All of this brings me to a new browser extension called Graph X-Ray. Created by Microsoft employees but not a formal product, Graph X-Ray displays the Graph API commands run to execute actions in consoles like the Azure AD admin center and the Intune admin center. Not every action in these consoles depends on Graph APIs, but enough do in important areas like users, groups, and device management to make this an interesting facility.

Raw Graph or Graph SDK

Anyone developing code for Microsoft 365 can get value from Graph X-ray, whether you’re using compiled languages like C# or JavaScript or writing PowerShell scripts. Using Graph APIs in PowerShell normally means that scripts run faster, especially if the code must process more than a few objects. Scripters have the choice to include “raw API calls” or use cmdlets from the Microsoft Graph PowerShell SDK. The script to create a tenant configuration report is a good example of using raw API calls while the script to generate an Office 365 licensing report uses the SDK cmdlets. In either case, you need to understand how Graph API queries are formed and executed, and that’s where the Graph X-Ray extension proves its worth.

Restoring Deleted Microsoft 365 Groups

Take the example of restoring a deleted Microsoft 365 group. Before you can restore a group, you need to know what groups are in a soft-deleted state. Groups remain in the soft-deleted state for 30 days after deletion to allow administrators to restore groups using options in the Microsoft 365 and Azure AD admin centers. After the 30-day retention period lapses, Azure AD removes the groups permanently and they become irrecoverable.

In a large tenant, many groups might be waiting for permanent deletion, including inactive groups removed by the Microsoft 365 Groups Expiration policy. The Get-UnifiedGroup cmdlet can generate a list of soft-deleted groups using a command like this:

Get-UnifiedGroup -ResultSize Unlimited -IncludeSoftDeletedGroups:$True | ? {$_.WhenSoftDeleted -ne $Null} | Sort WhenSoftDeleted | Format-Table DisplayName, PrimarySmtpAddress, WhenSoftDeleted

The cmdlet works, but it’s slow. To speed things up, I tried using the Get-MgDirectoryDeletedItem SDK cmdlet. The cmdlet works when listing deleted user accounts, but no matter what I did, I couldn’t find a way to make it return a list of deleted groups.

Using the Graph X-Ray

I downloaded the Graph X-Ray extension for the Edge browser add-on (other versions are available for Chrome and a Microsoft Store app). To load the add-on, I opened the Developer Tools option in Edge and selected Graph X-Ray. A new blade opened in the browser to display the Graph API commands used for actions performed in the Azure AD admin center (Figure 1).

Viewing Graph commands with the Graph X-Ray extension
Figure 1: Viewing Graph commands with the Graph X-Ray extension

It’s important to emphasize that this is very much an MVP release. Things are by no means perfect, but enough value is present to allow Graph X-Ray to be very helpful. For example, the command reported when the Azure AD admin center lists deleted groups is:

Get-MgDirectoryDeletedItem -DirectoryObjectId $directoryObjectId -Property "id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,deletedDateTime,isAssignableToRole" -Sort "displayName%20asc" -Top 20

This is fine, but nowhere does it tell you how to populate the $directoryObjectId variable. On a more positive note, the raw Graph API query showed the structure needed to return deleted groups, and I was able to use that information to submit the query with the Invoke-MgGraphRequest SDK cmdlet, which worked. It’s worth noting that the Invoke-MgGraphRequest cmdlet exists to allow scripts to execute raw Graph API queries when an SDK cmdlet isn’t available (or doesn’t work).

Equipped with new-found knowledge about how to find deleted groups, I coded this script to report the set of soft-deleted groups including when each group is due for permanent deletion.

Connect-MgGraph
Select-MgProfile Beta
$uri = "https://graph.microsoft.com/beta/directory/deleteditems/microsoft.graph.group?`$select=id,displayName,groupTypes,deletedDateTime&`$orderBy=displayName%20asc&`$top=100"
[array]$Groups = (Invoke-MgGraphRequest -Uri $Uri).Value
If (!($Groups)) { write-Host "No deleted groups available for recovery" ; break }
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file for report
$Now = Get-Date
ForEach ($Group in $Groups) {
     $PermanentRemovalDue = Get-Date($Group.deletedDateTime).AddDays(+30)
     $TimeTillRemoval = $PermanentRemovalDue - $Now
     $ReportLine = [PSCustomObject]@{ 
          Group                = $Group.DisplayName
          Id                   = $Group.Id
          Deleted              = $Group.deletedDateTime
          PermanentDeleteOn    = Get-Date($PermanentRemovalDue) -format g
          DaysRemaining        = $TimeTillRemoval.Days        } 
       $Report.Add($ReportLine) 
}
$Report | Sort {$_.PermanentDeleteOn -as [datetime]} | Out-GridView

The add-on includes the facility to download the commands it captures in a script (GraphXRaySession.PS1). There’s likely to be some duplication of commands in the downloaded script, but it’s great to have such an easy method to copy the commands for later use.

More Insight from Graph X-Ray

Moving on to restoring a soft-deleted group, Microsoft’s documentation for the Restore-MgDirectoryObject cmdlet is woefully deficient in terms of useful examples. An attempt to pass the identifier of a deleted group to the cmdlet failed:

Restore-MgDirectoryObject -DirectoryObjectId $GroupId
Restore-MgDirectoryObject : Resource '2eea84f2-eda3-4a72-8054-5b52c063ee3a' does not exist or one of its queried reference-property objects are not present.

Once again, I turned to Graph X-Ray to find out what command powered the restore deleted group option in the Azure AD admin center. The raw API reported by Graph X-Ray is a POST (update) query like this:

POST /directory/deleteditems/2eea84f2-eda3-4a72-8054-5b52c063ee3a/restore

It’s easy to take this command and repurpose it for use with the Invoke-MgGraphRequest cmdlet:

$uri = “https://graph.microsoft.com/beta/directory/deleteditems/8783e3dd-66fc-4841-861d-49976f0617c0/restore”
Invoke-MgGraphRequest -Method Post -Uri $Uri

More Please!

I wish Microsoft would provide similar insight across all the Microsoft 365 admin consoles. Being able to see the Graph API commands used to perform real-life actions is a powerful learning aid. If Microsoft is serious about driving the adoption of the Graph and the Graph SDK, they could do worse than invest in this kind of tooling. I hope that they do.


Keep up to date with developments like the Graph API commands by subscribing to the Office 365 for IT Pros eBook. Our monthly updates make sure that our subscribers understand the most important changes happening across Office 365.

]]>
https://office365itpros.com/2022/05/23/graph-x-ray-powershell/feed/ 1 55170
Use Azure AD Access Reviews to Check for Inactive Guests https://office365itpros.com/2022/05/17/azure-ad-access-review/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-access-review https://office365itpros.com/2022/05/17/azure-ad-access-review/#comments Tue, 17 May 2022 01:00:00 +0000 https://office365itpros.com/?p=55074

Remove Inactive Guests from Microsoft 365 Groups

Azure AD access reviews are a premium Identity Governance feature that helps organizations conduct periodic reviews of user and guest access to resources, including the membership of Microsoft 365 groups. Automation of this kind is most valuable in large enterprises where administrators can find it difficult to keep track of groups, guests, permissions, and role assignments. Further automation and reporting of access reviews are possible using a Graph API.

Tenants can enable a 30-day free trial of Azure AD Premium P2, which you’ll need if you want to test access reviews before deciding to make a long-term commitment. Licensing for guest accounts in the groups within the scope of the review is covered by Azure AD’s Monthly Active User (MAU) billing model, which requires an Azure subscription.

Finding Inactive Guests

Soon after Microsoft introduced Azure AD guest support for Office 365 Groups in late 2016, it became clear that not much administrative support was available to manage guest accounts. Since then, the number of guest accounts in tenants has exploded, largely due to the success of Teams, but also because SharePoint Online creates guest accounts for document sharing. However, the toolset available to manage the burgeoning guest accounts is still sparse.

Recently, Microsoft introduced a new preview feature for Azure AD access reviews to allow organizations to conduct an access review for inactive guest accounts, defined as “those who have not signed in either interactively or non-interactively to the tenant.”

Creating an access review to look for inactive guests is simple. The review covers:

  • All Microsoft 365 Groups with guest members, checking only guest users.
  • The period to determine inactivity can be anything from 1 to 730 days.

Other tabs have settings to cover whether the review is a one-off event or happens on a schedule, what to do if reviewers don’t respond, and what happens when the review period completes.

Figure 1 shows the access review I created to locate guests inactive for the last 365 days.

Creating an Azure AD access review for inactive guest accounts
Figure 1: Creating an Azure AD access review for inactive guest accounts

Reviewing Inactive Guests

After creating the review, Azure AD background processing locates Microsoft 365 groups in the tenant that have guest members. Azure AD uses sign-in records for the review period to determine if any guests in a group are deemed inactive, Azure AD sends email to the group owner (Figure 2) to ask them to review the inactive groups and decide if the membership in the group should continue for the inactive guests.

Email notification for a group owner to review inactive guests
Figure 2: Email notification for a group owner to review inactive guests

Clicking the Start review link in the message brings the group owner to a page in MyAccess.microsoft.com to allow them to see the inactive guests and make a decision for each (Figure 3). In this case, Azure AD was unable to find any sign-in data for the guest account.

Performing an Azure AD access review for an inactive guest
Figure 3: Performing an Azure AD access review for an inactive guest

A group owner can decide to ignore the review, in which case the settings for the access review determines what happens. This might be to do nothing; it could also be to remove access for the inactive guest. It’s best if group owners perform the review, even if administrators might have to cajole them to do the work.

After the review period finishes, Azure AD implements the review decisions and removes the inactive guests or leaves them in place.

Sounds Good but What About Outlook Groups

Running an access review to remove inactive guests from group membership sounds like a great idea and the implementation works. However, there’s one big flaw in the scheme and that’s the dependency on sign-in data. This is understandable because it’s an Azure AD review and the best data available to Azure AD to figure out if a guest account is in use is their sign-in history.

The problem is that some guest accounts can be active without ever signing into a tenant. Guest members of Outlook groups (the original implementation of Office 365 groups) use email to communicate and don’t need to ever sign in to the tenant hosting the group unless they want to access other group resources, like its SharePoint Online site or Planner.

I have multiple Outlook groups in this category. The access review highlighted most of the guests in these groups. The only guests that the access review did not tag were those that sign into the tenant to use Teams or another application. Perhaps Microsoft will introduce additional checks to help detect truly inactive guest accounts when this feature moves from preview to generally available status.

The bulk of Microsoft 365 group activity now focuses on Teams, which is an application that signs in every hour during a session. There’s no danger that Azure AD won’t know when guest accounts used with Teams are inactive.

Do-It-Yourself Inactive Guest Reviews

You don’t need to pay for Azure AD access reviews to find potentially inactive guest accounts. Over the years, I’ve written about this topic, most recently to describe my approach to detecting, reporting, and managing inactive guest accounts using PowerShell. An even simpler approach is to create a report for all guest accounts over a certain age together with their group membership.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/05/17/azure-ad-access-review/feed/ 2 55074
Track User Access to Teams Shared Channels with Entra ID Sign-In Logs https://office365itpros.com/2022/03/31/teams-shared-channels-access/?utm_source=rss&utm_medium=rss&utm_campaign=teams-shared-channels-access https://office365itpros.com/2022/03/31/teams-shared-channels-access/#comments Thu, 31 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54326

Know Who’s Collaborating in Teams Shared Channels From Outside Your Tenant

Updated 4 March 2024

When Microsoft launched Teams shared channels into public preview (according to MC390413, shared channels will GA in mid-July 2022) the rubber hit the road as tenant administrators tried to figure out the complexities of managing shared channels in production use. It’s true that Microsoft conducted a long private preview with many customers to get shared channels to the point where they squashed obvious bugs and delivered usable software. However, once software is exposed to the kind of examination that an application with 270 million monthly active users can create, other questions bubble to the surface.

Which brings me to the topic of controlling user access to shared channels. The cross-tenant access settings in the External identities section of the Entra admin center control which tenants your organization can access using Entra ID B2B Direct Connect. This is the underlying authentication mechanism for Teams shared channels. It allows users to authenticate in their home tenant and use that authentication, including MFA and device state claims, to access resources in other tenants, if permitted by other tenants.

Entra ID Sign-Ins Track Cross-Tenant Access

Microsoft’s guidance for cross-tenant access settings advises that you can use Entra ID sign in logs to figure out user access to other tenants. It’s true that you can use the PowerShell snippet provided there, but I think we can do better.

The code uses the Get-MgBetaAuditLogSignIn cmdlet from the Microsoft Graph PowerShell SDK to look for sign in records where the resource tenant identifier (the organization delivering a resource like Teams) is not the same as the home tenant identifier (the organization hosting the sign in logs).

$TenantId = (Get-MgOrganization).Id
Get-MgBetaAuditLogSignIn -Filter "ResourceTenantId ne '$TenantId'" -All:$True

The code works (the All switch doesn’t need $True), but the result of the query is a set of sign-in records for both Entra ID B2B Collaboration (guest accounts) and Entra ID B2B Direct Connect. This is a better filter if you want to focus on access to Teams shared channels:

Get-MgBetaAuditLogSignIn -Filter "ResourceTenantId ne '$TenantId' and CrossTenantAccessType eq 'b2bDirectConnect'" -All

Next, although you might recognize the identifier for your tenant, it’s unlikely that you’ll know the identifiers for other tenants (like 22e90715-3da6-4a78-9ec6-b3282389492b). To translate these identifiers into human-friendly tenant names, we need another method.

We’re already connected to the Microsoft Graph, so we can use a Graph query to resolve the identifier into a tenant name.

Finding Tenant Names

Fortunately, a beta query called findTenantInformationByTenantId does the trick. There’s little documentation available, but by running it through the Invoke-MgGraphRequest cmdlet (runs any Graph query when an SDK cmdlet is unavailable), we can retrieve tenant data:

$ExternalTenantId = $Record.ResourceTenantId
$Uri = "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$ExternalTenantId')"
$ExternalTenantData = Invoke-MgGraphRequest -Uri $Uri -Method Get

The tenant information returned is:

Name                           Value
----                           -----
@odata.context                 https://graph.microsoft.com/beta/$metadata#microsoft.graph.tenantInformation
tenantId                       22e90715-3da6-4a78-9ec6-b3282389492b
displayName                    o365maestros
federationBrandName
defaultDomainName              o365maestros.onmicrosoft.com

I assume this web site, which can return the identifier of any Microsoft 365 tenant, uses a similar API.

Flow of the Script

The flow of the PowerShell script to analyze sign-in data is therefore:

  • Find sign-in records for Entra ID Direct Connect activity. If you want to process records for Azure B2B Collaboration, change the filter to remove the check against the CrossTenantAccessType property.
  • Extract data from each record, including resolving external tenant identifiers to tenant names.
  • Report.

In normal circumstances, the sign-in data will feature just a few tenants. It would be slow to run a query to resolve the tenant identifier for every record. To ensure performance, the script resolves a tenant name the first time it is encountered and stores the tenant name identifier and name in a hash table. When the script processes subsequent records for the same tenant, it reads the information from the hash table.

You can download the script from GitHub. Normal warnings apply: use at your peril, etc. and please fix my bugs…

Script Outputs

The output of the script is a PowerShell list containing details of sign-ins which use cross-tenant access to connect to Teams shared channels in external tenants (Figure 1).

Viewing information about user connects to Teams shared channels
Figure 1: Viewing information about user connects to Teams shared channels

The data can be parsed to reveal statistics like which tenants use cross-tenant access:

$Report | Group TenantName | Sort Count -Descending | Format-Table Name, Count

Or to reveal the names of the users who connect to external tenants:

$Report | Group User | Sort Count -Descending | Format-Table Name, Count

Name       Count
----       -----
Sean Landy     4
James Ryan     3
Ken Bowers     3

And so on. I’m sure you’ll find other ways to use the information to track what’s happening with Teams shared channels. The point is that the data is there if you need it. All that’s required is a little massaging of the information.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/03/31/teams-shared-channels-access/feed/ 10 54326
Assign Azure AD Roles to User Accounts with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/03/30/azure-ad-role-assignments/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-role-assignments https://office365itpros.com/2022/03/30/azure-ad-role-assignments/#respond Wed, 30 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54307

So Many Roles to Work With

A bunch of built-in Azure AD roles exist to help manage resources. Microsoft adds more to the list over time. Not all the roles exist in Microsoft 365 tenants, but you can expect to find at least twenty roles, including:

  • Global administrator.
  • Exchange administrator.
  • SharePoint administrator.
  • Teams administrator.
  • Compliance administrator.
  • Reports reader.
  • User administrator.
  • Helpdesk administrator.

These are Azure AD roles. Another set of compliance roles exist like “Fraud Investigators” and “Disposition Processors,” used to grant the ability to perform information governance and protection tasks. As explained in this post, the Exchange Online Get-RoleGroup cmdlet reveals both types, but for the purpose of this article, I focus on the assignable Azure AD roles.

Finding the List of Roles

In my tenant, there are 31 Azure AD roles in use. I know this because I ran the Get-MgDirectoryRole cmdlet. Here’s what I see (list trimmed for space):

[array]$DirectoryRoles = Get-MgDirectoryRole | Sort DisplayName
$DirectoryRoles | Format-Table DisplayName, Id

DisplayName                                Id
-----------                                --
Attack Simulation Administrator            f28eae22-7444-492d-bb0a-d3e41f8f9d4f
Attribute Assignment Administrator         b1042b1d-c84a-448e-9ca8-e6ad85e4fb65
Attribute Definition Administrator         327df668-5ea8-4ad8-b153-75d326b3c7d1
Azure AD Joined Device Local Administrator 268030c9-556f-47a6-a167-5970cb734558
Billing Administrator                      07308ce7-381b-4fb1-b31e-398b8a66c946
Compliance Administrator                   88b6939a-ef4b-4e8e-9aba-00f4f8447e66
Compliance Data Administrator              fdc30bad-3a16-4c24-ac89-79b73ad9468d
Customer LockBox Access Approver           1402c923-f478-4a9c-82b1-0511726c43bd

This is functionally equivalent to running the Get-AzureADDirectoryRole cmdlet from the soon-to-deprecated Azure AD module. Other Azure AD administrative roles exist but haven’t been used. You can see these roles by running the Get-MgDirectoryRoleTemplate cmdlet.

The role identifier is the important piece of information because we need this to assign a role to a user account. To store the role identifier in a variable to make it easier to use, we filter it from the set of roles. For instance, these commands return the role identifier for the Global administrator and Teams administrator roles:

$GlobalAdminRoleId = $DirectoryRoles | ? {$_.DisplayName -eq "Global administrator"} | Select -ExpandProperty Id
$TeamsAdminRoleId  = $DirectoryRoles | ? {$_.DisplayName -eq "Teams administrator"} | Select -ExpandProperty Id

Assigning Azure AD Roles to User Accounts

The New-MgDirectoryRoleMemberByRef cmdlet assign an Azure AD role to a user account. This cmdlet works like the New-MgGroupOwnerByRef cmdlet used to assign a new user to an Azure AD group (see this post about group management with the Microsoft Graph PowerShell SDK).

In this example, we first fetch the identifier for a user account and the set of current holders of the role. We then check the user identifier against the set of current role holders and if the account is not in the list, we assign the role using New-MgDirectoryRoleByRef:

$User = Get-MgUser -UserId Ken.Bowers@Office365itpros.com
$RoleMembers = Get-MgDirectoryRoleMember -DirectoryRoleId $TeamsAdminRoleId
If ($User.Id -notin $RoleMembers.Id) {
  Write-Host ("Adding user {0} to the Teams administrator role" -f $User.DisplayName)
  New-MgDirectoryRoleMemberByRef -DirectoryRoleId $TeamsAdminRoleId -BodyParameter @{"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($user.Id)"}
}

By comparison, the equivalent Azure AD cmdlet is simpler:

Add-AzureADDirectoryRoleMember -ObjectId $TeamsAdminRoleId -RefObjectId $User.Id

To check that the correct account was added to the Azure AD role, fetch the set of updated role members and loop through the set to retrieve the display name of each role holder:

$RoleMembers = Get-MgDirectoryRoleMember -DirectoryRoleId $TeamsAdminRoleId
ForEach ($RoleMember in $RoleMembers) {
    Write-Host $RoleMember.AdditionalProperties["displayName"]}

Alternatively, check the assignments through Azure AD admin center (Figure 1):

Checking Azure AD role assignments in the Azure AD admin center
Figure 1: Checking Azure AD role assignments in the Azure AD admin center

There doesn’t appear to be a cmdlet available currently to remove a role assignment comparable to the Remove-AzureADDirectoryRoleMember cmdlet. This might be because Microsoft hasn’t yet added such a cmdlet to the SDK. Until they do, run the Azure AD cmdlet or use a graph API query to remove role assignments – or remove the assignments from the Azure AD admin center.

More Learning Required

Like many topics related to the Microsoft Graph PowerShell SDK, some more work is required to fully understand the intricacies of role assignment management, especially in deleting assignments. The good news is that this area is under active development. We can but wait for progress.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/03/30/azure-ad-role-assignments/feed/ 0 54307
Basic User Account Management with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/03/24/entra-id-user-accounts-powershell/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-user-accounts-powershell https://office365itpros.com/2022/03/24/entra-id-user-accounts-powershell/#comments Thu, 24 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54188

Preparing to Migrate Away from Old AzureAD cmdlets

Updated: 15 March, 2023

Manage Entra ID user accounts

I received a lot of reaction when I described Microsoft’s new deprecation schedule for the AzureAD and MSOL modules. In summary, you have until 30 March 2024 to update scripts which assign licenses to user accounts. After this, Microsoft will disable the cmdlets. The other cmdlets will continue working after Microsoft deprecates the modules. However, they’ll be out of support, which is not a good foundation for PowerShell scripts used to automate administrative processes, like managing Entra ID user accounts.

With time running out, it’s obvious that tenants need to inventory and upgrade scripts. One reaction I received was that there’s a dearth of information to help people who are less familiar with PowerShell and might have inherited ownership of some scripts. My response is that the community will publish examples over time, just like they did when Microsoft launched the AzureAD module in 2016 and the Exchange Online management REST-based cmdlets at Ignite 2019. Let’s hope this is true.

Over on Practical365.com, I compare creating a new Entra ID user account and assigning licenses to the account using both the old AzureAD module and the Microsoft Graph PowerShell SDK. In this post, I consider some additional basic user account management actions.

Connections

The basics of using the Microsoft Graph PowerShell SDK (the SDK) is to connect. You can connect interactively (delegated access) or with certificate-based authentication (application access). You can also run SDK cmdlets in Azure Automation runbooks. The simplest approach is to run Connect-MgGraph interactively, which signs into the Graph using the account you signed into PowerShell with.

Scopes

SDK cmdlets interact with Microsoft Graph APIs. A big difference between the SDK and AzureAD modules is that the SDK forces you to request the set of Graph permissions you want to use. The SDK uses a service principal to hold the permissions, and over time, that service principal might become overly permissioned. It’s a thing to keep an eye on.

In this example, we define an array of Graph permissions we wish to use, and then connect. If you request a permission that the SDK service principal doesn’t already hold, you’ll see an administrator prompt for consent.

$RequiredScopes = @("Directory.AccessAsUser.All", "Directory.ReadWrite.All", "User.ReadWrite.All", “User.Read.All”)
Connect-MgGraph -Scopes $RequiredScopes -NoWelcome

Welcome To Microsoft Graph!

Updating Properties for Entra ID User Accounts

Let’s assume that you’ve created the Sue.Ricketts@Office365itpros.com account using the New-MgUser cmdlet as described in this article and stored the user identifier for the account in the $UserId variable.

$UserId = (Get-MgUser -UserId Sue.Ricketts@office365itpros.com).Id

To update the properties of a user account, run the Update-MgUser cmdlet.

Update-MgUser -UserId $UserId -JobTitle "Senior Editor" -State NY

Updating Email Properties for an Account

You can’t update the proxyAddresses property of a user account because the Graph treats it as read-only, possibly because Exchange Online takes care of email proxy address management. However, if you change the UserPrincipalName property of an account, Update-MgUser sets the primary SMTP address of the account to match the new user principal name. The logic here is likely that it is best practice to match the user principal name and primary SMTP address. In most cases, this is true and it’s a good idea to have the cmdlet behave like it does. However, in some circumstances, you might decide to have different values in these properties.

In both situations, you should use the Exchange Online Set-Mailbox cmdlet to update proxy addresses. For example, this command adds a new SMTP proxy address to the mailbox identified by the $UserId variable:

Set-Mailbox -Identity $UserId -EmailAddresses @{Add="Johnnie.West@Office365itpros.com"}

This command updates the primary SMTP address for the mailbox without changing the user principal name:

Set-Mailbox -Identity $UserId -WindowsEmailAddress Johnnie.West@Office365itpros.com

Exchange Online uses a dual-write mechanism to make sure that any change made to mailboxes happens simultaneously to the underlying user account.

Updating a User’s Manager

The manager of a user account is updated by reference (to their account) rather than simply updating a property. To update the manager of a user account, run the Set-MgUserManagerByRef cmdlet after storing the identifier of the manager’s account in a variable:

$ManagerId = (Get-MgUser -UserId Terry.Hegarty@office365itpros.com).Id
Set-MgUserManagerByRef -UserId $UserId `
   -AdditionalProperties @{
     "@odata.id" = "https://graph.microsoft.com/v1.0/users/$ManagerId" }

To check that the manager update was successful, we need to fetch the manager’s details (expanded into a dictionary object) and retrieve the property we want.

$ManagerData = Get-Mguser -UserId $UserId -ExpandProperty Manager
$ManagerData.Manager.AdditionalProperties['displayName']
Terry Hegarty

You can also use the Get-MgUserManager cmdlet to return the manager of an account.

Get-MgUserManager -UserId Chris.Bishop@Office365itpros.com | Select-Object @{n="DisplayName";e={$_.AdditionalProperties.displayName}},@{n="UserPrincipalName";e={$_.AdditionalProperties.userPrincipalName}}

DisplayName UserPrincipalName
----------- -----------------
James Ryan  James.Ryan@office365itpros.com

Obviously, Microsoft has made defining and retrieving the manager of an account more complex than it needs to be. It would be nice if they would hide the complexity in code and deliver some straightforward cmdlets that don’t create friction when the time comes to update scripts.

Another way of updating user account properties is with the Invoke-MgGraphRequest cmdlet, which runs a Graph API query. The advantage of this cmdlet is that if you can’t find a way to do something with an SDK cmdlet, you can refer to the Microsoft Graph documentation, find some example code, and run or repurpose it.

In this example, we create a hash table to hold the properties we want to update, convert the table to a JSON object, and pass it to a PATCH query run by Invoke-MgGraphRequest:

$Parameters = @{
   JobTitle = "Managing Editor, Periodicals"
   State = "Vermont"
   OfficeLocation = "Burlington" } | ConvertTo-Json
Invoke-MgGraphRequest -Method PATCH -Uri "https://graph.microsoft.com/v1.0/users/Sue.Ricketts@office365itpros.com" -Body $Parameters -ContentType "application/json; charset=utf-8"

Delete a User Account

The Remove-MgUser cmdlet soft-deletes a user account and moves it into Entra ID’s deleted items container, where it remains for 30 days until Entra ID permanently deletes the object. The cmdlet is very simple, and it doesn’t prompt for confirmation before proceeding to delete a user account.

Remove-MgUser -UserId $UserId

If you need to restore a soft-deleted account, run the Restore-MgUser cmdlet and pass the object identifier of the account you want to restore. See this article for information about how to list the set of soft-deleted user accounts.

Restore-MgUser -UserId $UserId

I’ve experienced some issues with the Restore-MgUser cmdlet in the 1.9.3 release of the SDK which I have reported to Microsoft. Basically, the cmdlet doesn’t work in this release. I’m sure the bug will be fixed soon.

Finding User Accounts

We’ve already seen how the Get-MgUser cmdlet fetches information for an individual user account. It also fetches sets of accounts. To fetch all the accounts in the tenant, run:

[array]$Users = Get-MgUser -All

I always specify that the variable used as the target for a set of objects is an array. This makes it easy to find how many objects are returned, as in:

Write-Host $Users.Count “User accounts found”

Note that unlike Graph API queries, the Get-MgUser cmdlet takes care of data pagination for the query and fetches all available objects.

If you don’t specify the All switch, the cmdlet fetches the first 100 accounts. You can fetch a specific number of accounts using the Top parameter, up to a maximum of 999.

[array]$Top500 = Get-MgUser -Top 500

The Filter parameter uses server-side filtering to restrict the amount of data returned. For instance, here’s how to find all the guest accounts in a tenant:

[array]$Guests = Get- MgUser -Filter "usertype eq 'Guest'" -All

While this filter returns the accounts who usage location (for Microsoft 365 services) is the U.S.

Get-MgUser -Filter "usagelocation eq 'US'"

You can combine properties in a filter. For example:

Get-MgUser -Filter "usagelocation eq 'US' and state eq 'NY'"

Another interesting filter is to find accounts created in a specific date range. This command finds all tenant non-guest accounts created between January 1, 2022 and Matrch 24. Note the trailing Z on the dates. The Graph won’t treat the date as valid if the Z is not present.

Get-MgUser -Filter "createdDateTime ge 2022-01-01T00:00:00Z and createdDateTime le 2022-03-24T00:00:00Z and usertype eq ‘Member’"

Support for SDK Problems via GitHub

Hopefully, the examples listed above are useful in terms of understanding the SDK cmdlets to perform basic management of Entra ID user accounts. If you run into a problem when converting scripts to use SDK cmdlets, you can report the problem (or browse the current known issues) on GitHub. Happy migration!

]]>
https://office365itpros.com/2022/03/24/entra-id-user-accounts-powershell/feed/ 9 54188
Delete and Restore Entra ID User Accounts with the Microsoft Graph PowerShell SDK https://office365itpros.com/2022/03/23/delete-entra-id-user-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=delete-entra-id-user-accounts https://office365itpros.com/2022/03/23/delete-entra-id-user-accounts/#comments Wed, 23 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54175

Understanding How to Delete Entra ID User Accounts and Restore Them Afterwards is a Critical Skill

According to message center notification MC344406 (18 March), in early April Microsoft plans to roll-out the capability of recovering deleted service principal objects. Service principals are critical parts of registered Entra ID apps, such as the apps used to execute Microsoft Graph API queries with PowerShell. They’re also used in Azure Automation accounts, the Microsoft Graph PowerShell SDK, and managed identities. In all cases, the service principals hold the permissions needed for an app or account to operate. The worldwide roll-out to all tenants should complete by late May.

When the capability is available, any time an administrator deletes a service principal (for instance, because a registered app is no longer needed) using the Entra admin center, PowerShell (using Remove-AzureADServicePrincipal), or the Microsoft Graph API, Entra ID will place the service principal into a soft-deleted state. This already happens today for user, group, device, and application objects.

Deleted Entra ID objects stay in the deleted items container for 30 days. When the retention period elapses (extending to maybe a few days afterwards), Entra ID proceeds to permanently delete the object.

During the retention period, administrators can restore an object, which makes it easy to recover if someone deletes an important item by accident. For now, the list deleted items API doesn’t support service principals, but it will after the roll-out. Figure 1 shows user objects in the deleted items container as viewed through the Graph Explorer.

Viewing deleted Entra ID user accounts via the Graph Explorer

Delete Entra ID user account
Figure 1: Viewing deleted Entra ID user accounts via the Graph Explorer

Using Old Azure AD Cmdlets

MC344406 features two cmdlets from the Azure AD Preview module:

In some respects, it’s odd that they use cmdlets based on the Azure AD Graph API because Microsoft has scheduled the Azure AD modules for retirement in March 2024.

Of course, apart from the licensing management cmdlets, the rest of the Azure AD cmdlets will continue to work after retirement, which makes it perfectly acceptable to specify the cmdlets now, especially if replacements in the Microsoft Graph PowerShell SDK are unavailable.

Using Microsoft Graph PowerShell SDK Cmdlets to Delete Entra ID User Accounts

The Microsoft Graph PowerShell SDK can be difficult to navigate. It’s composed of 38 separate sub-modules. Although cmdlets are gathered logically, it can still be hard to find the right cmdlet to do a job. As you’d expect, the current version (1.9.3) doesn’t appear to include cmdlets to handle soft-deleted service principal objects. For now, we can see how to perform common administrative actions with user accounts as a guide to what should be available for service principals.

With that in mind, here are the steps to soft-delete user accounts, list the accounts in the deleted items container, and hard-delete (permanently remove) an account.

Soft-Delete an Entra ID User Account

To soft-delete an Entra ID account, run the Remove-MgUser and pass the object identifier or user principal name of the account to delete. The cmdlet does not prompt for a confirmation and deletes the account immediately:

Remove-MgUser -UserId Sue.Ricketts@office365itpros.com

List Soft-Deleted Entra ID User Accounts

During the 30-day retention period in the deleted items container, you can recover the account from the Entra admin center or by running the Restore-MgUser cmdlet. Before we can run Restore-MgUser, we need to know the object identifiers of the objects in the deleted items container. This code:

  • Uses the Get-MgDirectoryDeletedItemAsUser cmdlet to fetch the list of deleted user accounts. The Property parameter can be ‘*’ to return all properties of the deleted objects, but in this case, I’ve chosen to limit the set of properties to those that I want to use.
  • Loops through the data returned by Entra ID to extract the properties we want to use. The different behaviour of the Azure AD cmdlets and the Microsoft Graph PowerShell SDK cmdlets is an example of why tenants need to plan the upgrade and testing of scripts which use old cmdlets.
  • Lists the soft-deleted user accounts.
[array]$DeletedItems = Get-MgDirectoryDeletedItemAsUser -All -Property Id, DisplayName, DeletedDateTime, UserPrincipalName, Usertype
If ($DeletedItems.count -eq 0) { 
   Write-Host "No deleted accounts found - exiting"; break 
}

$Report = [System.Collections.Generic.List[Object]]::new()

ForEach ($Item in $DeletedItems) {
    $DeletedDate = Get-Date($Item.deletedDateTime)
    $ReportLine = [PSCustomObject][Ordered]@{ 
           UserId   = $Item.Id
           Name     = $Item.displayName
           Deleted  = $DeletedDate
           "Days Since Deletion" = (New-TimeSpan $DeletedDate).Days
           Type     = $Item.userType
     }
    $Report.Add($ReportLine)
}

UserId                               Name                      Deleted             Days Since Deletion Type
------                               ----                      -------             ------------------- ----
92cef396-1bd3-4296-b06f-786e2ee09077 The Maestro of Office 365 19/02/2022 17:36:44                  31 Guest
c6133be4-71d4-47c4-b109-e37c0c93f8d3 Oisin Johnston            26/02/2022 18:13:26                  24 Member
2e9f1189-d2d9-4301-be57-2d66f3df6bb1 Jessica Chen (Marketing)  04/03/2022 11:52:48                  18 Member
8cd64635-bce6-4af0-8e64-3bebe354e9a4 Alex Redmond              05/03/2022 17:36:45                  17 Member
0f16501c-8302-468a-99a6-78c22b0903d2 Jennifer Caroline         18/03/2022 21:33:13                   3 Member
3a6116ab-0116-490e-bd60-7e0cd9f36c9d Sue Ricketts (Operations) 20/03/2022 19:53:29                   2 Member
4a25ccf0-17df-42cf-beeb-4fd449531b47 Stephen Rice              22/03/2022 19:30:06                   0 Guest

To restore a soft-deleted user account, run the Restore-MgDirectoryDeletedItem cmdlet and pass the account’s identifier. After restoring the account, remember to assign licenses to allow the account to access Microsoft 365 services.

Restore-MgDirectoryDeletedItem -DirectoryObjectId 3a6116ab-0116-490e-bd60-7e0cd9f36c9d

Remove Soft-Deleted Entra ID User Account

To remove a soft-deleted directory object, run the Remove-MgDirectoryDeletedItem cmdlet and pass the object identifier. Like Remove-MgUser, the cmdlet doesn’t ask for confirmation and permanent deletion happens immediately.

Remove-MgDirectoryDeletedItem -DirectoryObjectId f9d30b84-ad5f-4151-98f0-a55dafe30829

Time of Transition

We’re in a time of transition now as Microsoft does its best to retire the Azure AD modules and build the capabilities (and hopefully the documentation) of the Microsoft Graph PowerShell SDK. In the intervening period, any time you see an example using Azure AD cmdlets, try to convert it to use the SDK. It’s a great way to learn.


Keep up to date with developments like the Microsoft Graph PowerShell SDK by subscribing to the Office 365 for IT Pros eBook. Our monthly updates make sure that our subscribers understand the most important changes happening across Office 365.

]]>
https://office365itpros.com/2022/03/23/delete-entra-id-user-accounts/feed/ 10 54175
Why It’s Difficult to Transfer Membership Rules from Exchange Online to Azure AD https://office365itpros.com/2022/03/18/membership-rules-exchange-teams/?utm_source=rss&utm_medium=rss&utm_campaign=membership-rules-exchange-teams https://office365itpros.com/2022/03/18/membership-rules-exchange-teams/#comments Fri, 18 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54000

Dynamic Distribution Lists to Dynamic Microsoft 365 Groups

Earlier this week, I described how to create a Microsoft 365 group and team from an Exchange Online dynamic distribution list. The code creates a group with static membership, but the input dynamic distribution list has its membership computed by Exchange Online using a recipient filter (aka a membership rule). Why can’t we take the filter used by the dynamic distribution list and apply it to create a dynamic Microsoft 365 group, which in turn becomes a team with dynamic membership. Well, as it turns out, it’s not quite as simple as taking a filter from one Microsoft 365 workload and using it in another.

Translating Recipient Filters for Dynamic Microsoft 365 Groups

Conceptually, it is possible to convert a dynamic distribution list to a be the membership rule for a dynamic Azure AD group. Two challenges exist: filter syntax and filter properties.

The query stored in a dynamic distribution list looks like this:

((((((Title -eq 'Architect') -or (Title -eq 'Senior Architect'))) -or (((Title -eq 'Principal Architect') -and (ExchangeUserAccountControl -ne 'AccountDisabled'))))) -and (-not(Name -like 'SystemMailbox{*')) -and (-not(Name -like 'CAS_{*')) -and (-not(RecipientTypeDetailsValue -eq 'MailboxPlan')) -and (-not(RecipientTypeDetailsValue -eq 'DiscoveryMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'PublicFolderMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'ArbitrationMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'AuditLogMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'AuxAuditLogMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'SupervisoryReviewPolicyMailbox')))

We know this is a custom recipient filter created using PowerShell because the properties it uses are not covered by the precanned filters created using EAC. The custom filter comes first followed by a bunch of exclusions inserted by Exchange to make sure that system mailboxes are not in the returned set. Exchange adds these exclusions automatically when it saves the recipient filter for a dynamic distribution list.

It’s technically possible to take a recipient filter from a dynamic distribution list and parse it to extract the custom part using Regex expressions. By using a function to remove special characters, I was able to process the recipient filter shown above like this:

$Filter = (Get-DynamicDistributionGroup -Identity "System Architects").RecipientFilter
$i = $Filter.IndexOf("-and (ExchangeUser")
$f = $Filter.Substring(0,$i)
$ExoFilter = Remove-StringSpecialCharacter -String $f -SpecialCharacterToKeep '-', " "

The output is:

Title -eq Architect -or Title -eq Senior Architect -or Title -eq Principal Architect

However, a complicating factor is that Exchange has changed the format of the exclusions it inserts over time. This means that you can never be sure how the recipient filter is formatted, and my code didn’t work when tested against several other dynamic distribution lists in my tenant, some of which go back to 2014.

In any case, the output I generated isn’t a valid Azure AD filter, and some additional work is needed to make it work with a dynamic Azure AD group (team). Briefly:

  • Title is the name of the Exchange property. It is JobTitle in Azure AD. Also, user properties are prefixed with “User,” meaning that you end up with User.JobTitle.
  • The -eq and -or operators in Exchange lose the leading hyphen in Azure AD.

Different Filterable Properties

A more fundamental issue is that while Exchange supports many mail-enabled properties for custom recipient filters in dynamic distribution lists, the set of filterable properties don’t match the set available for Azure AD. You might be able to convert some queries, but you won’t be able to convert others. The difference is accounted for by the fact that Exchange queries against its own directory, which stores details of mail-enabled objects, while Azure AD queries its directory. The two directories have different schemas.

Once I realized the extent of the incompatibility between the two sets of properties, I stopped trying to figure out how an automatic conversion could be done. Too much time would be needed to figure out the permutations and combinations involved in formatting membership rules. And given the number of times a conversion might be necessary, the easiest solution is to let human administrators generate the membership rules.

Previewing Azure AD Filters

The GUI in the Azure AD admin center to deal with dynamic groups include a rules editor. You can paste the outline of a membership rule taken from an Exchange dynamic distribution list and modify it there. The Azure AD admin center also includes a nifty preview feature to validate that a membership rule works. After making whatever changes are necessary to create a valid rule for Azure AD, you can test the rule by nominating one or more users that you know should match the membership rule. Click the validate button and Azure AD will tell you if the directory can find the users you selected using the rule (Figure 1).

Azure AD checks the membership rule for a dynamic Microsoft 365 group
Membership filter
Figure 1: Azure AD checks the membership rule for a dynamic Microsoft 365 group

Exchange Online doesn’t have a similar way to validate the membership of a dynamic distribution list. Maybe that’s why Microsoft considers dynamic Azure AD groups to be a premium feature and charges accordingly.

Creating a Dynamic Azure AD Group with PowerShell

For the record, you can create a dynamic Azure AD group with PowerShell. In this instance, I use the New-MgGroup cmdlet from the Microsoft Graph PowerShell SDK (the New-AzureADMSGroup cmdlet from the preview version of the Azure AD module will work too). The important point is that the group has dynamic membership rather than static and has a rule to control the membership:

$Group = New-MgGroup -DisplayName "System Architects (Dynamic x2)" -Description "People with an architect job title" -MailEnabled:$True -SecurityEnabled:$True -MailNickName "System.Architects.Dynamic2" -GroupTypes "DynamicMembership", "Unified" -MembershipRule "(User.JobTitle -eq ""Architect"" or  User.JobTitle eq ""Senior Architect

After creating the dynamic Azure AD group, you can team-enable it with the New-Team cmdlet by passing the identifier of the newly created group.

New-Team -GroupId $Group.Id

Incompatible schemas, properties, and syntax might stop the automatic conversion of membership rules, but you can at least get the job done with a little manual effort.


Learn more about how the Office 365 applications really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/03/18/membership-rules-exchange-teams/feed/ 1 54000
Microsoft Sets New Deprecation Schedule for Azure AD PowerShell https://office365itpros.com/2022/03/17/azure-ad-powershell-deprecation/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-powershell-deprecation https://office365itpros.com/2022/03/17/azure-ad-powershell-deprecation/#comments Thu, 17 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=54064

What You Need to Do Before Azure AD and MSOL Modules Retire

Azure AD PowerShell retirement

Microsoft has recently been beating the drum about the retirement of the Azure AD PowerShell module and its older Microsoft Online Services (MSOL) counterpart. On March 3, the Azure AD team posted in the Microsoft Technical Community to say that they had listened to customer feedback and pushed the termination of support out from the end of June to the end of 2022. On September 30, Microsoft set a new retirement date for the Azure AD and MSOL modules for June 30, 2023. Things tend to happen around the end of June to align with the end of Microsoft’s financial year and allow everyone to start the new year afresh.

The salient points in message center notification MC281145 are:

  • Reaffirmation that Microsoft will not retire the Azure AD Graph API on June 30, 2022. The Azure AD Graph is the component which underpins the Azure AD and MSOL modules. It’s a Graph API built especially for Azure AD before the Microsoft Graph established its position as the common API for Microsoft 365. The Azure AD team wants to deprecate their Graph API and embrace the Microsoft Graph, which is the basic reason for the planned deprecation of the Azure AD and MSOL modules.
  • Confirmation that the subset of the cmdlets in the Azure AD and MSOL modules which deal with user licensing will stop working earlier than the rest of the other cmdlets. Quite apart from the desire to move to the Microsoft Graph, these cmdlets are affected because Microsoft is moving to a new licensing management platform. Originally, the scheduled date for the transition was June 30, 2022. Microsoft pushed the date out eight weeks to August 26, 2022 and now it’s March 31, 2023. After this date, license management cmdlets like Get-AzureADSubscribedSKU won’t work.
  • Reconfirmation that the Microsoft Graph PowerShell SDK is the way forward.

Shifting Dates

The deprecation date for the Azure AD and MSOL modules is shifting. Originally, this was June 2022, then the end of 2022, and now it’s June 2023. Clearly, customer feedback has told Microsoft that it’s going to be difficult to update PowerShell scripts before Microsoft wants to retire these modules. ISV products which use the modules or the Azure AD Graph API must also be updated before the axe descends. See Microsoft’s FAQ for help in identifying other applications which use the Azure AD Graph API.

Update (July 29): Microsoft has pushed out the retirement of the Azure AD and MSOL license management cmdlets to 31 March 2023.

No matter which way you turn, the basic fact is that Microsoft will eventually retire the Azure AD and MSOL modules. It’s time to update scripts now, with the priority order being:

  • Scripts that manage licenses for Azure AD accounts (before August 26, 2022). This example of creating a license management report might help get you started.
  • Scripts that perform other Azure AD management operations (ideally before the end of 2022).

Microsoft Documents Its Migration Approach

To help, Microsoft has created some documentation for steps to migrate scripts. The most important statement is “There is currently no tool to automatically converts scripts in Azure AD PowerShell to Microsoft Graph PowerShell.” I doubt that any automatic script migration tool will appear. There are just too many variations in how people code with PowerShell to guarantee that a tool could handle even moderately complex scripts. The potential to create a support nightmare is one reason why I think Microsoft won’t produce a migration tool.

Which leaves us with Microsoft’s simple three-step approach to script migration:

  • Find the Microsoft Graph equivalent of your Azure AD PowerShell cmdlets from the Cmdlet map.
  • Select the Microsoft Graph cmdlet to view the reference documentation and get the new syntax for the cmdlet.
  • Update your existing scripts using the new syntax.

Testing might be a good fourth step to add. And before you start, you need to create an inventory of scripts which use Azure AD or MSOL cmdlets.

Migration Tips

At first glance, the process seems straightforward. In many cases, it is, and you won’t have huge difficulty in converting Get-AzureADUser with Get-MgUser. Microsoft notes some limitations, to which I add:

  • Don’t depend on the Microsoft Graph PowerShell SDK documentation for help with basic information like the format of input parameters. The documentation is machine-created and is shockingly bad in terms of its ability to guide people with real-life examples.
  • The SDK cmdlets are based on Graph API queries and often the documentation for those queries will help you understand how cmdlets work and the parameter values they expect.
  • The Graph Explorer is an excellent tool to help understand how Graph queries run and what they return.
  • Pay attention to parameters and switches. Some parameters of SDK cmdlets require a colon between the parameter and the value where an Azure AD or MSOL cmdlet does not. Some parameter and switch names change.
  • Don’t plan to run SDK scripts interactively. It will only lead to an accumulation of permissions for the service principal used by the SDK.
  • The SDK cmdlets handle pagination when necessary to retrieve all matching objects. Usually, there’s an -All parameter to help (like Get-MgGroup -All).
  • Sometimes you’ll need to use certificate-based authentication and a separate Azure AD registered to gain administrative access to data. The Teams tags report is a good example of when this technique is necessary.

We Feel Your Pain

The Office 365 for IT Pros eBook writers are busy converting script examples to use the Microsoft Graph PowerShell SDK. We plan to have everything done over the next few months. On one level, it’s a pain to be forced to find and upgrade scripts. On another, it’s an opportunity to revamp scripts to make them work better. Perhaps you might even consider moving some of your long-running scripts to Azure Automation?


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

]]>
https://office365itpros.com/2022/03/17/azure-ad-powershell-deprecation/feed/ 6 54064
Creating an Authentication Method Report for Entra IAccounts https://office365itpros.com/2022/03/03/azure-ad-accounts-authentication/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-accounts-authentication https://office365itpros.com/2022/03/03/azure-ad-accounts-authentication/#comments Thu, 03 Mar 2022 01:00:00 +0000 https://office365itpros.com/?p=53754

Moving from Old Modules to the Microsoft Graph SDK for PowerShell

Update: This article describes a script to generate a report showing the MFA status for accounts and highlights administrative accounts that aren’t MFA-enabled.

Microsoft 365 tenants often create reports to understand the health of their Azure AD accounts. In June 2021, Microsoft announced that they are moving away from the Microsoft Online Services (MSOL) and Azure AD PowerShell modules and would deprecate the Azure AD Graph API at the end of June 2022. Customer feedback convinced Microsoft to push the deprecation date out to the end of 2022, and then to March 2024. However, the writing is on the wall for the Azure AD Graph API and it’s time to move to Graph-based interfaces.

Their future focus for PowerShell access to Entra ID data is the Microsoft Graph SDK for PowerShell. The only definite drop-dead date affecting the older modules is June 30, 2022, when Microsoft moves to a new license management platform. At this point, any cmdlet which retrieves license information for user accounts will cease working. Any scripts used for tenant license management that haven’t been updated now require urgent attention.

I have an MFA status script written in 2018. The script uses the MSOL cmdlets to check and report the “strong authentication methods” for each user account. The state of multi-factor authentication has moved on since 2018 to accommodate new methods like FIDO2 keys and passwordless authentication. These methods aren’t handled by the MSOL cmdlets. It’s therefore time to take a different approach.

Given Microsoft’s direction to use the Microsoft Graph SDK for PowerShell for Azure AD access, it seems like this is the right path to follow. I’ve done a reasonable amount with the SDK and have written several articles to report my progress. For example, here’s how to generate a licensing report for a tenant.

Not a Perfect SDK

The SDK is not perfect. Essentially, its cmdlets are wrappers around Graph API queries. If you’re used to dealing with Graph APIs, the SDK cmdlets will be second nature. If not, it will take time to become familiar.

Getting acquainted isn’t helped by the poor state of the documentation for the SDK cmdlets. Microsoft uses automatic text generation tools to create the documentation from source code. The result is often as useful as a snowball in a desert, especially in terms of practical examples and explanations about inputs. Again, if you know the Graph APIs, you probably won’t be surprised at what you find in the documentation, but the current state of the documentation is no credit to Microsoft and a barrier to adoption.

Steps in the Creation of the Report

The aim is to create a report showing the authentication methods used by Azure AD accounts and highlight accounts which might attention (hopefully, by enabling multi-factor authentication). According to a recent Microsoft report, only 22% of Microsoft 365 accounts use multi-factor authentication. Although this marks an improvement over the past, it’s still far too low a percentage. Perhaps people don’t know about recent improvements Microsoft has made in MFA processing to make it easier for people to use.

The script I wrote to create the report does the following:

  • Connects to the Graph endpoint with the following permissions: UserAuthenticationMethod.Read.All, Directory.Read.All, User.Read.All, Auditlog.Read.All. If the service principal for the SDK doesn’t have administrat9or consent of any permission, it must be granted at this point.
  • Set the Graph profile to beta to make sure that we have access to all the user account data.
  • Call the Get-MgUser cmdlet to fetch the set of Azure AD member accounts. The set returned excludes guest accounts but includes the accounts used for shared and resource mailboxes. To focus solely on licensed member accounts, you could apply a filter to look for accounts with at least one assigned license.
  • Loop through each account to check its authentication methods. To ensure that only active accounts are checked, the script calls the Get-MgAuditLogSignIn cmdlet to look for a sign-in record. This check can only go back 30 days.
  • For each active account, call the Get-MgUserAuthenticationMethod cmdlet to return the authentication methods used by the account. An account can use all the valid authentication methods from passwordless to the Microsoft authenticator app. The first time an account uses a method, Azure AD adds it to the list used by the account.
  • For each method, retrieve some information.
  • Report the results of checking each method.
  • After processing all user accounts, create a list of users for which an authentication method is available and check each account to see if one of the strong (MFA) methods is noted.
  • Create a final report and output it to a CSV file.

Figure 1 shows an example of the kind of output generated.

Azure AD Accounts and authentication methods
Figure 1: Authentication methods report for Azure AD accounts

You can download the script from GitHub. As always, the code is intended to illustrate a principal rather than being a fully-baked solution.

Automating the Check

A script like this is a good candidate for execution by an Azure Automation runbook. It can be run on a schedule and the results emailed to administrators for action. Getting a weekly or monthly reminder to improve the security posture of the organization by increasing the percentage of well-protected accounts can only be a good thing, can’t it?


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/03/03/azure-ad-accounts-authentication/feed/ 9 53754
Understanding How App Certification for Microsoft 365 Apps Works https://office365itpros.com/2022/02/23/app-certification-microsoft365/?utm_source=rss&utm_medium=rss&utm_campaign=app-certification-microsoft365 https://office365itpros.com/2022/02/23/app-certification-microsoft365/#comments Wed, 23 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53581

The Many Ways to Stress the Need for Modern Authentication

By now, all Microsoft 365 tenant administrators should be aware that Microsoft is removing support for basic authentication for many Exchange Online connectivity protocols. The aim is to complete the process by October 2022. SMTP AUTH is an exception, but Microsoft will deal with it in time.

What you might not be aware of is that access to Microsoft 365 data using modern authentication requires that the developers must register their app with Azure AD. This applies to any Microsoft API, including the Outlook add-in model and the Graph APIs. If you’ve written PowerShell scripts which make Graph queries, you know that you must register an app to receive consent for the Graph permissions necessary to access the target data. This is a basic registration. Registrations for more sophisticated apps like those sourced from ISVs contain more information about the app, such as a redirect URL for the app. Registration for ISV apps usually happens during the app installation, including the creation of a service principal to allow the app to run with API permissions consented to by tenant administrators.

Previously, I’ve written about the need for tenants to clean out application crud from Azure AD. The crud is composed of unwanted apps and their service principals accumulated over time in Azure AD. Being able to fetch sign-in data for service principals via Graph queries makes it easier to add context to this exercise by knowing what service principals are active.

After cleaning out obsolete applications, Azure AD might be tidy, but do you know much about the apps which remain? The application governance add-on for Microsoft Defender for Cloud Apps might help, but only if your tenant has the necessary licenses.

Microsoft’s App Compliance Program

Fortunately, Microsoft has an App Compliance Program, part of their Zero Trust initiative to help customers verify apps they might want to run in their tenant. App developers go through the process to achieve app certification by providing information about the app and the data it accesses. The program has three phrases or levels:

Publisher verification: The app developer has a Microsoft developer network identity. The app supports modern authentication and is capable of multi-tenant activity. This is the entry-level participation in certification.

Publisher attestation: The app developer completes a questionnaire covering security, data handling, and compliance.

Microsoft 365 certification: Instead of the app developer reporting details of their app, third-party assessors audit the assertions to validate that the app meets Microsoft standards for security and compliance. The process occurs annually, and details gathered during the audit is available online. Figure 1 shows details of a Microsoft certified app in AppSource. The audit information is available through the Microsoft 365 certification link for the app.

App certification information in AppSource
Figure 1: App certification information in AppSource

The app certification information available online (Figure 2) includes detail of the app permissions, including the reason why the app developers need administrator consent to use the permission.

App certification includes documenting API permissions
Figure 2: App certification includes documenting API permissions

Obviously, app developers must invest time and effort to satisfy Microsoft criteria for app certification. However, once completed, they should reap the benefits gained by increased customer confidence in their product. At least, that’s the theory.

Downgraded Certification

In April 2020, I reviewed the new Manage Apps section in the Teams admin center and commented on the Microsoft 365 certified status of the Wrike app. The number of apps available for Teams continues to expand (from 462 in April 2020 to 1,402 as I write this in February 2022, or roughly 44 new apps monthly). Checking the online list of Teams apps, it looks like very few apps are Microsoft 365 certified. This begs the question why app developers feel it unnecessary to go through Microsoft’s audit process – or why publishers of apps like Wrike downgraded their apps from certified to publisher attestation.

I’m sure cost has something to do with it, along with a feeling that customers don’t go looking for apps which are Microsoft 365 certified. If a developer gains no business advantage by completing the full certification process for their apps, why bother? It’s a reasonable perspective. Microsoft would obviously like developers to go the whole hog, but this might be an uphill battle.

One way that customers might help persuade developers that app certification is worthwhile is to allow users to grant consent for apps from verified publishers when apps require only “low-impact” permissions. The idea is that if less friction exists to deploy and use an app, it will be more popular and profitable.

The consent settings for a tenant are available in the Azure AD admin center (Figure 3) and include the ability to define what you consider to be low-impact permissions. In this case, the selected option allows users to grant consent, but only for three low-impact permissions such as the ability to read a user’s profile. Tenants can define what they consider to be low-impact permissions through the Permissions Classifications option shown in Figure 3.

Azure AD Consent and Permissions settings
Figure 3: Azure AD Consent and Permissions settings

Some will be uneasy about the prospect of users granting consents to apps. The safeguard is that consent is only possible for verified publishers; the counterargument is that developers can attain verification too easily to make this status truly valuable. If Microsoft 365 certified apps were the threshold, a different story might ensue. Microsoft recommends that it’s OK to allow users to grant consent to apps, but without stronger controls, this might be a stretch for many organizations.

The Rocky Road to App Certification

The situation is complex. Microsoft wants everyone to use modern authentication to access Microsoft 365. Getting to that position means a great deal of change for clients, apps, users, and organizations. Certification helps customers understand and control the access apps have to data in their tenant. That’s goodness, but only if ISVs co-operate and certify their products. Time enables change. While that happens, keep your app repository clean and tidy. You know it makes sense.


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/02/23/app-certification-microsoft365/feed/ 1 53581
How Microsoft Teams Displays Local Time in Profile Cards https://office365itpros.com/2022/02/21/teams-time-zone-profile-cards/?utm_source=rss&utm_medium=rss&utm_campaign=teams-time-zone-profile-cards https://office365itpros.com/2022/02/21/teams-time-zone-profile-cards/#comments Mon, 21 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53593

Teams Local Time a Useful Feature Dependent on Exchange Calendar Settings

On February 14, Microsoft updated the Teams profile card to display the profile owner’s local time and the time difference between you and them. To see a profile card, hover over a user’s thumbnail photo anywhere they appear in Teams, like a chat or channel conversation. As you can see in Figure 1, the local time for the chosen person and the difference to your time appear.

Local time information appears on a Teams profile card
Figure 1: Local time information appears on a Teams profile card

Obviously, if you’re trying to contact someone or arrange a meeting with them, knowing when they work is valuable information. It’s also a feature requested several times in the Teams feedback forum (here’s one example).

Administrators don’t have to do anything to make local time appear in profile cards. Like other information shown in the profile card, the local time depends on information already known about users. In this case, the working hours defined for user calendars. Apart from tenant accounts, local time information is also displayed for guest accounts, if an Exchange Online organization relationship exists to share calendar information between the tenant and the guest’s home domain. Local time information is not available for federated chat including chats with Teams consumer users.

Puzzled by Time Zones

All of this is wonderful until I saw some puzzling results, like people showing up as being in odd time zones or with time differences that just didn’t work. Take the local time shown for Vasil Michev’s guest account (Figure 2). I am in Dublin, Ireland and Vasil is in Sofia, Bulgaria. At 9:51am, Teams told me that Vasil’s local time was 07:51am and that he is two hours behind me. In other words, his time zone is somewhere in the mid-Atlantic. This is upsetting, because the technical editor for the Office 365 for IT Pros eBook shouldn’t be stuck in mid-ocean.

Teams displays an interesting local time zone for a Bulgarian user
Figure 2: Teams displays an interesting local time zone for a Bulgarian user

Why would someone’s time zone be four hours off? To answer the question, we need to know where Teams obtains its time zone information.

Two Time Zones for Outlook

It’s logical that Teams would use someone’s location to determine their time zone. Looking at the data, it seems OK.

Get-User -Identity Vasil.Michev | fl city, stateorprovince, countryorregion

City            : Sofia
StateOrProvince : Sofia
CountryOrRegion : Bulgaria

However, when you think about things a little more, mailboxes have a regional configuration. Perhaps this is where Teams fetches the time zone from. The problem with this theory is that guest accounts have only special cloud-only mailboxes used to store compliance records and other system data. You can’t query these mailboxes using the Get-MailboxRegionalConfiguration cmdlet, like you can for tenant mailboxes:

Get-MailboxRegionalConfiguration -Identity Ken.Bowers | fl

DateFormat                            : dd/MM/yyyy
Language                              : en-GB
DefaultFolderNameMatchingUserLanguage : False
TimeFormat                            : HH:mm
TimeZone                              : Eastern Standard Time

The answer therefore must be data that remote tenants can access, such as the calendar configuration. Each calendar has a time zone for working hours, which is used when scheduling meetings and to publish free/busy information. Organizations can share free/busy data with other Microsoft 365 tenants, and as it turns out, this is the data used by Teams.

Users can set the time zone for their calendar through Outlook or OWA settings. OWA is more intelligent about time zone settings than Outlook desktop is and detects if a difference exists between the regional time zone configured in the General tab and the calendar time zone. In Figure 3, we see that OWA offers to fix a mismatch detected between a user’s regional time zone (Eastern Standard Time or UTC -5) and  the time zone for their calendar meeting hours (UTC).

OWA calendar settings detect a time zone mismatch
Figure 3: OWA calendar settings detect a time zone mismatch

Although the two time zones are usually the same, they don’t need to be. By default, the time zone for the calendar is set to the tenant time zone during the creation of a new mailbox. Afterwards, the user can update the time zone to match their location, or an administrator can update the time zone using the Set-MailboxCalendarConfiguration cmdlet. For example:

Set-MailboxCalendarConfiguration -Identity Nikki.Patia -WorkingHoursTimeZone "FLE Standard Time"

Like any change to a mailbox or account setting, it can take some time before Teams clients refresh their cache to pick up the change. In testing, I found it could take several days before Teams reflected calendar adjustments in profile cards.

Checking Calendar Settings

Apart from running the Get-MailboxCalendarConfiguration cmdlet, administrators can use the Graph Explorer to check calendar settings for a user by running a Calendar API query, which is how Teams fetches user time zone information.

To run the query, open the Graph Explorer and sign into your account. In the request body, enter the request you want the Graph to process. In this case, we want to know about the calendar settings for two users defined in the schedules section. The start and end time can be any date.

{
    "schedules": [
        "jane.smith@office365itpros.com",
        "john.hopper@office365itpros.com"
    ],
    "startTime": {
        "dateTime": "2023-03-15T09:00:00",
        "timeZone": "GMT Standard Time"
    },
    "endTime": {
        "dateTime": "2023-03-15T18:00:00",
        "timeZone": "GMT Standard Time"
    },
    "availabilityViewInterval": 60
}

After populating the request body, run this POST query:

https://graph.microsoft.com/v1.0/me/calendar/getSchedule

The response gives the availability of the users for the requested time slot. However, we’re interested only in the time zone included in the response for each user. In this instance, we see that the user’s calendar time zone is Eastern Standard Time.

                ],
                "startTime": "08:00:00.0000000",
                "endTime": "17:00:00.0000000",
                "timeZone": {
                    "name": "Eastern Standard Time"
                }

We started off by reporting problems with the profile card for Vasil Michev’s guest account. My tenant has an Exchange Online federated relationship with Vasil’s tenant, so we can use the Calendar API to perform a free/busy lookup. This is how the Outlook scheduling assistant finds free time slots for meetings.

The lookup returned the following result shows that Vasil’s calendar uses a custom time zone to apply a four-hour time offset from UTC. This is why his profile card reports such an odd local time.

"startTime": "09:00:00.0000000",
                "endTime": "18:00:00.0000000",
                "timeZone": {
                    "@odata.type": "#microsoft.graph.customTimeZone",
                    "bias": -120,
                    "name": "Customized Time Zone",
                    "standardOffset": {
                        "time": "04:00:00.0000000",
                        "dayOccurrence": 5,
                        "dayOfWeek": "sunday",
                        "month": 10,
                        "year": 0

You might decide that it’s up to users to make sure that their calendars have the correct time zones set and administrators have no part to play to ensure no mismatches exist. However, if you decide that you’d like to know if any mailboxes have mismatched time zones, we can detect the condition with some PowerShell code. The script below:

  • Fetches user mailboxes.
  • Checks the regional configuration to get the time zone set for the user location.
  • Checks the calendar configuration to get the time zone set for meeting hours.
  • Checks the user account properties to get their physical address.
  • Reports any mismatches found between the two time zones.

$ModulesLoaded = Get-Module | Select Name
If (!($ModulesLoaded -match "ExchangeOnlineManagement")) {Write-Host "Please connect to the Exchange Online Management module and then restart the script"; break}
Write-Host "Finding user mailboxes..."
# OK, we seem to be fully connected and ready to go...
[array]$Mbx = Get-ExoMailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited
If (!($Mbx)) { Write-Host "Something happened and we found no user mailboxes - exiting" ; break }

$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($M in $Mbx) {
   Write-Host "Processing" $M.DisplayName
   $RegionalConfiguration = Get-MailboxRegionalConfiguration -Identity $M.UserPrincipalName
   $CalendarConfiguration = Get-MailboxCalendarConfiguration -Identity $M.UserPrincipalName
   $UserInfo = Get-User -Identity $M.UserPrincipalName
   $Status = $Null
   If ($CalendarConfiguration.WorkingHoursTimeZone -ne $RegionalConfiguration.TimeZone) {$Status = "Time zone mismatch"}

   $DataLine= [PSCustomObject][Ordered]@{ 
        Status          = $Status
        User            = $M.DisplayName
        UPN             = $M.UserPrincipalName
        CalendarZone    = $CalendarConfiguration.WorkingHoursTimeZone
        RegionalZone    = $RegionalConfiguration.TimeZone
        Language        = $RegionalConfiguration.Language
        DateFormat      = $RegionalConfiguration.DateFormat
        TimeFormat      = $RegionalConfiguration.TimeFormat
        Office          = $UserInfo.Office
        StreetAddress   = $UserInfo.StreetAddress
        City            = $UserInfo.City
        StateOrProvince = $UserInfo.StateOrProvince
        CountryOrRegion = $UserInfo.CountryOrRegion
        PostalCode      = $UserInfo.PostalCode
      
    }
    $Report.Add($DataLine)
}
$Report | Out-GridView

Figure 4 shows example output from the script.

Time zone mismatches reported by PowerShell
Figure 4: Time zone mismatches reported by PowerShell

The cmdlets to fetch regional and calendar configurations are not quick and the script can take between ten and fifteen seconds to process a mailbox. In fact, this is a great example of an Exchange Online script suitable for processing by Azure Automation.

Adjustments Best Left to Users

Although it would be easy to insert an extra line of PowerShell to fix time zone mismatches by adjusting the calendar time zone to match the regional time zone, that’s a call better left to users. They know their calendar and they know how they work. But with the information to hand, you can advise users with mismatched time zones to update their settings as necessary to make sure that Teams profile cards reflect accurate data. After all, you wouldn’t want people to see bad local times, would you?


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/02/21/teams-time-zone-profile-cards/feed/ 27 53593
Understanding What’s in an Entra ID Access Token https://office365itpros.com/2022/02/17/understanding-entra-id-access-token/?utm_source=rss&utm_medium=rss&utm_campaign=understanding-entra-id-access-token https://office365itpros.com/2022/02/17/understanding-entra-id-access-token/#comments Thu, 17 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53497

Critical Piece When Connecting to the Microsoft Graph

By now, most people who write PowerShell code to interact with Microsoft 365 workloads understand that sometimes it’s necessary to use Microsoft Graph API queries instead of “pure” PowerShell cmdlets. The Graph queries are usually faster and more reliable when retrieving large quantities of data, such as thousands of Microsoft 365 Groups. Over the last few years, as people have become more familiar with the Microsoft Graph, an increased number of scripts have replaced cmdlets with Graph queries. All these scripts use Entra ID (Azure AD) access tokens, as does any utility which interacts with the Microsoft Graph, like the Graph Explorer (Figure 1).

The Graph Explorer displays its Azure AD access token
Figure 1: The Graph Explorer displays its access token

In the remainder of this article, I explore what an Entra ID access token contains.

The Need for Access Tokens

Graph queries need authentication before they can run and the Graph API uses modern authentication. Entra ID registered applications bridge the gap between PowerShell and the Graph. The apps hold details used during authentication such as the app name, its identifier, the tenant identifier, and some credentials (app secret or certificate. The app also holds permissions granted to access data through Graph APIs and other APIs. When the time comes to authenticate, the service principal belonging to an app uses this information to request an access token from Entra ID. Once Entra ID issues the access token, requests issued to the Invoke-RestMethod or Invoke-WebRequest cmdlets can include the access token to prove that the app has permission to access information.

At first glance, an access token is a confused mass of text. Here’s how PowerShell reports the content of an access token:

eyJ0eXAiOiJKV1QiLCJub25jZSI6IlFQaVN1ck1VX3gtT2YzdzA1YV9XZzZzNFBZRFUwU2NneHlOeDE0eVctRWciLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1yNS1BVWliZkJpaTdOZDFqQmViYXhib1hXMCIsImtpZCI6Ik1yNS1BVWliZkJpaTdOZDFqQmViYXhib1hXMCJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iNjYyMzEzZi0xNGZjLTQzYTItOWE3YS1kMmUyN2Y0ZjM0NzgvIiwiaWF0IjoxNjQ0ODQ1MDc3LCJuYmYiOjE2NDQ4NDUwNzcsImV4cCI6MTY0NDg0ODk3NywiYWlvIjoiRTJaZ1lEaW1McEgwTSt5QTk5NmczbWZUUXlYN0FBPT0iLCJhcHBfZGlzcGxheW5hbWUiOiJHZXRUZWFtc0xpc3QiLCJhcHBpZCI6IjgyYTIzMzFhLTExYjItNDY3MC1iMDYxLTg3YTg2MDgxMjhhNiIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2I2NjIzMTNmLTE0ZmMtNDNhMi05YTdhLWQyZTI3ZjRmMzQ3OC8iLCJpZHR5cCI6ImFwcCIsIm9pZCI6IjM4NTRiYjA4LTNjMmMtNGI1Ny05NWZjLTI0ZTA3OGQzODY4NSIsInJoIjoiMC5BVndBUHpGaXR2d1Vva09hZXRMaWYwODBlQU1BQUFBQUFBQUF3QUFBQUFBQUFBQmNBQUEuIiwicm9sZXMiOlsiVGVhbVNldHRpbmdzLlJlYWRXcml0ZS5BbGwiLCJUZWFtTWVtYmVyLlJlYWQuQWxsIiwiR3JvdXAuUmVhZC5BbGwiLCJEaXJlY3RvcnkuUmVhZC5BbGwiLCJUZWFtLlJlYWRCYXNpYy5BbGwiLCJUZWFtU2V0dGluZ3MuUmVhZC5BbGwiLCJPcmdhbml6YXRpb24uUmVhZC5BbGwiLCJBdWRpdExvZy5SZWFkLkFsbCJdLCJzdWIiOiIzODU0YmIwOC0zYzJjLTRiNTctOTVmYy0yNGUwNzhkMzg2ODUiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiRVUiLCJ0aWQiOiJiNjYyMzEzZi0xNGZjLTQzYTItOWE3YS1kMmUyN2Y0ZjM0NzgiLCJ1dGkiOiI3RVkyWnVXV2JFYVF0T3piVVlwOUFBIiwidmVyIjoiMS4wIiwid2lkcyI6WyIwOTk3YTFkMC0wZDFkLTRhY2ItYjQwOC1kNWNhNzMxMjFlOTAiXSwieG1zX3RjZHQiOjEzMDI1NDMzMTB9.N9yvmkCedti2fzT44VfBkN7GvuCInrIgiMgNxdyZeAyxnbdZjEhxHmNdU6HLLHQ3J-GonpPdt28dKwYxgLcrSibGzSPVHddh6MDPYutSwfIxh2oRanxhgFOWVJADfbFoCxsRFDhKJNT39bsauIUiRNzGzbb6dvWuZQ8LrgWjZzjae2qxVxj9jvYgjXEypeYZgLvPOzJiBCuluAMH3TjPuS-CuglFK_edn4CS-ztCwM0hmDFD5BLNZqng5P2KqGTEgjkMKoyIJ8yTGBJpASfdqqEFqWzQwcQ9ese924qNC3hJR_5TWHp2Fl73bpdhwBHRL5UwGTPi9_ysYdndKhXwgA

Deciphering an Access Token

Access tokens issued by Entra ID comply with the OAuth 2.0 bearer token standard (RFC6750) and are structured as JSON-formatted Web Tokens. We can’t see the JSON content because it is base64Url encoded and signed. However, if you paste the token into a site like https://jwt.ms/, the site will decrypt the list of claims included in the token and we’ll see something like the details shown below for the access token featured above:

{ "typ": "JWT", 
"nonce": "gq3zmJhybfXGDGqt6RO2PX9s0cimmRpSRrTO90sQ4w4", 
"alg": "RS256",
 "x5t": "Mr5-AUibfBii7Nd1jBebaxboXW0", 
"kid": "Mr5-AUibfBii7Nd1jBebaxboXW0" 
}.
{ "aud": "https://graph.microsoft.com", 
"iss": "https://sts.windows.net/a662313f-14fc-43a2-9a7a-d2e27f4f3478/", 
"iat": 1644833772, 
"nbf": 1644833772,
 "exp": 1644837672,
 "aio": "E2ZgYJif1+eocevtzqRIrgDGA2V3AQ==",
 "app_displayname": "ReportDLs", 
"appid": "76c31534-ca1f-4d46-959a-6159fcb2f77a", 
"appidacr": "1",
 "idp": "https://sts.windows.net/a662313f-14fc-43a2-9a7a-d2e27f4f3478/", 
"idtyp": "app",
 "oid": "4449ce36-3d83-46fb-9045-2d1721e8f032",
 "rh": "0.AVwAPzFitvwUokOaetLif080eAMAAAAAAAAAwAAAAAAAAABcAAA.",
 "roles": 
[ "Group.Read.All", "Directory.Read.All", "User.Read.All" ],
 "sub": "4449ce36-3d83-46fb-9045-2d1721e8f032", 
"tenant_region_scope": "EU", 
"tid": "a662313f-14fc-43a2-9a7a-d2e27f4f3478",
 "uti": "BU1RVc7mHkmBq2FMcZdTAA", 
"ver": "1.0", 
"wids": [ "0997a1d0-0d1d-4acb-b408-d5ca73121e90" ],
 "xms_tcdt": 1302543310 
}
.[Signature]

The deciphered token divides into three parts: header, payload, and signature. The aim of a token is not to hide information, so the signature is not protected by encryption. Instead, it’s signed using a private key by the issuer of the token. Details of the algorithm and private key used to sign an access token are in its header. An application can validate the signature of an access token if necessary, but this is not usually done when running a PowerShell script. The payload is the location for the claims made by the token and is the most interesting place to check.

Another way to check what’s in an access token is to use the JWTDetails PowerShell module, which is available in the PowerShell Gallery. To install this (very small) module, run:

Install-Module -Name JWTDetails -RequiredVersion 1.0.0 -Scope AllUsers

Afterward, you can examine a token with the Get-JWTDetails cmdlet. Here’s an example revealing that the access token issued to an app allows it to access Exchange Online using the IMAP4 or POP3 protocols:

Get-JWTDetails -Token $Token

aud             : https://outlook.office.com
iss             : https://sts.windows.net/b662313f-14fc-43a2-9a7a-d2e27f4f3478/
iat             : 1671891468
nbf             : 1671891468
exp             : 1671895368
aio             : E2ZgYDAQS/prW6b0Zsah6KMXtnTEAQA=
app_displayname : POP3 and IMAP4 OAuth 2.0 Authorization
appid           : 6a90af02-6ac1-405a-85e6-fb6ede844d92
appidacr        : 1
idp             : https://sts.windows.net/a662313f-14fc-43a2-9a7a-d2e27f4f3478/
oid             : b7483867-51b6-4fdf-8882-0c43aede8dd5
rh              : 0.AVwAPzFitvwUokOaetLif080eAIAAAAAAPEPzgAAAAAAAABcAAA.
roles           : {POP.AccessAsApp, IMAP.AccessAsApp}
sid             : 1475d8e7-2671-47e9-b538-0ea7b1d43d0c
sub             : b7483867-51b6-4fdf-8882-0c43aede8dd5
tid             : a662313f-14fc-43a2-9a7a-d2e27f4f3478
uti             : COCw22GGpESVXvfdhmEVAQ
ver             : 1.0
wids            : {0997a1d0-0d1d-4acb-b408-d5ca73121e90}
sig             : PdScMpYqwA25qJL1z8q589sz/Ma5CGQ4ea9Bi0lnO2yByrIs530emYPnFPfQNN9EPBIvv4EaAoTLomrw4RMBWYoQSAgkBUXVrYGnC
                  jzAU6a2ZNZgo7+AORHk4iyLO0FpbLEaMJvCvI5vWhP9PHOxnGLcIsCbOmyrCK6lxxIKtBx851EpLrhpyvJ3p05NSw0D/mKzXPRKtc
                  rzQcUwECxOUugbm1zdq8JaE/PmSggBb87VZy7p1S2BXhxQZ5QU17JeIADyhCGm1Ml+avuIHsVS2iat/LPEi/nktbrXMcOzROpUKyZ
                  /7uVhxQ0cscJ6WGxbd+zJm36s25Yp1vMzSHaRxQ==
expiryDateTime  : 24/10/2022 15:22:48
timeToExpiry    : 00:59:34.7611307

Claims and Scopes

The list of claims in the access token includes simple claims and scopes (groups of claims). A claim is an assertion about something related to the token. In this case, the claims tell us details like:

  • The tenant (tid).
  • The intended consumer of the token (aud): https://graph.microsoft.com.
  • The app name (app_displayname).
  • The app identifier (appid).
  • The security token service (STS) responsible for issuing the token (iss): https://sts.windows.net/a662313f-14fc-43a2-9a7a-d2e27f4f3478/.
  • The generation time for the token (iat).
  • The time when the token expires (exp). All dates are in Unix epoch time, so 1644837672 means 11:21:12 GMT on February 14, 2022. By default, access tokens issued by Entra ID last one hour, except those used by applications which support continual access evaluation (CAE), where Entra ID issues 28-hour access tokens because it can terminate access at any time and force the user to reauthenticate should a critical user event (like a password change) happen.
  • The identifier for the object in the Microsoft identity system used for authentication (oid). In this case, the script uses a registered Entra ID app, so the value is the service principal for the app. You can test this by running the Get-MgServicePrincipal cmdlet from the Microsoft Graph PowerShell SDK:

Get-MgServicePrincipal -Filter "Id eq '4449ce36-3d83-46fb-9045-2d1721e8f032'"

DisplayName Id                                   AppId                                SignInAudience ServicePrincipalTy
                                                                                                     pe
----------- --                                   -----                                -------------- ------------------
ReportDLs   4449ce36-3d83-46fb-9045-2d1721e8f032 77c31534-ca1f-4d46-959a-6159fcb2f77a AzureADMyOrg   Application

Scopes are a logical grouping of claims, and they can serve as a mechanism to limit access to resources. The roles claim contains a scope of Graph API permissions starting with Group.Read.All and ending with User.Read.All. We therefore know that this app has consent from the organization to use the permissions stated in the scope when it executes Graph API queries. The list of permissions is enough to allow the PowerShell script (in this case, one to generate a report of distribution list memberships) to query the Graph for a list of all groups and read the membership of each group.

From bitter experience, I know how easy it is to get Graph permissions wrong. One way to check is sign into the Graph Explorer and run the query (here’s an example) to check what permissions the Explorer uses to execute the query. However, you can also dump the access token to check that the set of permissions in the access token matches what you expect. It’s possible that you might have requested some application permissions for the app and failed to gain administrator consent for the request, meaning that the access token issued to the app by Entra ID won’t include the requested permissions.

Using the Access Token

Once we’re happy that we have a good access token, we can use it with Graph queries. Here’s how to fetch the list of distribution groups in a tenant. The access token is included in the $Headers variable passed to the Invoke-RestMethod cmdlet.

$Headers = @{Authorization = "Bearer $token"}

$Uri = "https://graph.microsoft.com/V1.0/groups?`$filter=Mailenabled eq true and not groupTypes/any(c:c+eq+'Unified')&`$count=true"
[array]$DLs = (Invoke-RestMethod -Uri $Uri -Headers $Headers -Method Get -ContentType "application/json")
$DLs = $DLs.Value

And if everything goes to plan, we should have a set of distribution lists to process. If not, it’s bound to be a problem with your access token, so it’s time to return to square one and restart the acquisition process.


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2022/02/17/understanding-entra-id-access-token/feed/ 6 53497
Managing Azure AD’s Keep Me Signed In (KMSI) Feature https://office365itpros.com/2022/02/14/azure-ad-keep-me-signed-in-kmsi/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-keep-me-signed-in-kmsi https://office365itpros.com/2022/02/14/azure-ad-keep-me-signed-in-kmsi/#comments Mon, 14 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53191

Feature Can Suppress Sign-in Prompts

Azure AD’s Keep Me Signed In (KMSI) feature uses a persistent cookie to allow users with member accounts in the tenant directory to close and resume browser sessions without needing to sign in again. Azure AD generates the persistent cookie if a user responds affirmatively to the Stay signed in? prompt after a successful authentication (Figure 1). Azure AD uses the persistent cookie to extend the user session (and thus avoid sign-in prompts) and revokes the cookie only after the user signs out.

The Keep Me Signed In (KMSI) prompt
Figure 1: The Keep Me Signed In (KMSI) prompt

According to Microsoft’s documentation, Azure AD shows the KMSI prompt only when “it can benefit the user” and doesn’t prompt guest accounts, if Azure AD considers the sign-in risk score to be high, if persistent browser session control is configured in a conditional access policy, and if accounts sign in via SSO or AD FS.

The Value of KMSI

I understand the value of KMSI for users who work with Microsoft 365 apps through browser sessions. Some applications, like Planner, don’t have desktop clients, so you’re forced to use browser or mobile clients. SharePoint Online and OneDrive for Business are also in this category. However, if a high percentage of user interaction with these workloads is through Teams, I wonder how important persistent connectivity is for their browser sessions.

Overall, given the influence of Teams and mobile clients, the argument for facilitating persistent browser sessions weakens. A good case is arguable that it is better to disable KMSI and force users to reauthenticate if they close the browser as this removes the possibility of compromise should an attacker be able to access a workstation. Requiring reauthentication when opening a session to a Microsoft 365 application seems to take the proactive approach to security endorsed by Microsoft in their Zero Trust model. It also seems to be aligned with recent developments such as enabling continual access evaluation for critical Azure AD events in all Microsoft 365 tenants. In a nutshell, it might be true that KMSI is not as valuable as it once was.

Disabling KMSI

Unless you deploy conditional access policies to control browser session persistence, KMSI is either on or off for everyone in a tenant. If you decide to disable KMSI, the way to do so is through Azure AD company branding. Tenants with Azure AD Premium or Office 365 licenses can customize different graphic elements displayed on user sign-in screens, such as the background screen. Company branding is one of those often overlooked features that every tenant should use (Figure 2).

The effects of Azure AD company branding on sign-in screens
Figure 2: The effects of Azure AD company branding on sign-in screens

To apply custom branding, go to the Company branding section of the Azure AD admin center. You can then create elements for the default locale or for individual language-specific locales. Azure AD applies the default locale if custom elements aren’t available for a user’s selected language.

Applying custom branding is straightforward and requires just a few graphic files (PNG preferred, JPEG works fine):

  • A background image (1920×1080 pixels). This is the type of image used in Figure 2.
  • A banner logo (280×60 pixels). This is the type of image used at the top of the Enter password screen in Figure 2.
  • Square logo (240×240 pixels). This image appears elsewhere, like the bottom of email notifications sent when users share files.

Azure AD replaces its standard images with the custom images defined in company branding Figure 3 shows the properties for company branding applied to my tenant. The important point for this discission is that the option for users to remain signed in is off (at the bottom of the screen).

Custom elements for Azure AD company branding
Figure 3: Custom elements for Azure AD company branding

When you disable KMSI, Azure AD notes:

Important: some features of SharePoint Online and Office 2010 have a dependency on users remaining signed in. If you hide this option, users may get additional and unexpected sign in prompts.

Given that Microsoft 365 no longer supports Office 2010, you can safely ignore that warning. I cannot find precise details of what SharePoint Online features the removal of KMSI affects, but so far, I have experienced few problems since I removed KMSI. OWA signs out automatically after a period of inactivity and sometimes users need to reenter credentials to keep a SharePoint Online session active, but that seems to be all. The rebuttal is that signing out and forcing users to reauthenticate after they leave browser sessions inactive for a while is a good thing. It’s less convenient for the users, but more secure for the organization,

It’s possible that the Azure AD warning is old and reflects concerns when Microsoft revamped the KMSI implementation in 2018. Although improvements in Azure, federation, and SharePoint Online since 2018 might have eliminated some or all of the difficulties reported in this Microsoft Technical Community discussion, it’s still worth reading to understand some of the complexities involved in authentication.

I obviously can’t test every authentication flow in use by tenants, so it’s important that anyone considering disabling KMSI should conduct a full suite of tests to validate whether this action causes problems for users.

Prioritizing Administrative Effort

One of the joys of working in the Microsoft 365 ecosystem is that there’s always something to investigate and debate. Disabling KMSI is probably an easier decision for cloud-only tenants. Hybrid deployments invariably introduce complications, especially in authentication. In those scenarios, it might be best to leave KMSI in place as there’s probably more urgent matters to deal with than plunging into the minutiae of testing authentication pathways.


Make sure that you’re not surprised about changes which appear inside Office 365 applications by subscribing to the Office 365 for IT Pros eBook. Our monthly updates make sure that our subscribers stay informed.

]]>
https://office365itpros.com/2022/02/14/azure-ad-keep-me-signed-in-kmsi/feed/ 2 53191
Microsoft Launches Azure AD Cross-Tenant Access Policies https://office365itpros.com/2022/02/08/azure-ad-cross-tenant-access/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-cross-tenant-access https://office365itpros.com/2022/02/08/azure-ad-cross-tenant-access/#comments Tue, 08 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53410

Laying the Foundation for New Collaboration Scenarios Like Teams Shared Channels

Updated: March 22, 2022

On February 7, Microsoft announced that Azure AD cross-tenant collaboration settings are available in preview. Part of Azure AD B2B Direct Connect, Azure AD cross-tenant access means that users can authenticate in their home tenant and use the credentials gained there to access resources in other tenants, subject to the collaboration settings now in preview. Microsoft says that the new settings allow organizations to control how users collaborate with other Azure AD organizations (Microsoft 365 tenants). Inbound and outbound controls are available to control access on a tenant-wide, group, or application basis, together with the ability to trust security claims from external organizations like multi-factor authentication and device compliance.

External Identities Settings

The new settings are available in the External identities section of the Azure AD admin center. The organizational settings tab is where you define settings for individual Azure AD tenants you want to collaborate with (Figure 1) while the default settings tab is where you define settings to apply to Azure AD tenants in general. Specific settings for another tenant take precedence over the default settings.

Azure AD cross-tenant access settings
Figure 1: Azure AD cross-tenant access settings

Being able to define how individual tenants interact with your tenant allows precise control over who can connect and what they can do. For instance, in Figure 2 we see that the inbound access settings for the O365Maestro tenant allow collaboration via just one application (Office 365). You can add other Microsoft applications to the mix or include other applications if registered in Azure AD.

Inbound access settings for an external Microsoft 365 tenant
Figure 2: Inbound access settings for another Azure AD organization

Note the external users and groups tab. By default, any user can connect with your organization. If you don’t want this to happen, the inbound access settings allow you to define exactly whom from another organization can collaborate with people in your organization. Likewise, the outbound access settings give you control over the people in your organization you want to collaborate outside your tenant. Again, because the whole idea of collaboration is to enable people to work together, the default is to allow everyone to collaborate with external organizations. However, sometimes control is necessary, and you might want to manage who connects with specific tenants, and this is where you can exert that control.

Accepting Security Claims

All Azure AD organizations apply the same fundamentals of authentication to allow users access to resources. It therefore makes sense to accept that a process performed for one tenant is valid for connection to another. If your security posture is higher (for instance, your tenant insists on connections from trusted devices), you can still insist that external connections meet this standard while at the same time accepting valid claims established when users sign into the other organization.

The Trust settings tab defines the set of security claims made by another tenant you are willing to accept. For example, let’s assume that the other tenant enforces MFA for all users. The trust settings for the tenant allows you to accept that the tenant has validated the user’s identity with MFA and won’t issue another challenge from your tenant. Reducing the necessity for multiple MFA challenges removes a major source of user irritation. By default, Azure AD accepts connections from another tenant based on that tenant’s assessment of MFA, compliant (trusted) devices, and hybrid Azure AD joined devices. You can enable or disable each of these claims as shown in Figure 3.

Figure 3: Trust settings for another Azure AD organization

Removing some friction from MFA challenges is a good thing. According to Microsoft, Azure AD customers secure only 22% of Azure AD accounts with MFA. That’s a horrible statistic (albeit showing steady growth over the past few years). The simple fact is that MFA helps accounts resist 99% of brute-force attacks designed to crack passwords, so this is an area where Microsoft 365 tenants need to do better.

Default Settings

If you don’t define settings for an Azure AD organization you want to collaborate with, Azure AD uses the default settings (Figure 4). Like those for individual tenants, the settings break down into B2B collaboration and Trust.

Default settings to control access to other Azure AD organizations
Figure 4: Default settings to control access to other Azure AD organizations

More information about configuring default and specific organization settings for cross-tenant access is available online. Like conditional access policies, it will take time to figure out the best approaches for configuring rules for inbound and outbound access. And like conditional access policies, no one wants to make the mistake of applying a change that blocks collaboration for everyone in a tenant. The advice is therefore to go slowly and understand exactly what effect a proposed change will have on users before proceeding.

Teams Connect the First for Cross-Tenant Access

Microsoft has said that people can connect using “native identities” to collaborate Teams shared channels (aka Teams Connect). It’s therefore no secret that Azure AD cross-tenant access is the foundation to allow users to use credentials obtained within their home tenant to connect with people in a shared channel in an external organization.

Teams shared channels (aka Teams Connect) are now in public preview. Many criticized Microsoft’s slowness in delivering shared channels but given that the feature depends on a new way of authentication and Azure AD collaboration that is only just available in preview, it’s understandable why the delay happened. After all, you don’t want authentication from another tenant to potentially compromise sensitive information stored in a shared channel. Teams Connect is likely the first app to exploit cross-tenant access. I don’t think it will be the last.

Azure AD cross-tenant access won’t mean that guest accounts will go away anytime soon. Many valid scenarios exist to demonstrate the usefulness of guest accounts. Cross-tenant access gives organizations a new way of collaborating to add to the methods enabled by guest accounts. It’s all goodness.


Keep up with the changing world of the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. Monthly updates mean that our subscribers learn about new developments as they happen.

]]>
https://office365itpros.com/2022/02/08/azure-ad-cross-tenant-access/feed/ 11 53410
How to Exploit Entra ID Sign-in Data to Detect Problem Service Principals https://office365itpros.com/2022/02/03/service-principal-sign-in-data-detect-problem-apps/?utm_source=rss&utm_medium=rss&utm_campaign=service-principal-sign-in-data-detect-problem-apps https://office365itpros.com/2022/02/03/service-principal-sign-in-data-detect-problem-apps/#respond Thu, 03 Feb 2022 01:00:00 +0000 https://office365itpros.com/?p=53160

Spring Clean Time for Apps Coming Soon

Last year, I wrote about the need to review and clean up Entra ID integrated applications. That article describes how to extract information from Entra ID o a CSV file and use the CSV to create a Microsoft List. To make it easy to access the list, we create a channel tab in Teams. Everything works to identify suspect apps that might need removal. I think that you should perform such a review periodically. It just makes sense.

Another way to monitor potentially suspicious app activity is to review sign in data for service principals. The intention is to identify unrecognized service principals signing into the tenant and figure out what apps are involved. Sign-ins can originate from well-known service principals used by Microsoft apps, third-party apps, or the service principals automatically created by Entra ID when tenants register apps to interact with the Graph (for instance, to authenticate calls made to Graph APIs in PowerShell scripts). Sign-in data for service principals is available through the Entra admin center (Figure 1) and now it’s accessible using the Microsoft Graph List SignIns API.

Sign-in logs for service principals in the Azure AD admin center
Figure 1: Sign-in logs for service principals in the Entra admin center

The reason why this update is important is that access to sign-in data via the Graph makes it possible to download the information for analysis or store it for long-term retention in an external repository. Although you can download sign-in data as a CSV file from the Entra admin center, it’s more flexible to access the information via Graph queries, especially when you want to probe the activity patterns of certain service principals.

Getting Sign-In Data from the Graph

Any application which wants to interact with the Graph requires consent for permissions to access data. In this instance, consent is needed the Directory.Read.All and AuditLog.Read.All application permissions. Delegate permissions can also be used, and in this case the account used must hold an administrative role capable of accessing the Entra ID sign-in logs.

A suitably-permissioned application can issue queries against the SignIns API. To fetch service principal sign-in data, the query executed by the application must use a Lambda qualifier to filter data. Apart from setting a date range to search for sign-in data, the important point is to filter against the signInEventTypes property to select sign-in events for service principals. Here’s an example of a query to fetch sign-in data for between 17:30 and 22:3 on 19 January.

https://graph.microsoft.com/beta/auditLogs/signIns?&$filter=createdDateTime ge 2022-01-19T17:30:00Z and createdDateTime le 2022-01-19T22:30:00Z and signInEventTypes/any(x:x eq 'servicePrincipal')

To test the query (or one which suits your purposes), use the Graph Explorer to see what the query returns.

I wrote a simple PowerShell script (downloadable from GitHub) to fetch service principal sign-in data for the last seven days. A quick summary of the data revealed that many sign-ins came from an app named Office 365 Reports. Curiously, an app used by a PowerShell script that I had posted on GitHub also showed up with 22 sign-ins. The Information Barrier Processor is the app used by Microsoft 365 to check user accounts against information barrier policies to ensure that no one is communicating with anyone when they shouldn’t.

$Report | Group SpName | Sort Count -Descending | Select Name, Count

Name                                         Count
----                                         -----
Office 365 Reports                             369
Graph Microsoft 365 Groups Membership Report    22
Information Barrier Processor                   21
Security and Audit                               5
PS-Graph                                         1

Resolving the large set of sign-ins was easy. The data stored in the list (Figure 2) revealed the service principal to belong to an Office 365 Reporting app originally published by Cogmotive (acquired by Quadrotech and then by Quest Software). I haven’t used the app in years, but the sign-ins kept on coming.

Service Principal information
Figure 2: Service Principal information

Over time, it’s easy to accumulate crud in the form of service principals installed for one reason or another. Testing an ISV product is a classic example, which is a good reason to always conduct tests in a test tenant instead of the production tenant. Or if you stop using an app, remember to clean up by removing service principals and other app debris that the app vendor might leave behind.

The sign-ins for the app used by the PowerShell script probably exist because I shared a copy of the script with my tenant identifier, the app identifier, and the app secret in place. I quickly replaced the script with a copy containing obfuscated credentials, but failed to change the app secret, meaning that anyone with an original copy could run the code. Now alerted, I removed the app secret. My suspicions were confirmed when a batch of failed sign-ins subsequently occurred for the app. This goes to prove how easy it is to create a potential compromise if you’re not careful.

Removing a Service Principal with PowerShell

You can clean up unwanted service principals with either the Entra admin center or PowerShell. I always have a PowerShell session open, so I chose that route. In this example, we find the object identifier for a service principal using its display name as a filter for the Get-MgServicePrincipal cmdlet. When sure that this is the right service principal to remove, we use the object identifier to remove the service principal with the Remove-MgServicePrincipal cmdlet.

$SP = Get-MgServicePrinicpal -filter "displayname eq 'Office 365 Reports'"

$SP

DisplayName        Id                                   AppId                                SignInAudience     
-----------        --                                   -----                                --------------     
Office 365 Reports 9ac957ae-160b-48d3-9a6f-f4c27acca040 507bc9da-c4e2-40cb-96a7-ac90df92685c AzureADMultipleOrgs 

Remove-MgServicePrincipal -ServicePrincipalId $Sp.id

Adding Context

A list of service principals known to the tenant is a valuable input to a review for unwanted or unnecessary apps holding some form of consent (permissions) to organization data. Adding context to the data by knowing which service principals are actively signing into the tenant makes it easier to prioritize action. The data is there, it’s available, and it’s up to you to decide what to do with it.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

]]>
https://office365itpros.com/2022/02/03/service-principal-sign-in-data-detect-problem-apps/feed/ 0 53160
Using Break Glass Accounts with Microsoft 365 Tenants https://office365itpros.com/2022/01/19/using-break-glass-accounts-microsoft-365-tenants/?utm_source=rss&utm_medium=rss&utm_campaign=using-break-glass-accounts-microsoft-365-tenants https://office365itpros.com/2022/01/19/using-break-glass-accounts-microsoft-365-tenants/#comments Wed, 19 Jan 2022 01:00:00 +0000 https://office365itpros.com/?p=52978

Backup In Case Normal Authentication Fails

An obvious difference between cloud and on-premises management is that Microsoft 365 won’t allow you to sign into the console of a physical computer when all else fails and you need to access a server. Not having to go and reboot a server or perform other maintenance to resurrect a failing application is one of the joys of cloud services.

However, sometimes things do go wrong, and normal administrative sign-ins don’t work. It’s possible that an outage might interfere with the ability to sign into Azure AD to access administrator accounts. The most serious kind of outage is when a tenant comes under attack and the attackers change the password for the administrator accounts. A more mundane reason is that someone changes the password of the administrator accounts (perhaps with the best intentions) and promptly forgets. Or that you follow best practice and enable multi-factor authentication (MFA) for all administrator accounts only for the MFA service to go down as happened in November 2018.

To prevent the complete lock out of administrators when bad things happen, it’s a good idea to create one or more break glass accounts (otherwise known as an emergency access accounts). These are highly-permissioned accounts (perhaps holding the global administrator role) intended for use in emergency situations.

Break glass accounts don’t need Microsoft 365 licenses. Their sole role is to perform administrative actions when regular administrator accounts are unavailable. It’s a waste to assign licenses to these accounts as you’ll end up paying monthly fees for zero utility.

Characteristics of Break Glass Accounts

Break glass accounts have the following characteristics:

  • Hosted in the cloud: To avoid any dependency on federation with an external or on-premises directory, break glass accounts are cloud objects. The user principal name for the accounts should use the tenant service domain (tenant.onmicrosoft.com). Although it seems logical to use a value like “Break Glass Account” in the user principal names and display names assigned to these accounts, it might be better to obscure their purpose with names that won’t attract attention like “Building Pipeline Maintenance” or something else that won’t attract attention.
  • No simple passwords: Multiple layers of authentication such as MFA protect the accounts. However, you should take care to minimize the number of dependencies used by authentication to ensure that the account is available when needed. For instance, you should exclude break glass accounts from conditional access policies to ensure that a policy doesn’t block a signin attempt for the account.
  • Varied authentication: To reduce the possibility that a failure blocks access to all break glass accounts, you should vary the authentication methods used for these accounts. Break glass accounts need MFA to access Azure administrative sites and tools. Don’t use SMS-based responses for MFA as the preferred challenge for all accounts. It’s a weak authentication method and a failure of the SMS service will prevent all access. Use a strong authentication method like a FIDO2 key instead and make sure that the keys are stored securely.

In the past, the recommendation was to give break glass accounts passwords that are complex, long, and obscure. Given the need to use MFA to access Azure administrative sites and tools, the need for such a password is reduced. However, multiple layers of security is usually a good idea, so set good passwords for or break glass accounts and store the passwords securely. The details of the storage location and how administrators can access passwords will vary from organization to organization. Some people suggest storing the passwords in fireproof containers in a locked safe. Others recommend dividing passwords up into several parts and storing each part in a separate network location (OneDrive personal, Google Drive, Dropbox, and so on). The important thing is that the process to retrieve break glass account password works, is documented, and audited to prove that it works.

Checking for Break Glass Sign-In Events

After each use of a break glass account, you should change the password. And to make sure that no unauthorized access happens, you should check Azure AD sign-in data periodically to pick up any attempts to log into the accounts. Microsoft documents how to use Azure Monitor for this purpose. The same Kusto queries will work with Microsoft Sentinel.

It’s also possible to run checks against the Office 365 audit log using the Search-UnifiedAuditLog cmdlet. For example, this code runs an audit log search for log in events for two break glass accounts and displays details of any events it finds.

# Identify the accounts to check
$Accounts = "Break.Glass.Account1@office365itpros.onmicrosoft.com", "Break.Glass.Account2@office365itpros.onmicrosoftcom"
$StartDate = (Get-Date).AddDays(-14); $EndDate = (Get-Date).AddDays(1) # Set your own date span here!
[array]$Records = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Formatted -Operations UserLoggedIn -UserIds $Accounts -ResultSize 5000
If (!($Records)) {Write-Host "No audit records found - exiting!"; break}
$Events = [System.Collections.Generic.List[Object]]::new() 	
ForEach ($Rec in $Records) {
   $AuditData = $Rec.AuditData | ConvertFrom-Json
   $DataLine = [PSCustomObject] @{
         ClientIP            = $AuditData.ClientIP
         Date                = $Rec.CreationDate
         User                = $Rec.UserIds
         UserAgent           = $AuditData.ExtendedProperties | ? {$_.Name -eq "UserAgent"} | Select -ExpandProperty Value
         OS                  = $AuditData.DeviceProperties | ? {$_.Name -eq "OS"} | Select -ExpandProperty Value
         Browser             = $AuditData.DeviceProperties | ? {$_.Name -eq "BrowserType"} | Select -ExpandProperty Value
        }
    $Events.Add($DataLine) 

}
If ($Events) {
     CLS
     Write-Host "Log in Events for Break Glass Accounts"
     $Events | Select Date, ClientIP, User, UserAgent
>> }

Log in Events for Break Glass Accounts

Date                ClientIP       User                                                  UserAgent
----                --------       ----                                                  ---------
10/01/2022 17:48:31 51.171.212.129 Break.Glass.Account1@office365itpros.onmicrosoft.com Mozilla/5.0 (Windows NT 10....
10/01/2022 17:48:31 51.171.212.129 Break.Glass.Account1@office365itpros.onmicrosoft.com Mozilla/5.0 (Windows NT 10....
10/01/2022 17:48:29 51.171.212.129 Break.Glass.Account1@office365itpros.onmicrosoft.com Mozilla/5.0 (Windows NT 10....
10/01/2022 17:48:29 51.171.212.129 Break.Glass.Account1@office365itpros.onmicrosoft.com Mozilla/5.0 (Windows NT 10....
10/01/2022 17:48:28 51.171.212.129 Break.Glass.Account1@office365itpros.onmicrosoft.com Mozilla/5.0 (Windows NT 10....

Multiple signin events for an account over a short period of time are not unusual. Teams, for instance, has a habit of generating multiple events when a user connects. The important thing is that evidence exists of sign-in activity for an account which should not be signing in. This deserves immediate investigation.

Not for Everyday Use

Hopefully, you never have to use a break glass account to rescue a tenant. Touching every available piece of wood in the immediate vicinity, I have never had to use my break glass account. But it’s there and waiting. Just in case.


Keep up with the changing world of the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. Monthly updates mean that our subscribers learn about new development as they happen.

]]>
https://office365itpros.com/2022/01/19/using-break-glass-accounts-microsoft-365-tenants/feed/ 6 52978
How to Determine the Age of a Microsoft 365 Tenant https://office365itpros.com/2022/01/14/find-age-microsoft-365-tenant/?utm_source=rss&utm_medium=rss&utm_campaign=find-age-microsoft-365-tenant https://office365itpros.com/2022/01/14/find-age-microsoft-365-tenant/#comments Fri, 14 Jan 2022 01:00:00 +0000 https://office365itpros.com/?p=53007

Use Teams, PowerShell, or the Graph

Vasil Michev, the Technical Editor of the Office 365 for IT Pros eBook, comes up with all sorts of weird and wonderful insights into Microsoft 365. A recent question he discussed on his blog was how to find the creation date for a tenant. It’s a good question because it forces respondents to know where to look for this information and is exactly the kind of poser we like to tease out as we write content for the book.

As Vasil points out, the obvious answer is to fire up the Teams admin center because the tenant creation date appears on a card displayed on its home screen (Figure 1). The Teams admin center is the only Microsoft 365 portal which shows this information. Why the Teams developers thought that it was useful to highlight the tenant creation date is unknown. After all, the date won’t change over time and static information is not usually featured by workload dashboards.

Viewing the tenant creation date in the Teams admin center
Figure 1: Viewing the tenant creation date in the Teams admin center

Opening an administrative portal is no challenge. Vasil suggests several alternate methods to retrieve the tenant creation date. It seemed like fun to try some of these methods against my tenant. Here’s what I found.

Using Exchange Online Data

If you’ve used Exchange Online from the start, you can check the creation date of the Exchange organization configuration object, created when an administrator enables Exchange Online for the first time.

(Get-OrganizationConfig).WhenCreated

Monday 27 January 2014 20:28:45

It’s an interesting result. Exchange Online reports its initiation in January 2014 while Teams is quite sure that the tenant existed in April 2011. I’ve used Exchange Online for email ever since I had a tenant, so the disconnect between Exchange Online and the tenant creation date is interesting.

Another way of checking Exchange data is to look at the creation dates for mailboxes. This PowerShell snippet finds all user mailboxes and sorts them by creation date. The first mailbox in the sorted array is the oldest, so we can report its creation date:

[array]$Mbx = Get-ExoMailbox -ResultSize Unlimited -Properties WhenCreated -RecipientTypeDetail UserMailbox | Sort {$_.WhenCreated -as [datetime]} 
Write-Host ("The oldest mailbox found in this tenant is {0} created on {1}" -f $Mbx[0].DisplayName, $Mbx[0].WhenCreated)

The oldest mailbox found in this tenant is Tony Redmond created on 27/01/2014 20:36:38

(Dates shown are in Ireland local format. The equivalent U.S. format date is 01/27/2014).

Grabbing all mailboxes to check their creation date will not be a fast operation. Even using the REST-based Get-ExoMailbox cmdlet from the Exchange Online management module, it will take time to retrieve all the user mailboxes in even a medium size tenant.

As it turns out, the oldest mailbox is my own, created about eight minutes after the initiation of Exchange Online. However, we’re still in 2014 when the tenant proclaims its creation in 2011, so what happened?

A search through old notes revealed that Microsoft upgraded my original Office 365 tenant created in 2011 to an enterprise version in 2014. It seems that during the tenant upgrade, Microsoft recreated the instance of Exchange Online. That explanation seems plausible.

Administrator Accounts

Another method is to examine the creation dates of administrator accounts to find the oldest account. This is usually the administrator account created during tenant setup. In other words, when you create a new tenant, you’re asked to provide the name for an account which becomes the first global administrator. If we look at the administrator accounts in the tenant and find the oldest, it should be close to the tenant creation date shown in the Teams admin center. That is, unless someone deleted the original administrator account.

Azure AD is the directory of record for every Microsoft 365 tenant, so we should check Azure AD for this information. The steps are:

  • Find the set of accounts which currently hold the global administrator role. We omit the account returned with the object id 25cbf210-02e5-4a82-9f5c-f41befd2681a as this is a service principal used by Microsoft Rights Management services (you can confirm this by running Get-AzureADServicePrincipal -ObjectId 25cbf210-02e5-4a82-9f5c-f41befd2681a).
  • Check each account to find the creation date. This is slightly complicated when using the Azure AD PowerShell module because the creation date is part of the extension properties. We therefore use the Get-AzureADUserExtension cmdlet to extract the date and then store it in the array used to hold details about tenant administrators.
  • Sort the accounts by creation date and report the oldest.

Here’s the code I used:

# Find the identifier for the Azure AD Global Administrator role
$TenantAdminRole = Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq ‘Global Administrator’} | Select ObjectId
# Get the set of accounts holding the global admin role. We omit the account used by
# the Microsoft Rights Management Service
$TenantAdmins = Get-AzureADDirectoryRoleMember -ObjectId $TenantAdminRole.ObjectId | ? {$_.ObjectId -ne "25cbf210-02e5-4a82-9f5c-f41befd2681a"} | Select-Object ObjectId, UserPrincipalName
# Get the creation date for each of the accounts
$TenantAdmins | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Name "Creation Date" -Value (Get-AzureADUserExtension -ObjectId $_.ObjectId ).Get_Item("createdDateTime") }
# Find the oldest account
$FirstAdmin = ($TenantAdmins | Sort-Object {$_."Creation Date" -as [datetime]} | Select -First 1)
Write-Host ("First administrative account created on {0}" -f $FirstAdmin."Creation Date")

The older Microsoft Online PowerShell module doesn’t require such a complicated approach to retrieve account creation data. Taking the code shown above and replacing the Get-AzureADUserExtension cmdlet with Get-MsOlUser, we get:

$TenantAdmins | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Name "Creation Date" -Value ((Get-MsOlUser -ObjectId $_.ObjectId ).WhenCreated) }

Using either cmdlet, the result is:

First administrative account created on 11/04/2011 17:35:11

The Teams admin center also reports April 11, 2011, so using administrator accounts might be a viable way to determine tenant age.

Use the Graph

Microsoft 365 stores information for each tenant in the Microsoft Graph, and it’s the Graph which is the source for the Teams admin center. We can retrieve the same information by running the https://graph.microsoft.com/V1.0/organization Graph query. The createdDateTime property returned in the organization settings is what we need.

Here’s the PowerShell code to run after obtaining the necessary access token for a registered app, which must have consent to use the Organization.Read.All Graph permission. Vasil used the beta endpoint when he showed how to fetch tenant organization settings using the Graph Explorer (which saves the need to write any code), but the V1.0 endpoint works too.

$Uri = "https://graph.microsoft.com/V1.0/organization"
$OrgData = Invoke-RESTMethod -Method GET -Uri $Uri -ContentType "application/json" -Headers $Headers
If ($OrgData) {
  Write-Host ("The {0} tenant was created on {1}" -f $Orgdata.Value.DisplayName, (Get-Date($Orgdata.Value.createdDateTime) -format g)) }

The Redmond & Associates tenant was created on 11/04/2011 18:35

The first administrator account appears to date from 17:35 while the tenant creation time is an hour later. This is easily explained because all dates stored in the Graph are in UTC whereas the dates extracted from Azure AD and reported by PowerShell reflect local time. In April 2011, local time in Ireland was an hour ahead of UTC.

An Old Tenant

After all the checks, it’s clear that I created my tenant in the early evening of April 11, 2011. Given that this was ahead of Microsoft’s formal launch of Office 365 in July 2011, I can claim to use an old tenant, for what that’s worth.

]]>
https://office365itpros.com/2022/01/14/find-age-microsoft-365-tenant/feed/ 2 53007
Continual Access Evaluation Enabled for Critical Azure AD Events in Microsoft 365 Tenants https://office365itpros.com/2022/01/12/continual-access-evaluation/?utm_source=rss&utm_medium=rss&utm_campaign=continual-access-evaluation https://office365itpros.com/2022/01/12/continual-access-evaluation/#comments Wed, 12 Jan 2022 01:00:00 +0000 https://office365itpros.com/?p=52991

Important Microsoft 365 Workloads Respond to Critical Azure AD Events

Microsoft made a critical announcement on January 10 when they revealed that the base Office 365 workloads support continual access evaluation (CAE) for specific Azure AD events. What’s more, Microsoft has enabled this capability for all Microsoft 365 tenants.

Exchange Online, SharePoint Online, and Teams can now accept signals from Azure AD when an administrator:

  • Deletes or disables an Azure AD user account.
  • Changes or resets the password for a user account.
  • Explicitly revokes all refresh tokens for a user account.
  • Enables multi-factor authentication for a user account.

The top three actions correspond to highlighted options available at the top of the user account management card in the Microsoft 365 admin center (Figure 1). Multifactor enablement is at the bottom of the card.

Continuous access evaluation covers critical administrative actions for Microsoft 365 user accounts
Figure 1: CAE covers critical administrative actions for Microsoft 365 user accounts

In addition, Exchange Online can respond when Azure AD Identity Protection detects that higher risk of compromise exists for a user account.

Administrators can see details of sign-ins which use continuous access evaluation by applying a filter of (Is CAE Token = Yes) in the Azure AD admin portal. Figure 2 shows details of a CAE-enabled session.

Continuous Access Evaluation noted in the Azure AD sign-in log
Figure 2: Continuous Access Evaluation noted in the Azure AD sign-in log

Browsing the Azure AD sign-in log is enlightening in terms of understanding the degree of application support for CAE. Although currently limited to applications like OWA and the SharePoint Online browser interface, you’d anticipate that Microsoft will increase coverage over time.

Enlightened Applications

Continuous access evaluation means that the “enlightened” applications learn about changes in user accounts in almost real-time. For instance, if an administrator deletes a user account, the applications remove access immediately instead of waiting for the access token granted as the result of the last successful authentication by the account to expire.

Microsoft says that the use of continuous access evaluation means that “authentication session lifespan now depends on session integrity rather than on a predefined duration.” For example, if an event like a password change occurs to affect the integrity of a browser session where a user is connected to SharePoint Online, instead of waiting for the access token to expire, SharePoint Online will immediately demand that the user re-establishes session integrity by proving their credentials are still valid.

The effect is that users affected by these critical events must either reauthenticate (for instance, using a new password), or lose access to email, documents, calendar, and Teams. This makes it much easier to manage the possibility of data loss in cases like account compromise or the departure of disgruntled employees.

A benefit of continuous access evaluation is that in the case of outages, extended session lifetimes enabled by removing the dependency on the access token as the sole control over accounts mean that people can continue working without needing to revert to Azure AD (see this note about Microsoft’s Azure AD backup service).

Conditional Access Policy Support

While response to critical Azure AD events is available for all Microsoft 365 tenants, those with Azure AD Premium licenses can include continuous access evaluation in the criteria used by conditional access policies to decide to grant or deny user access to applications based on conditions like network location.

Zero Trust in Action

Microsoft talks about the Zero Trust model a lot. An action like enabling continuous access evaluation for critical events in all Microsoft 365 tenants is a practical and useful example of the Zero Trust initiative. Even if you don’t use conditional access policies (something I think all tenants should consider to improve their security posture), the fact that the base Microsoft 365 workloads now respond to critical Azure AD events almost in real time is a very welcome advance.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant. We cover continuous access evaluation in the chapter on Microsoft 365 identities.

]]>
https://office365itpros.com/2022/01/12/continual-access-evaluation/feed/ 1 52991
Stopping Microsoft Teams Posting System Messages About New Members https://office365itpros.com/2022/01/07/stopping-teams-posting-system-messages-about-new-members/?utm_source=rss&utm_medium=rss&utm_campaign=stopping-teams-posting-system-messages-about-new-members https://office365itpros.com/2022/01/07/stopping-teams-posting-system-messages-about-new-members/#respond Fri, 07 Jan 2022 01:00:00 +0000 https://office365itpros.com/?p=52923

No Way to Suppress Messages

A reader asked if it’s possible to stop Teams displaying a system-generated message when someone joins a team. It’s a reasonable question. In the past, I have pointed out the dangers of adding someone to a group too early as people can then discover that a new employee is joining the company. Conversely, it’s not good when people learn about the departure of a valued colleague through an informational message posted in Teams to say that the person has left a team.

Things used to be worse. Before May 2020, Teams posted messages about members joining and leaving a team in the team’s General channel. The introduction of the channel information pane gave these system messages a new home. Unless people open the information pane, they don’t see messages about membership changes, new owners and channels, and other developments, so there’s a fair chance that the addition of a new employee to a team will go unnoticed.

The Many Ways to Add New Members to a Team

To see any of the methods to add a new member do not result in a system message in the information pane, I tested by adding a new member through:

  • The Teams client.
  • The Add-UnifiedGroupLinks cmdlet from the Exchange Online management module.
  • The Add-AzureADGroupMember cmdlet from the Azure AD module.
  • The Add-TeamUser cmdlet from the Microsoft Teams module.

I didn’t test using the Microsoft Graph API. The Add-TeamUser cmdlet is a wrapper around the Graph API call, so the results observed for that cmdlet are likely the same for a Graph call. System messages are retrievable using Graph API calls.

Azure AD is the directory of record. Add-AzureADGroupMember updates the Azure AD group object used by the team. Add-UnifiedGroupLinks updates the Azure AD group object and the group in the Exchange Online directory using a dual write. Add-TeamUser is like adding a new member through the client because the action updates both the team roster (to make the new team member immediately available) and Azure AD. Rosters (lists of members and owners) are how Teams organizes and manages membership.

Changes made to Azure AD or by other Microsoft 365 workloads synchronize with Teams through a background process called Microsoft Teams Aad Sync, introduced in 2020 to make the synchronization process between Teams and Azure AD more efficient and effective. Note that it can take several hours before a system message about a new member shows up. Apart from the need to run background synchronization, clients also need to refresh their cache.

In a nutshell, no matter how you add or remove a tenant or guest account, the change synchronizes back to Teams and the system message appears in the information pane (Figure 1).

System messages about membership changes appear in the information pane
Figure 1: System messages about membership changes appear in the information pane

Different system messages in the information pane appear depending on the method used to add an account. If you see that someone added a member (like “Tony Redmond has added Niamh Smith to the team”), it’s an indication that the action occurred through the Teams client, the Add-TeamUser cmdlet, or the Graph API (all of which execute the same code). On the other hand, if you see that someone joined the team, the source is Azure AD or Exchange Online PowerShell.

No Control Over System Messages

There’s no system or team setting to tweak to turn off system messages about member updates. Granular control would be best, but I guess Microsoft ignored me when I previously complained about the lack of control over system message publication, so I’ve submitted it again to the new Teams Feedback portal. Please vote there if you support the idea of having a team-level setting to control the publication of system messages.

In the interim, if you don’t want other users to discover that someone has joined a team, either wait until an appropriate time before adding them as a member or consider assigning a new display name to that person’s account until you’re ready to reveal their presence. For instance, I changed the name of a new user as follows:

Set-AzureADUser -Identity James.Baker@office365itpros.com -DisplayName "The Maestro of Office 365"

After waiting for a few hours to allow Teams to pick up details of the user account, I added them to a team. Sometime later, the information pane duly displays the system message for the addition (Figure 2):

Obscuring the addition of a new team member
Figure 2: Obscuring the addition of a new team member

This technique works if you want to pre-add new users to teams before they join the organization if you use suitably obscured display names, like UserAXXAD19948. Naturally, you should update their display name after they’re active in the organization. However, it’s not a great approach for people who already work there as other workloads pick up and use the changed display name.

Small Detail

The answer to the original question is that you can’t stop Teams posting system messages to inform team members about membership changes. No control is available at a system or individual team level, which is a pity. But life isn’t perfect, and this is a small detail in the overall scheme of things – unless you inadvertently reveal the name of a new employee before they join the company.


Learn how to exploit the Office 365 data available to tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2022/01/07/stopping-teams-posting-system-messages-about-new-members/feed/ 0 52923
Latest AAD Connect Removes On-Premises Disabled User Accounts from Azure AD https://office365itpros.com/2021/12/22/aad-connect-fails-synchronize-shared-mailboxes/?utm_source=rss&utm_medium=rss&utm_campaign=aad-connect-fails-synchronize-shared-mailboxes https://office365itpros.com/2021/12/22/aad-connect-fails-synchronize-shared-mailboxes/#comments Wed, 22 Dec 2021 12:11:32 +0000 https://office365itpros.com/?p=52823

Shared Mailboxes Aren’t Important, Are They?

First reported by MVP Jeff Guillet, the recent release of AAD Connect 2.0.88.0 includes a very nasty bug: it removes disabled Active Directory user accounts from Azure AD when it synchronizes information from the on-premises directory to the cloud. The issue here is that Exchange uses disabled user accounts for shared mailboxes. When synchronization occurs to remove the disabled user accounts, Exchange Online users can no longer access on-premises shared mailboxes because they’re not present in the GAL.

According to the release history for AAD Connect, on December 21, Microsoft acknowledged the problem and released version 2.0.89.0 for download. This version is unavailable for auto upgrade.

Roll Back to Previous Version

If you’ve already deployed 2.0.88.0, possibly to explore the (preview) ability to synchronize objects from a single Active Directory forest to multiple Microsoft 365 tenants, Jeff recommends that you roll back to version 2.0.28.0 instead (the software is available from his site). He knows more than I do about AAD Connect and it seems wise to revert to a stable version while Microsoft sorts out any issues which might still lurk in the new version.

A Lack of Testing

Given that the function of AAD Connect is to synchronize mail-enabled objects from on-premises directories to Microsoft 365 tenants, it’s both strange and troubling that Microsoft allowed this software to appear with such a fundamental flaw in place. Omitting shared mailboxes during synchronization cycles creates questions about the kind of testing regime Microsoft used. Perhaps the need to ship the software before Microsoft closed for the holidays meant that some shortcuts in testing crept in. For whatever reason, it’s not a good story.

Happy Holidays

Speaking of the holidays, this is likely the last post in the Office 365 for IT Pros blog for 2021. We’ll be back in 2022 to share information about Office 365 and the wider Microsoft 365 ecosystem in all its glory and occasional seedy bits. If you’re on vacation, enjoy the time off, and if you need to work to keep systems going, we hope you don’t have any major outages to deal with.

As for us, we need to get the January 2022 update done for the Office 365 for IT Pros eBook. That’s a train which keeps on chugging…

]]>
https://office365itpros.com/2021/12/22/aad-connect-fails-synchronize-shared-mailboxes/feed/ 3 52823
How to Manage Guest Accounts in Other Tenants from Microsoft Teams https://office365itpros.com/2021/12/15/manage-guest-accounts-from-microsoft-teams/?utm_source=rss&utm_medium=rss&utm_campaign=manage-guest-accounts-from-microsoft-teams https://office365itpros.com/2021/12/15/manage-guest-accounts-from-microsoft-teams/#comments Wed, 15 Dec 2021 01:00:00 +0000 https://office365itpros.com/?p=52726

Decluttering Your Set of Guest Accounts

Originally published as MC300029 and then again as MC302456 (December 8, Microsoft 365 roadmap item 88430), Microsoft is making it easier for people to manage the guest memberships they have in other organizations (Microsoft 365 tenants) through Teams. Until now, leaving an organization must be initiated from Azure AD’s My Organizations page. However, many users don’t know about this page or how to go about reviewing and removing unwanted memberships in other organizations. The net result is that the organization drop-down menu in Teams can become very cluttered.

Changes

The changes due to be rolled out by late December allow users to:

  • Decline invitations in the Teams desktop and browser clients.
  • Leave an organization from the Teams desktop and browser clients.
  • Hide organizations they don’t want to access often to unclutter the organizations listed by the Teams clients (and unhide or show those organizations again if needed).

Let’s examine each change in more detail.

Nope, I Don’t Want to Join

When a user is added as a guest in a team (or Outlook group) for the first time in an organization, Azure B2B Collaboration (aka Microsoft Invitations) generates the guest account and adds it to the team membership. However, the guest account only becomes active after its owner redeems the invitation to join the organization.

The change made in Teams allows people to decline an inbound invitation to become a guest in another organization using the Decline option from the […] menu in Manage Accounts (Figure 1).

Using Teams to decline an invitation to join another organization as a guest
Figure 1: Using Teams to decline an invitation to join another organization as a guest

Declining an invitation removes the inviting tenant from the list shown to the user in the Teams menu bar. The person who extended the invitation can add the user as a guest to a team or group if they wish to regenerate the invitation.

Leaving You is Bittersweet

The Teams user interface for leaving an organization (Figure 2) brings you to the My organizations page and the process of leaving a tenant follows the same steps as outlined here. Even so, it’s still goodness to make the process more accessible and easier for users.

The Teams option to leave another organization
Figure 2: The Teams option to leave another organization

Once the user reaches the My Organizations page, they can select the organization to leave (not necessarily the one chosen in Teams). After signing the user into the target organization, Azure AD removes the guest account and returns them to their home organization. Azure B2B Collaboration generates email (Figure 3) to let the user know that they’ve left successfully and to remind them that information they created in the organization they’ve just left remains under the control of that organization. The logo in the message is the result of customizing the organization’s Azure AD sign in screens.

Figure 3: The last sight of an organization you’ve just left

In practical terms, the important point here is to remove anything you want from Teams (including documents posted to SharePoint Online) before departing. Remember, removing a guest account from an organization also breaks any sharing links to SharePoint Online and OneDrive for Business data which use the guest account.

Some organizations proactively search for and remove obsolete guest accounts. When this happens, users don’t have to worry about their guest accounts because the host organization deletes them.

Stay Hidden

Sometimes leaving another tenant by removing a guest account is a step too far. You might want to retain access to the organization, even if you only use it intermittently and not as part of your day-to-day activities. If you look at Figure 2, you see the option to Hide an organization. This keeps your guest account intact while removing the organization from the list shown by Teams to allow the user to switch between tenants. If you’re hiding an organization, it’s often a good idea to mute notifications from that organization too.

If the user wants to add an organization back to the tenant list, they can use the Manage account option in Teams settings to unhide (show) a tenant.

Some Relief in Teams Connect

The advent of shared channels in Teams (due in early 2022) will remove the need to use guest accounts to access Teams information in other organizations because it uses a technology called Teams Connect instead of Azure B2B Collaboration. The big difference is that those who access shared channels in another tenant use their own identities (authentication against Azure AD in their home tenant) instead of guest accounts in the host tenant. However, guest accounts will continue to support access to Teams regular and private channels and sharing links created by SharePoint Online and OneDrive for Business.


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2021/12/15/manage-guest-accounts-from-microsoft-teams/feed/ 3 52726
How Microsoft Aims to Cure Azure AD Authentication Problems with New Backup Service https://office365itpros.com/2021/11/25/azure-ad-backup-authentication-service/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-backup-authentication-service https://office365itpros.com/2021/11/25/azure-ad-backup-authentication-service/#comments Thu, 25 Nov 2021 01:00:00 +0000 https://office365itpros.com/?p=52489

Fixing the Achilles Heel of Office 365

Over the years, Office 365 has maintained a very high level of service, comfortably exceeding Microsoft’s financially-backed 99.9% SLA target since some initial glitches soon after Office 365 launched in 2011. When things have gone wrong recently, Azure AD has often been the source of problems. Authentication woes of one sort or another have existed since the start of Office 365. As long ago as 2015, I asked the question if Azure AD was the Achilles heel for Office 365.

In some respects, it’s natural that the directory service should be a hyper-critical component of any service, whether cloud or on-premises. If a client cannot authenticate, it cannot access resources. It’s a simple equation proven by the many instances when loss of authentication capability brought clients to a crashing halt.

The Backup Authentication Service and Its Three-Day Cache of Successful Authentications

Microsoft has gradually improved the resilience of Azure AD over the years by eliminating single point of failures (like the MFA service) and building out capacity. The latest innovation is a backup authentication service, aimed at underpinning 99.99% authentication uptime for Azure AD.

A November 22 blog post explains the plan. Microsoft has implemented a service which monitors Azure AD to detect any outages. When an outage occurs, the backup authentication service swings into operation to handle authentication requests from clients, which are routed to it automatically by the Azure AD gateway (the first point of contact When the primary instance of Azure AD recovers, the backup service dynamically reroutes requests to it and returns to monitoring (normal) mode.

The backup service handles authentication requests using information derived from successful authentication requests processed by Azure AD (Figure 1). This information can be up to three days old. It’s enough for the backup service to validate that an application successfully authenticated at a point in time within the last three days and go ahead to generate an authentication response to allow the application to proceed. According to Microsoft, more than 90% of authentication requests processed by Azure AD are for existing client sessions. These can all be handled by the backup service. On the other hand, because the backup service doesn’t have any data for new sessions, it cannot handle these requests (or requests from guest accounts).

The Azure AD backup authentication service (image credit: Microsoft)
Figure 1: The Azure AD backup authentication service (image credit: Microsoft)

Conditional Access and Resilience Defaults

Apart from dealing with authentication requests, the backup authentication service enforces multi-factor authentication, conditional access policies, and continuous access evaluation to ensure that invalid credentials cannot be used.

To ensure as high a level of continuity of service as possible, the backup authentication service uses resilience defaults for conditional access policies to allow it to continue without depending on conditions such as sign-in risk or group membership that aren’t available in real time when the primary Azure AD service is offline. Essentially, the policies proceed on the basis that conditions have not changed since Azure AD went offline. Organizations who don’t want this to happen can disable the resilience defaults for all or some conditional access policies through the Azure AD admin center (Figure 2) in the knowledge that this will affect the ability of some client connects to authenticate.

Where to disable resilience defaults for an Azure AD conditional access policy
Figure 2: Where to disable resilience defaults for an Azure AD conditional access policy

Gradual Introduction Since 2019

The best thing of all is that the backup authentication service has been in place for OWA and SharePoint Online since 2019. In early 2021, Microsoft added support for “native” apps, including the Microsoft 365 apps for enterprise (like Outlook) and the Teams desktop and mobile clients. Because the rerouting of authentication requests happens at the gateway level and the responses from the backup authentication service are identical to those issued by the primary Azure AD service, no client reconfiguration or special settings are necessary.

Microsoft is now upgrading support to bring in apps using Open ID Connect, starting with their own Teams Online and Office Online apps and progressing to customer apps. They expect to begin rolling out this support at the end of 2021. At that point, all of Office 365 should be protected by the backup authentication service, which should mean that any future Azure AD outage should be much less serious than previous events.

Reasonable Compromise

Storing information about successful authentication requests for three days and using that information to allow people to continue working if the Azure AD service goes offline seems like a reasonable balance between utility and security. We know that Azure AD outages have occurred in the past. We also know that Azure AD continues to handle more traffic over time (now at 500 million monthly active users generating tens of billions of authentications daily, according to Microsoft), which creates stress on its own. Some Azure AD outages can be expected in the future. The good news is that a backup supply for authentications, at least for the majority of client sessions, is now available.


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2021/11/25/azure-ad-backup-authentication-service/feed/ 1 52489
How to Find When Azure AD User Accounts Receive Microsoft 365 Licenses https://office365itpros.com/2021/11/10/find-when-azure-ad-user-accounts-receive-microsoft-365-licenses/?utm_source=rss&utm_medium=rss&utm_campaign=find-when-azure-ad-user-accounts-receive-microsoft-365-licenses https://office365itpros.com/2021/11/10/find-when-azure-ad-user-accounts-receive-microsoft-365-licenses/#comments Wed, 10 Nov 2021 01:00:00 +0000 https://office365itpros.com/?p=52291

Licensing Report Has No Dates

I recently published a Practical365.com article explaining how to create a licensing report for an Office 365 tenant using cmdlets from the Microsoft Graph SDK for PowerShell.

A reader asked: “I am trying to determine when a specific license, in this case an E3 Security and Mobility license, was added for all users.”

No Dates for Licenses

It’s an interesting question. As written, my script generates a report based on the licenses and service plans assigned to user accounts. However, it doesn’t do anything to tell you when a license for a product like Enterprise Security and Mobility E3 (EMS E3) is assigned to a user. This is because Azure AD does not record assignment dates for the product license information held for user accounts. Instead, license information for an account is presented as a table of SKU identifiers with any disabled service plans in a SKU noted:

$User,AssignedLicenses

DisabledPlans                          SkuId
-------------                          -----
{bea4c11e-220a-4e6d-8eb8-8ea15d019f90} b05e124f-c7cc-45a0-a6aa-8cf78c946968
{}                                     8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b
{}                                     4016f256-b063-4864-816e-d818aad600c9
{a23b959c-7ce8-4e57-9140-b90eb88a9e97} 6fd2c87f-b296-42f0-b197-1e91e994b900

However, date information is included in the service plan information for an account:

$User.AssignedPlans

AssignedDateTime    CapabilityStatus Service                       ServicePlanId
----------------    ---------------- -------                       -------------
09/11/2021 10:33:37 Enabled          AzureAdvancedThreatAnalytics  14ab5db5-e6c4-4b20-b4bc-13e36fd2227f
09/11/2021 10:33:37 Enabled          AADPremiumService             eec0eb4f-6444-4f95-aba0-50c24d67f998
09/11/2021 10:33:37 Enabled          RMSOnline                     5689bec4-755d-4753-8b61-40975025187c
09/11/2021 10:33:37 Enabled          SCO                           c1ec4a95-1f05-45b3-a911-aa3fa01094f5
09/11/2021 10:33:37 Enabled          AADPremiumService             41781fb2-bc02-4b7c-bd55-b576c07bb09d
09/11/2021 10:33:37 Enabled          MultiFactorService            8a256a2b-b617-496d-b51b-e76466e88db0
09/11/2021 10:33:37 Enabled          RMSOnline                     bea4c11e-220a-4e6d-8eb8-8ea15d019f90
09/11/2021 10:33:37 Enabled          RMSOnline                     6c57d4b6-3b23-47a5-9bc9-69f17b4947b3
09/11/2021 10:33:37 Enabled          Adallom                       2e2ddb96-6af9-4b1d-a3f0-d6ecfd22edb2

Checking Dates for Service Plan Assignments

Given that date information is available for service plans, it should therefore be possible to check against the service plan information for user accounts to find assignments of a service plan belonging to a product (SKU). Looking at the Product names and service plan identifiers for licensing page , we find the list of service plans included in EMS E3 (SKU identifier efccb6f7-5641-4e0e-bd10-b4976e1bf68e). The set of service plans are:

  • Azure Active Directory Premium P1: 41781fb2-bc02-4b7c-bd55-b576c07bb09d
  • Azure Information Protection Premium P1: 6c57d4b6-3b23-47a5-9bc9-69f17b4947b3
  • Cloud App Security Discovery: 932ad362-64a8-4783-9106-97849a1a30b9
  • Exchange Foundation: 113feb6c-3fe4-4440-bddc-54d774bf0318
  • Microsoft Azure Active Directory Rights: bea4c11e-220a-4e6d-8eb8-8ea15d019f90
  • Microsoft Azure Multi-Factor Authentication: 8a256a2b-b617-496d-b51b-e76466e88db0
  • Microsoft Intune: c1ec4a95-1f05-45b3-a911-aa3fa01094f5

The theory is that you should be able to check accounts assigned EMS E3 to retrieve information about one of the service plans in the SKU and retrieve and report the assigned date. I don’t have EMS E3 in my tenant, but I do have EMS E5. I therefore checked the theory by running this PowerShell code:

# Check the date when a service plan belonging to a product like EMS E3 is assigned to an account
$EMSE3 = "efccb6f7-5641-4e0e-bd10-b4976e1bf68e" # Product SKU identifier for Enterprise Mobility and Security E3
$EMSE5 = "b05e124f-c7cc-45a0-a6aa-8cf78c946968" # Product SKU identifier for Enterprise Mobility and Security E5
$TestSP = "41781fb2-bc02-4b7c-bd55-b576c07bb09d" # Azure Active Directory Premium P1
$Report = [System.Collections.Generic.List[Object]]::new()
# Find tenant accounts
Write-Host "Finding Azure AD accounts..."
[Array]$Users = Get-MgUser -Filter "UserType eq 'Member'" -All | Sort DisplayName
ForEach ($User in $Users) {
  ForEach ($SP in $User.AssignedPlans) {
   If (($User.AssignedLicenses.SkuId -contains $EMSE5) -and ($SP.ServicePlanId -eq $TestSP -and $SP.CapabilityStatus -eq "Enabled")) {
        $ReportLine = [PSCustomObject][Ordered]@{  
          User            = $User.DisplayName
          UPN             = $User.UserPrincipalName
          ServicePlan     = $SP.Service
          ServicePlanId   = $SP.ServicePlanId 
          Assigned        = Get-Date($SP.AssignedDateTime) -format g
         }
        $Report.Add($ReportLine)
    } #End if
  } #End ForEach Service plans
} #End ForEach Users

After defining some variables, the code calls the Get-MgUser cmdlet to find the Azure AD accounts in the tenant (I used the script described in this article as the basis; see this article for more information about the Microsoft Graph SDK for PowerShell). Make sure that you connect to the beta endpoint as license information is not available with the V1.0 endpoint (run Select-MgProfile beta after connecting to the Graph).

Next, the code checks the assigned plans and if the desired plan belongs to the right product and is enabled, we report it. Each line in the report is like this:

User          : Kim Akers
UPN           : Kim.Akers@office365itpros.com
ServicePlan   : AADPremiumService
ServicePlanId : 41781fb2-bc02-4b7c-bd55-b576c07bb09d
Assigned      : 11/11/2017 16:52

This is a quick and dirty answer to the problem of discovering when a product license is assigned to user accounts. It might serve to fill in while Microsoft improves matters.

As reported by Vasil Michev, Microsoft recently added a licenseAssignmentState resource to the Graph API. This isn’t yet available for PowerShell, but the date information can be retrieved using the Graph. In this snippet, we find user accounts and examine their assignment state for EMS E5 to discover when the license was assigned. The code assumes that you’ve already used a registered app to authenticate and fetch an access token to interact the Graph APIs. Remember that you might need to use pagination to fetch all the pages of user data available in the tenant. Anyway, here’s my quick and dirty code to prove the point:

# Use the Graph API to check license assignment states
Write-Host "Fetching user information from Azure AD..."
$Uri = "https://graph.microsoft.com/v1.0/users?&`$filter=userType eq 'Member'"
[Array]$Users = (Invoke-RestMethod -Uri $Uri -Headers $Headers -Method Get -ContentType "application/json")
$Users = $Users.Value

Write-Host “Processing users…”
ForEach ($User in $Users) {
    $Uri = "https://graph.microsoft.com/beta/users/" + $User.UserPrincipalName + "?`$select=licenseAssignmentStates"
    [Array]$Assignments = Get-GraphData -Uri $Uri -AccessToken $Token
    ForEach ($License in $Assignments.LicenseAssignmentStates) {
        $LicenseUpdateDate = $Null
        If ($License.SkuId -eq $EMSE5 -and $License.State -eq "Active") {
           If ([string]::IsNullOrWhiteSpace(($License.lastUpdatedDateTime)) -eq $False ) {
              $LicenseUpdateDate = Get-Date($License.lastUpdatedDateTime) -format g }
           Else {
              $LicenseUpdateDate = "Not set" }
           Write-Host ("Last update for EMS for {0} on {1}" -f $User.DisplayName, $LicenseUpdateDate) }
    } # End ForEach License
} # End ForEach User

Last update for EMS for Tony Redmond on 15/07/2021 15:28
Last update for EMS for Andy Ruth (Director) on Not set
Last update for EMS for Kim Akers on 26/10/2021 16:58
Last update for EMS for Jack Hones on Not set
Last update for EMS for Oisin Johnston on 03/10/2020 13:18

The dates retrieved using this method differ to the values you get from service plans because Microsoft is populating these values using the last licensing change made to the account. However, in the future, the dates will be more accurate and usable because they will capture changes, hopefully when PowerShell access is possible.

No Audit Data

In passing, I note that the Office 365 audit log captures a “Change user license” audit record when an administrator updates the licenses for an account. However, the audit record doesn’t include details of what licenses were added, changed, or removed. The Azure AD team could do a better job of capturing audit information about license updates. I’m sure they’ll be happy to hear that.


Keep up with the changing world of the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. Monthly updates mean that our subscribers learn about new development as they happen.

]]>
https://office365itpros.com/2021/11/10/find-when-azure-ad-user-accounts-receive-microsoft-365-licenses/feed/ 3 52291
How to Switch Entra B2B Collaboration (External Identities) to the Monthly Active User Billing Model https://office365itpros.com/2021/11/04/entra-id-guest-user-licensing/?utm_source=rss&utm_medium=rss&utm_campaign=entra-id-guest-user-licensing https://office365itpros.com/2021/11/04/entra-id-guest-user-licensing/#comments Thu, 04 Nov 2021 01:00:00 +0000 https://office365itpros.com/?p=52211

Tenant administrators are all too aware of the growth of guest user accounts in tenant directories over recent years. The success of Teams and the use of guest accounts in sharing SharePoint Online and OneDrive for Business documents are the biggest factors in driving the growth in guest accounts. As we’ll discuss, some premium features of Microsoft 365 Groups require consideration of Entra ID guest user licensing.

Apart from cluttering up the directory, guest accounts don’t do any harm. You can try to identify and remove obsolete accounts using a variety of methods such as checking the Entra ID sign-in logs to discover the last sign in to the account or using the Office 365 audit log and message tracking logs to figure out if guest accounts are active.

However, one thing you should keep an eye on is the requirement to license guest accounts if you use premium Entra ID features like conditional access policies or dynamic Microsoft 365 groups. In the past, the rule was that guest accounts needed premium licenses at a 1:5 ratio to Entra ID premium licenses. In other words, each premium license covers five guest accounts. Guest accounts don’t need licenses for “normal” activity such as accessing a team or opening a shared document. Entra ID access reviews can help control the need for licenses by forcing group owners to validate continued membership of guests in their groups.

External Identities Licensing Change

In September 2020, Microsoft announced a change in licensing for external identities (Azure B2B and B2C collaboration). Instead of requiring customers to buy premium licenses to cover guest accounts, the new monthly active users (MAU) billing model allows up to 50,000 free MAU for premium activities monthly. Licenses are still needed for tenant accounts that use premium features.

The definition on Microsoft’s billing model for Entra ID external identities page explains that MAU is “the count of unique users with authentication activity within a calendar month.” In other words, the MAU threshold covers all authentication activity by 50,000 external identities (like guest accounts) in a month. Any individual identity within that set can authenticate as many times as they like. If a tenant exceeds the 50,000 MAU threshold, Microsoft bills for authentications by subsequent external identities. Pricing varies according to market and whether an authenticated external identity uses Entra ID P1 or P2 features (see MAU pricing). As an example, in the U.S., an engra ID P1 MAU costs $0.00325.

To date, Microsoft hasn’t done much to enforce the changeover to MAU pricing, and it’s very possible that Microsoft’s change in licensing strategy passed tenant administrators by without registering. It certainly made no impact on me. However, the signs are that some new features might require tenants to use MAU billing, which requires customers to link their Entra ID tenant to an Azure subscription. If you’ve already done this, you don’t need to do anything else as Microsoft bills you based on the MAU model. If you haven’t, you’ll need to link your tenant to an existing or new subscription.

Switching Entra ID Guest User Licensing to MAU Billing

On the surface, the process to switch to MAU billing seems straightforward:

  • Create a new Azure subscription or identify an existing subscription to use for MAU billing.
  • Go to the External Directories blade in the Entra admin center and select the Linked subscriptions option. Figure 1 shows the result of successfully linking Entra ID to a Azure subscription.
  • Select your directory (most tenants have just one).
  • Click Link subscription to select the Azure subscription and resource group (within the subscription) to use for MAU billing. Click Apply to link the directory to the subscription.

Linked subscriptions for an Azure AD instance

Azure AD guest user licensing
Figure 1: Linked subscriptions for an Azure AD instance

Registering the Entra ID Resource Provider

In my case, linking proceeded smoothly until Azure rejected my chosen subscription with the error:

The subscription is not registered to use namespace ‘Microsoft.AzureActiveDirectory’. See https://aka.ms/rps-not-found for how to register subscriptions.

The referenced page contains a lot of information about fixing various problems but nothing I could see relating to Entra ID. Some research (aka web searches) revealed that Microsoft.AzureActiveDirectory is the name of the resource provider for Entra ID. As you might imagine, not every resource provider is registered for every Azure subscription, so the solution is to register Entra ID for the subscription.

You can do this in two ways. First, go to the Subscriptions section of the Azure portal and select the subscription you want to use. Now select resource providers and look for Microsoft.AzureActiveDirectory in the set of providers. Select and register the provider. Figure 2 shows that the provider is registered, which is what you want to see.

Resource providers for an Azure subscription.

Entra ID guest users licensing.
Figure 2: Resource providers for an Azure subscription

Those wanting to live on the edge can register the provider using the Azure Cloud Shell. Start a session by clicking the Cloud Shell icon in the menu bar (it’s the icon which looks vaguely like PowerShell). This opens a small pane in the Azure portal into which you can type commands (you have a choice of Bash-like or PowerShell-like environments).

Accessing Cloud Shell from the Azure portal logs into your account automatically. All you need to do is run two commands to select the subscription you want to update and then register the Microsoft.AzureActiveDirectory provider with the subscription:

Az account set –-subscription "Visual Studio Enterprise Subscription"
Az provider register –-namespace Microsoft.AzureActiveDirectory

If you access the Cloud Shell directly (https://shell.azure.com/), you’ll need to sign in first with:

Az login

In either case, after registering the provider, you can link the subscription to Entra ID and use the MAU billing model.

It seems strange that Microsoft hasn’t optimized the Entra admin center to make sure that a selected subscription has access to Entra ID and if not, offer the administrator to register Entra ID with the subscription. There should be no need to force administrators to solve the problem when software can do it automatically.

Extra SMS Charges

Although Microsoft allows for 50,000 free MAU monthly, the MAU pricing page says:

A flat fee of $0.03 is billed for each SMS/Phone-based multi-factor authentication attempt.

Note the wording. The charge applies whether the attempt to send an SMS code is successful or not and covers the telephony charge involved in sending the SMS. The charge does not apply when external identities use the Microsoft Authenticator app for MFA verification, which is another good reason to encourage guest accounts to use the app.

Entra ID Guest User Licensing Works for Microsoft and Tenants

I’m sure Microsoft likes the new MAU pricing model for external identities because it gives them more control and visibility over the volume of guest account activity with premium Entra ID features. The old 1:5 licensing model was unenforceable and probably ignored in many tenants. On the upside, because MAU pricing is linked to Azure subscriptions, tenants gain more insight into the activity level for guest accounts too. I’ll be keeping an eye on costs as time goes by.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what’s happening.

]]>
https://office365itpros.com/2021/11/04/entra-id-guest-user-licensing/feed/ 3 52211
How to Use /Any Filters in Microsoft Graph API Queries with PowerShell https://office365itpros.com/2021/09/17/graph-lambda-operators-powershell/?utm_source=rss&utm_medium=rss&utm_campaign=graph-lambda-operators-powershell https://office365itpros.com/2021/09/17/graph-lambda-operators-powershell/#comments Fri, 17 Sep 2021 01:00:00 +0000 https://office365itpros.com/?p=51564

Why Lambda Operators are Sometimes Needed

A reader asked about the meaning of x:x in a Graph API query included in the article about upgrading Office 365 PowerShell scripts to use the Graph. You see this construct (a Lambda operator) in queries like those necessary to find the set of accounts assigned a certain license. For example, to search for accounts assigned Office 365 E3 (its SKU or product identifier is always 6fd2c87f-b296-42f0-b197-1e91e994b900):

https://graph.microsoft.com/beta/users?$filter=assignedLicenses/any(s:s/skuId eq 6fd2c87f-b296-42f0-b197-1e91e994b900)

Find the set of Microsoft 365 Groups in the tenant:

https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(a:a eq 'unified')

Find the set of Teams in the tenant:

https://graph.microsoft.com/beta/groups?$filter=resourceProvisioningOptions/Any(x:x eq 'Team')

As you might expect, because the cmdlets in the Microsoft Graph SDK for PowerShell essentially are wrappers around Graph API calls, these cmdlets use the same kind of filters. For example, here’s how to find accounts with the Office 365 licenses using the Get-MgUser cmdlet:

[array]$Users = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq 6fd2c87f-b296-42f0-b197-1e91e994b900)" -all

Lambda Operators and Advanced Graph Queries

All these queries use lambda operators to filter objects using values applied to multi-valued properties. For example, the query to find users based on an assigned license depends on the data held in the assignedLicenses property of Azure AD accounts, while discovering the set of Teams in a tenant relies on checking the resourceProvisioningOptions property for Microsoft 365 groups. These properties hold multiple values or multiple sets of values rather than simple strings or numbers. Because this is a query against a multivalue property for an Entra ID directory object, it’s called an advanced query.

Accessing license information is a good example to discuss because Microsoft is deprecating the Azure AD cmdlets for license management at the end of 2022, forcing tenants to upgrade scripts which include these cmdlets to replace them with cmdlets from the Microsoft Graph SDK for PowerShell or Graph API calls. This Practical365.com article explains an example of upgrading a script to use the SDK cmdlets.

If we look at the value of assignedLicenses property for an account, we might see something like this, showing that the account holds three licenses, one of which has a disabled service plan.

disabledPlans                          skuId
-------------                          -----
{33c4f319-9bdd-48d6-9c4d-410b750a4a5a} 6fd2c87f-b296-42f0-b197-1e91e994b900
{}                                     1f2f344a-700d-42c9-9427-5cea1d5d7ba6
{}                                     8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b

It’s obvious that assignedLicenses is a more complex property than a single-value property like an account’s display name, which can be retrieved in several ways. For instance, here’s the query with a filter to find users whose display name starts with Tony.

https://graph.microsoft.com/v1.0/users?$filter=startswith(displayName,'Tony')

As we’re discussing PowerShell here, remember that you must escape the dollar character in filters. Taking the example above, here’s how it is passed in PowerShell:

$Uri = "https://graph.microsoft.com/v1.0/users?`$filter=startswith(displayName,'Tony')"
[array]$Users = Invoke-WebRequest -Method GET -Uri -ContentType "application/json" -Headers $Headers | ConvertFrom-Json

The data returned by the query is in the $Users array and can be processed like other PowerShell objects.

Using Any and All

Getting back to the lambda operators, while OData defines two (any and all), it seems like the all operator, which “applies a Boolean expression to each member of a collection and returns true if the expression is true for all members of the collection (otherwise it returns false)” is not used. At least, Microsoft’s documentation says it “is not supported by any property.”

As we’ve seen from the examples cited above, the any operator is used often. This operator “iteratively applies a Boolean expression to each member of a collection and returns true if the expression is true for any member of the collection, otherwise it returns false.”

If we look at the filter used to find accounts assigned a specific license:

filter=assignedLicenses/any(s:s/skuId eq 6fd2c87f-b296-42f0-b197-1e91e994b900)

My interpretation of the component parts (based on Microsoft documentation) of the filter is:

  • assignedLicenses is the parameter, or the property the filter is applied to. The property can contain a collection of values or a collection of entities. In this case, the assignedLicenses property for an account contains a collection of one or more license entities. Each license is composed of the SkuId and any disabled plans unavailable to the license holders.
  • s:sis a range variable that holds the current element of the collection during iteration.” The interesting thing is that you can give any name you like to the range variable. In this case, it could be license:license or even rubbish:debris. It’s just a name for a variable.
  • SkuId is the subparam, or value within the property being checked. When there’s only one value in a collection (as when you check for team-enabled groups), you don’t need to specify a subparam. In the case of assignedLicenses, it is needed because we want to match against the SkuId within the collection of entities in the assignedLicenses property.
  • 6fd2c87f-b296-42f0-b197-1e91e994b900 is the value to match against items.

I’m Not a Developer

All of this is second nature to professional developers but not so much to tenant administrators who want to develop some PowerShell scripts to automate operations. This then poses the question about how to discover when lambda qualifiers are needed. I don’t have a great answer except to look for examples in:

  • Microsoft’s Graph API documentation.
  • Code posted online as others describe their experiences working with the Graph APIs.

And when you find something which might seem like it could work, remember that the Graph Explorer is a great way to test queries against live data in your organization. Figure 1 shows the results of a query for license information.

Running a query with a lambda qualifier in the Graph Explorer
Figure 1: Running a query with a lambda qualifier in the Graph Explorer

Exploring the Mysteries of the Graph

One complaint often extended about Microsoft’s documentation for the Graph APIs is that it pays little attention to suitable PowerShell examples. The Graph SDK developers say that they understand this situation must change and they plan to improve their documentation for PowerShell over the next year. Although understandable that languages like Java and C# have been priorities up to now, Microsoft can’t expect the PowerShell community to embrace the Graph and learn its mysteries (like lambda qualifiers) without help. Let’s hope that the Graph SDK developers live up to their promise!


Learn how to exploit the Office 365 data available to tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2021/09/17/graph-lambda-operators-powershell/feed/ 4 51564
Inconsistencies Using Reserved Aliases with Groups in Microsoft 365 https://office365itpros.com/2021/08/30/reserved-aliases/?utm_source=rss&utm_medium=rss&utm_campaign=reserved-aliases https://office365itpros.com/2021/08/30/reserved-aliases/#comments Mon, 30 Aug 2021 01:00:00 +0000 https://office365itpros.com/?p=51279

Current Implementation Blocks Some but Not All Use of Reserved Aliases with Groups

SMTP email addresses are composed of an alias (otherwise called a mail nickname) and a domain. The alias is assigned to a mailbox or other mail-enabled object to allow it to receive email. User clients tend to generate aliases automatically when creating new groups. Administrative interfaces like the Microsoft 365 admin center or PowerShell allow more control over the alias given to new mail-enabled objects. And then we come to the question of reserved email aliases.

A reserved alias is a sensitive name that’s usually kept for specific purposes. Azure AD defines a set of reserved or highly-privileged aliases which it doesn’t allow for (some) mail-enabled groups. The purposes that these aliases often serve including being the contact address for an email system or web site. Obviously, you don’t want a common-or-garden group to hijack an email address which people might assume is used for a different purpose.

It is not unusual for email systems to ring-fence reserved aliases. Google Workspace does the same, explaining that “The following words can’t be used in the email addresses of groups that you create in groups.google.com:

  • abuse
  • admin
  • administrator
  • hostmaster
  • majordomo
  • postmaster
  • root
  • ssl-admin
  • webmaster

Azure AD adds “secure” and “security” to the list.

Testing the Creation of Groups with Reserved Aliases

The Azure AD documentation says that an Azure AD global administrator can create groups with reserved aliases. This isn’t altogether true as it depends on the administrative interface used, which points to an inconsistency of implementation across Microsoft 365. Table 1 shows the results of some tests I did to see if I could create groups with reserved aliases.

Admin endpointGroup TypeCreation with reserved alias possible?
Microsoft 365 admin centerMail-enabled security groupNo
 Security groupYes
 Distribution listNo
 Microsoft 365 groupYes
Exchange admin centerDistribution listNo
 Mail-enabled security groupNo
 Dynamic distribution listYes
Azure AD admin centerMicrosoft 365 groupYes
PowerShell
New-AzureADGroup
Security groupYes
New-UnifiedGroupMicrosoft 365 groupYes
New-DistributionGroupDistribution listNo
Table 1: Tracking the ability to create groups with reserved aliases

I am a global tenant administrator, so finding five administrative endpoints where it’s possible to create a mail-enabled group with a reserved alias confirms that the documentation’s assertion that global administrators can create these groups is correct. A more exhaustive test might find more, especially in PowerShell cmdlets.

However, the problem is the five places where a global administrator couldn’t create groups with reserved aliases. Three of these are distribution lists, the others are mail-enabled security groups. That’s where the inconsistency exists. Microsoft’s documentation mentions “groups,” a term which covers a spectrum of different types of group objects and doesn’t focus on any specific kind of group. This raises the question of why are distribution lists and mail-enabled security groups treated differently?

Testing is simple. Select an administrative interface and see if you can create a group with a reserved alias (Figure 1).

Creating a new group with a reserved alias in the Microsoft 365 admin center

Reserved email alias
Figure 1: Creating a new group with a reserved alias in the Microsoft 365 admin center

When the Microsoft 365 admin center or Exchange Online admin center detect a problem creating a group with a reserved alias, it flags the error. The error text is by no means perfect. It starts off by pointing to a synchronization issue between Azure AD and Exchange Online before saying that the value for the alias is incorrect as it contains a blocked word.

Error when creating a new group with a reserved alias
Figure 2: Error when creating a new group with a reserved alias

Pointing to synchronization between Azure AD and Exchange Online is misleading. The two workloads use a dual-write process to make sure that the creation or update of a mail-enabled object occurs in both directories or not at all. Microsoft introduced the double-write some years ago to avoid synchronization issues between Azure AD (the directory of record for Microsoft 365) and Exchange Online (which has its own directory for mail-enabled objects). Reading the text, I assume that Exchange Online rejected the attempt to create the new group because of the reserved alias and Azure AD then declined the write.

PowerShell Inconsistencies Too

Other administrative interfaces give different errors. For instance, here we create a new security group with Azure AD PowerShell. Azure AD accepts the reserved alias because this group is not mail-enabled. If we try to mail-enable the group, we get an error.

New-AzureADGroup -Description "Abuse Group" -DisplayName "Abuse Group" -MailNickName Abuse -MailEnabled $False -SecurityEnabled $True

ObjectId                             DisplayName Description
--------                             ----------- -----------
d347eec5-62f1-4436-af41-e53fa18090be Abuse Group Abuse Group

Set-AzureADGroup -ObjectId d347eec5-62f1-4436-af41-e53fa18090be -MailEnabled $True
Set-AzureADGroup : Error occurred while executing SetGroup
Code: Request_BadRequest
Message: The service does not currently support writes of mail-enabled groups. Please ensure that the mail-enablement
property is unset and the security-enablement property is set.     

The Exchange Online cmdlets to work with Microsoft 365 groups are happy to accept reserved aliases:

New-UnifiedGroup -DisplayName "Majordomo Group" -Alias Majordomo -Members Tony.Redmond@office365itpros.com -Owner Tony.Redmond@office365itpros.com
Set-UnifiedGroup -Identity Majordomo -PrimarySmtpAddress Majordomo@office365itpros.com
Get-UnifiedGroup -Identity Majordomo | fl EmailAddresses

EmailAddresses : {SPO:SPO_720c5dd5-e387-4c93-836d-899466759f64@SPO_b662313f-14fc-43a2-9a7a-d2e27f4f3478, smtp:majordomo@office365itpros.onmicrosoft.com, SMTP:majordomo@office365itpros.com}

But the Exchange Online cmdlets for distribution lists are not so content to assign reserved aliases:

New-DistributionGroup -DisplayName "Secure" -Alias "Secure" -PrimarySmtpAddress Secure@Office365itpros.com -Name "Secure Group"
An Azure Active Directory call was made to keep object in sync between Azure Active Directory and Exchange Online.
However, it failed. Detailed error message:
        The value specified for property Alias is incorrect. Reason: ContainsBlockedWord RequestId :
514d14b4-cc5f-4581-b97a-9930dff98542
The issue may be transient and please retry a couple of minutes later. If issue persists, please see exception members
for more information.
    + CategoryInfo          : NotSpecified: (:) [New-DistributionGroup], UnableToWriteToAadException
    + FullyQualifiedErrorId : [Server=DB9PR04MB8445,RequestId=9f8a149c-dc90-4196-9274-7625148d6280,TimeStamp=25/08/202
   1 12:05:53] [FailureCategory=Cmdlet-UnableToWriteToAadException] AEC31773,Microsoft.Exchange.Management.RecipientTasks.NewDistributionGroup
    + PSComputerName        : outlook.office365.com

Moving along, we can assign a reserved alias to a dynamic distribution list.

Get-DynamicDistributionGroup "Secure DDL" | fl primarysmtpaddress

PrimarySmtpAddress : Secure@office365itpros.com

The Need for Consistency

One way of looking at this is to say that so many ways exist to create new mail-enabled groups within Microsoft 365 that it’s inevitable that some inconsistencies will creep in. However, the current situation shows all the signs of poor attention to detail. Global administrators usually know what they’re doing when they create groups. Users can create distribution lists and Microsoft 365 groups/teams (if allowed by policy), so user-driven creation is where an absolute block should exist on reserved aliases.

It would be nice if Microsoft either lived up to its assertion that global administrators aren’t subject to the block on using reserved aliases or documented exactly where they can and cannot create groups with reserved aliases. Knowing what to expect and where to do it is so much better than probing holes in documentation.


Learn how to exploit the Office 365 data available to tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2021/08/30/reserved-aliases/feed/ 1 51279
How to Remove a Single Service Plan from Multiple User Accounts with PowerShell https://office365itpros.com/2021/08/18/remove-service-plan-powershell/?utm_source=rss&utm_medium=rss&utm_campaign=remove-service-plan-powershell https://office365itpros.com/2021/08/18/remove-service-plan-powershell/#comments Wed, 18 Aug 2021 01:00:00 +0000 https://office365itpros.com/?p=51156

Remove Service Plan PowerShell to Manage User Functionality

Note: This post is now obsolete. Please see this article for an updated approach to the problem.

Service plans are non-saleable elements of a Microsoft licensable product (SKU or stock keeping unit). SKUs are what people often think of when they discuss licenses. Individual Microsoft 365 accounts can have multiple SKUs, such as TOPIC_EXPERIENCES, ENTERPRISEPACK, and EMSPREMIUM. The product names for these SKUs are Viva Topics, Office 365 E3, and Enterprise Mobility and Security E5. Product names appear in places like the Billing section of the Microsoft 365 admin center (Figure 1).

Product names in the Microsoft 365 admin center

Remove service plans PowerShell
Figure 1: Product Names in the Microsoft 365 admin center

At a more granular level, a “bundled” SKU like Office 365 E3 includes multiple service plans, each of which enable access to some functionality like an app. This page lays details the connections between SKUS and service plans.

At the time of writing, Office 365 E3 covers 28 service plans and Office 365 E5 has 53. Office 365 E5 includes service plans to license capabilities like advanced compliance features, customer lockbox, advanced auditing, content explorer, server-based auto-labeling for sensitivity labels and retention labels, records management, and information barriers.

Microsoft introduces new service plans to enhance its ability to license new features to different user communities or to provide control over user access to a new feature. Teams is a good example. The Teams service plan (TEAMS1) is in many Office 365 and Microsoft 365 SKUs. In April, Microsoft announced they would add the Teams Pro service plan to some SKUs and will use the Teams Pro service plan to allow accounts licensed with those SKUs to access new features. To date, Microsoft has not added the Teams Pro service plan to any SKU in my tenant nor have they described what features the new service plan will cover.

Reviewing Available Service Plans

In some cases, tenant administrators might not want users to be able to access a licensed app or capability. Perhaps the feature is obsolete, or the organization has different software to do the same thing, or maybe a delay is necessary to enable preparation of training, documentation, and support. Some years ago, Microsoft made a big thing about Kaizala and its impending integration into Teams. Kaizala is now an obsolete feature that’s still available in Office 365 E3 and E5. Sway is in the same category. Microsoft Bookings is an optional feature which isn’t often used by enterprise users, but it’s also part of Office 365 E3 and E5. In short, when you review the set of service plans bundled into Office 365 and Microsoft 365 SKUs, you might be surprised at the amount of unwanted debris in the mix.

Removing Individual Service Plans

Let’s say that we want to remove individual service plans from SKUs assigned to users. This post describes how to report the accounts assigned individual service plans (licenses) and explains how Azure AD stores the service plan information in user accounts. We want to go further by removing access to selected service plans, and as it turns out, we must use cmdlets from the older Microsoft Online Services module to get the job done. It’s possible to use the Set-AzureADUserLicense cmdlet to remove a service plan from an account. Laziness and the availability of some existing code to do the job stopped me using this cmdlet.

In any case, I wrote a script to demonstrate the principle of the steps to remove an individual service plan from multiple Microsoft 365 accounts. Three versions are available.

Given that Microsoft deprecated the licensing management cmdlets in the MSOL and Azure AD modules in 2023, it makes sense to focus on the version based on the Microsoft Graph PowerShell SDK.

The major steps to remove a service plan from Azure AD licenses with PowerShell are:

  • Determine the set of SKUs (products) available in the tenant.
  • Select the SKU to remove a service plan from. A tenant might use many SKUs, so we read the information with Get-AzureADSubscribedSKU (or Get-MgSubscribedSku) and ask the administrator to choose a SKU.
  • Select the service plan from the chosen SKU to remove. This is a matter of reading the service plans from the SKU and asking the administrator to choose one.
  • Select the target accounts. I use Get-ExoMailbox to fetch a set of user mailboxes because this cmdlet supports a wide range of server-side filters (for instance, everyone in a country or department). The important thing is that you fetch the Azure AD object identifiers for the target accounts. The Microsoft Graph PowerShell SDK version doesn’t use Exchange Online because it reads the licensed account information direct from Azure AD.
  • Access each account (using its object identifier) and remove the service plan. The MSOL version does this by running the Set-MsolUserLicense cmdlet. The Azure AD version uses the Set-AzureADUserLicense cmdlet, while the Graph SDK uses Set-MgUserLicense.
  • Report the service plans removed from SKUs assigned to the target mailboxes.

Figure 2 shows the MSOL version of the script in action. You can see the selection of the service domain, SKU, and service plan and processing of user accounts. In this case, the selected options remove the Sway service plan from the ENTERPRISEPACK (Office 365 E3) SKU.

Selecting the SWAY service plan to remove

Remove Azure AD license PowerShell
Figure 2: Running the script to remove the SWAY service plan from Office 365 E3 licenses assigned to Microsoft 365 users

The report output is a CSV file. Figure 3 shows the information captured in the report as viewed through the Out-GridView cmdlet.

Reporting the removal of a service plan

How to remove an Azure AD license with PowerShell
Figure 3: Reporting the removal of a service plan

PowerShell Scores Again

I’m sure others will have different ways to solve the problem of removing service plans from SKUs, which is just fine. What’s obvious here (once again) is that PowerShell is a very flexible tool for automating administrative operations. Which is why I am so surprised when tenant administrators admit that they have never taken the time to become acquainted with the basics of PowerShell scripting. It’s not difficult; there are tons of available examples to learn from; and it gets work done. All good stuff!


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2021/08/18/remove-service-plan-powershell/feed/ 10 51156
SharePoint Online Embraces Azure B2B Collaboration for External Sharing https://office365itpros.com/2021/08/17/sharepoint-online-embraces-azure-b2b-collaboration-external-sharing/?utm_source=rss&utm_medium=rss&utm_campaign=sharepoint-online-embraces-azure-b2b-collaboration-external-sharing https://office365itpros.com/2021/08/17/sharepoint-online-embraces-azure-b2b-collaboration-external-sharing/#comments Tue, 17 Aug 2021 01:00:00 +0000 https://office365itpros.com/?p=51117

Removing Friction from Sharing

External sharing of SharePoint Online and OneDrive for Business elements like documents, list items, and folders uses a technology called ad-hoc external sharing. When users share items with external recipients, SharePoint Online and OneDrive for Business use a one-time passcode to allow that person to verify their identity. A one-time passcode (OTP) is a way to authenticate the identity of people outside your Microsoft 365 tenant when Azure AD cannot verify their accounts using another method.

The ad-hoc sharing mechanism works but requires several steps before the user can open the shared item.

  • User receives the email telling them that someone has shared an item with them.
  • User attempts to access the item. SharePoint Online detects that it must verify their identity, so sends an 8-digit OTP to their email address.
  • The user receives the email (or finds it in their Junk Email folder) and enters the code (or cuts and pastes the code) into the form (Figure 1). Passcodes are valid for 30 minutes. The Keep me signed in checkbox controls the saving of the authentication cookie to disk to allow the user to reuse it for authentication until the cookie expires.
  • SharePoint Online verifies the code and if correct, allows access.

Using a one-time passcode to validate access to a shared file
Figure 1: Using a one-time passcode to validate access to a shared file

Integrating SharePoint External Sharing with Azure AD B2B

To improve external sharing, in October 2021, Microsoft plans to turn on Email one-time passcode authentication for Azure AD by default for all tenants. Like the current ad-hoc sharing, the new mechanism features one-time passcodes. The big difference is that successful authentication results in the automatic creation of Azure AD guest accounts for external users.

Microsoft is making the change because it will enable new functionality for external recipients. Among the advantages cited are:

  • Because they will have Azure AD guest accounts, external recipients who redeem one-time passcodes won’t need to create a Microsoft (MSA) account.
  • Administrators can manage details of guest accounts, such as assigning them user-friendly display names or photos.
  • Other Microsoft 365 features, such as team membership or sharing of other SharePoint Online and OneDrive for Business resources, can take advantage of the guest accounts.
  • Guest accounts are subject to conditional access policies.
  • Tenants that configure Google Cloud federation with Azure AD can share resources with federated accounts.
  • The Azure AD B2B Collaboration policy controls external sharing. In other words, you can whitelist or blacklist domains that you want to limit sharing with or stop sharing with (a tenant can choose to deploy either a whitelist or blacklist, but not both).

Configuring Email OTP Authentication for Azure AD

While they can wait until Microsoft enables Email OTP authentication for Azure AD in October (or opt to disable the capability), tenants can choose to use email OTP authentication for Azure AD today. To enable the feature, go to the identity providers section and configure the email one-time passcode provider as shown in Figure 2.

Configuring the Azure AD Email one-time passcode identity provider
Figure 2: Configuring the Azure AD Email one-time passcode identity provider

As you can see, this is where you can disable the feature, if that’s what you want to do.

Some configuration is necessary for SharePoint Online to integrate with Azure AD B2B and use email OTP authentication (or as Microsoft says in its documentation, Azure B2B Invitation Manager). Do this with the SharePoint Online management module by connecting and running the Set-SPOTenant cmdlet to update the necessary settings:

Set-SPOTenant -EnableAzureADB2BIntegration $True
Set-SPOTenant -SyncAadB2BManagementPolicy $True

Bizarrely, while you can use the Get-SPOTenant cmdlet to retrieve the value of the EnableAzureADB2BIntegration setting, it doesn’t report a value for SyncAadB2BManagementPolicy.

Using Email OTP Authentication for Azure AD

With Email OTP authentication for Azure AD enabled and connected to SharePoint Online, the following happens for external sharing.

The user creates a sharing link as usual (existing sharing links continue to work and there’s no need to recreate links).

  • Azure AD checks the directory and creates a guest account if an account doesn’t already exist for the external recipient.
  • The external recipient receives the email notification of sharing and clicks the sharing link.
  • Azure AD enters a validation process. Users with Azure AD or MSA accounts enter their email address and, if this is valid for the sharing link, the Azure AD Invitations service invokes the consent process to allow it to sign in the new guest account (Figure 3). Users without Azure AD or MSA accounts sign in using the one-time passcode authentication procedure to validate their identity.
  • If the external recipient grants consent, Azure AD signs them in and allows access to the shared resource.
Completing the validation process for the new guest account
Figure 3: Completing the validation process for the new guest account

The external recipient now has a guest account in the tenant. They can use this account to access other resources shared with them. And if the authentication token granted through a sign-in is still valid, they won’t have to sign in again to open other shared resources. When the guest account accesses tenant resources, Azure AD captures audit records (Figure 4).

An Azure AD audit record for a guest account sign-in to access a shared file
Figure 4: An Azure AD audit record for a guest account sign-in to access a shared file

The tenant can manage the guest account like any other account, including imposing conditional access policies to restrict access where necessary, like confidential sites marked with an authentication context with a sensitivity label.

Guest Accounts Need Management

Using guest accounts to manage external access to SharePoint Online and OneDrive for Business resources is a sensible move. It’s a lower friction mechanism for external people that’s easier for tenants to operate. That being said, guest accounts do need to be managed as it is all too easy to allow obsolete or unused accounts accumulate in Azure AD. Microsoft doesn’t provide any tools to clean up old guest accounts, but you can do the job with PowerShell.


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2021/08/17/sharepoint-online-embraces-azure-b2b-collaboration-external-sharing/feed/ 8 51117
How to Control the Creation of Microsoft 365 Groups (and Teams) in a Tenant https://office365itpros.com/2021/08/11/creation-microsoft-365-groups/?utm_source=rss&utm_medium=rss&utm_campaign=creation-microsoft-365-groups https://office365itpros.com/2021/08/11/creation-microsoft-365-groups/#comments Wed, 11 Aug 2021 02:03:00 +0000 https://office365itpros.com/?p=51014

Azure AD – then Microsoft 365 – And Maybe OWA

My recent note about the changes Microsoft made to the Azure AD admin center to control the creation of groups created some additional questions about the overall governance of group creation, specifically for Microsoft 365 Groups. It’s a topic that Microsoft has been accused of over-complicating in the past, but it seems reasonably straightforward now.

The Central Role of Azure AD

Azure AD exerts governance over Microsoft 365 Groups at tenant level. This is easy to understand because Microsoft 365 Groups are a form of Azure AD groups. Every Microsoft 365 group is an Azure AD group, and the group membership and ownership are in Azure AD. Because Microsoft 365 Groups are mail-enabled objects, Exchange Online stores some additional properties for the groups (like proxy addresses, membership counts, and SharePoint Online URLs). However, Azure AD is the directory of record and manages the foundational elements of a group.

In late 2019, Microsoft introduced a dual write mechanism to ensure that any changes made by clients to a Microsoft 365 group must update both the Exchange Online Directory and Azure AD to succeed. This change avoids the synchronization glitches which sometimes interfered with object consistency across the two directories.

Configuring Azure AD for Group Creation

Because Azure AD “owns” groups at the tenant level, it therefore follows that the Azure AD control for group creation (Figure 1) must be switched on before anyone can create Microsoft 365 Groups through any app or administrative interface.

Turning on Microsoft 365 Groups in the Azure AD admin center
Figure 1: Turning on Groups in the Azure AD admin center

The Azure AD control lets users create Microsoft 365 Groups using the Azure portal, API, or PowerShell. By API, it means the Microsoft Graph Groups API, which is how the Microsoft 365 admin center, Teams admin center, and new Exchange admin center create groups. It also covers creation in group-enabled apps like Teams, Planner, and Outlook. PowerShell covers creation using cmdlets like New-UnifiedGroup and New-Team.

Controlling Group Creation by Apps

The next level down is to control group creation by apps. Microsoft 365 uses an Azure AD directory setting policy for this purpose. If the policy doesn’t exist, apps allow anyone to create new Microsoft 365 Groups. If the policy exists, apps use the defined policy settings.

Be aware that using the Azure AD policy to control group creation is an Azure AD premium feature. Administrators and the accounts who are members of the group used to control group creation need an Azure AD Premium P1 license (included in several Microsoft 365 plans and the Enterprise Mobility and Security suite). In the education sector, Azure AD Basic EDU licenses are sufficient. It’s also important to realize that members of the nominated group receive the right to create new groups. It’s not enough to be the owner of the group: if you want to be able to create new groups, you’ve got to be a member.

As discussed in the previous article, some of the settings in the Azure AD policy are accessible through the Azure AD admin center. The settings controlling group creation are not, so PowerShell is needed. The necessary cmdlets are in the Azure AD Preview module. A bunch of PowerShell examples are available to help people understand how to update the settings for group creation, most of which seem to be based on Microsoft’s version. I have my own version of a script to update the group control settings (downloadable from GitHub), which is parameter driven and has more error checking and validation. You won’t run the script very often, but it’s nice to have a version that does things like report back on what it’s done.

The PowerShell commands used to configure group control are simple and relatively straightforward. The basic approach is:

  • Use the Get-AzureADDirectorySetting cmdlet to check whether the tenant has customized the Azure AD policy for groups. If no, create a new policy using the New-AzureADDirectorySetting cmdlet.
  • Fetch the existing settings using the Get-AzureADDirectorySetting cmdlet and update the two settings in the policy used to control group creation.
    • EnableGroupCreation is $True if anyone can create new Microsoft 365 Groups or $False if creation is restricted.
    • GroupCreationAllowedGroupId contains the Azure AD object identifier (GUID) for a group (security group or Microsoft 365) holding the set of users allowed to create new Microsoft 365 Groups. If this property is not set, then no one except administrators can create new Microsoft groups.
  • Update the Azure AD policy for Groups using the Set-AzureADDirectorySetting cmdlet.

Example commands to enable group creation control are shown below. The variables used to hold the group object identifier and the True/False setting for EnableGroupCreation are set beforehand.

$PolicySettingsId = (Get-AzureADDirectorySetting | ? {$_.DisplayName -eq "Group.Unified"}).Id
If (!$PolicySettingsId) { # No policy settings found for the tenant, so create it and extract the identifier
  $PolicyTemplate = Get-AzureADDirectorySettingTemplate | ? {$_.DisplayName -eq "Group.Unified"}
  $PolicySettings = $PolicyTemplate.CreateDirectorySetting()
  New-AzureADDirectorySetting -DirectorySetting $PolicySettings
  $PolicySettingsId = (Get-AzureADDirectorySetting | ? {$_.DisplayName -eq "Group.Unified"}).Id
} # End If

$PolicySettings = Get-AzureADDirectorySetting -Id $PolicySettingsId
$PolicySettings["EnableGroupCreation"] = $OnOffSwitch
$PolicySettings["GroupCreationAllowedGroupId"] = $GroupId
Set-AzureADDirectorySetting -Id $PolicySettingsId -DirectorySetting $PolicySettings

Once you’ve updated the Azure AD policy for Groups, it takes a little while for apps (like Teams and Planner) which support the policy to pick up the new settings. It’s worth mentioning that apps which don’t include code to check the Azure AD policy won’t respect the settings.

OWA Mailbox Policy

When Microsoft launched Office 365 Groups (now Microsoft 365 Groups) in November 2014, OWA was the initial client. At the time, it made sense to have a setting in the OWA mailbox policy to control who could create new groups. Today, the separate OWA setting is an anachronism that should be replaced by the Azure AD policy.

In any case, the GroupCreationEnabled setting controls whether Outlook users can create new Microsoft 365 groups. Anyone assigned an OWA mailbox policy with GroupCreationEnabled set to True can go ahead – that is, if they’re also allowed to do so by the Azure AD policy.

To help understand the situation in a tenant, this code reports the set of OWA mailbox policies which allow group creation, and the set of mailboxes assigned those policies:

[array]$OWAPolicies = Get-OWAMailboxPolicy | ? {$_.GroupCreationEnabled -eq $True} | Select -ExpandProperty Identity
Write-Host ""
Write-Host "OWA Mailbox policies allowing group creation:"
Write-Host ""
$OWAPolicies
[array]$Mailboxes = Get-CasMailbox | ? {$_.OWAMailboxPolicy -in $OWAPolicies } | Select DisplayName, OWAMailboxPolicy
Write-Host ""
Write-Host "The OWA Mailbox policy assigned to these mailboxes allows them to create Microsoft 365 Groups:"
$Mailboxes

Changing the assigned OWA mailbox policy for an account can take several hours to take effect. You’ll know when the change is effective when OWA no longer offers the option to create a new group.

Managing Group Creation

Managing the creation of Microsoft 365 Groups isn’t difficult. Make sure that Azure AD allows their creation and then decide if everyone or a restricted set can create new groups. Adjust the OWA mailbox policy as required. The need for Azure AD Premium P1 licenses to use the Azure AD policy for groups to control creation is a barrier for some, but probably not in the large enterprise deployments which benefit most from the capability. And if you’re feeling brave, you can create your own approval workflow using Power Apps to allow users to request a new group/team (here’s a useful article to start with).


Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

]]>
https://office365itpros.com/2021/08/11/creation-microsoft-365-groups/feed/ 3 51014
Updates to Group Creation Settings in Azure AD Admin Center https://office365itpros.com/2021/08/09/updates-group-creation-settings-azure-ad-admin-center/?utm_source=rss&utm_medium=rss&utm_campaign=updates-group-creation-settings-azure-ad-admin-center https://office365itpros.com/2021/08/09/updates-group-creation-settings-azure-ad-admin-center/#comments Mon, 09 Aug 2021 00:23:00 +0000 https://office365itpros.com/?p=50983

Changes to Close Off Creation Gaps in Administrative Interfaces

Message center notification MC275349 (August 3) informs tenant administrators of the need to check the group creation settings in the Azure AD admin center. Previously, these settings governed the ability of users to create new security groups and Microsoft 365 groups through the Azure AD admin center. However, the setting did not govern other administrative interfaces such as PowerShell or the Microsoft Graph Groups API. The new settings (Figure 1) cover all administrative interfaces and are now in place.

 The Groups creation settings in the Azure AD admin center
Figure 1: The Groups creation settings in the Azure AD admin center

Microsoft advises checking your tenant settings to make sure that the change has not affected the way your organization manages group creation. I haven’t seen any issue in any tenant I use, but it’s good to be sure.

Groups-Specific Controls

Azure AD settings apply to administrative interfaces. Other controls exist at an application level. The best example of this is Microsoft 365 Groups, which use an Azure AD directory policy to store settings used to control different aspects of groups. The default value for the EnableGroupCreation setting is True, meaning that any user can create a new Microsoft 365 group. If False, the GroupCreationAllowedGroupId setting comes into play. This defines the GUID of a group whose members are allowed to create new groups.

Controlling group creation in this way requires Azure AD P1 Premium licenses. Many large organizations have Microsoft 365 plans which include these licenses so the requirement not usually an issue.

What’s a little more problematic for some is the lack of a GUI to control most of the policy settings (the naming policy and blocked words settings are available in the Azure AD admin center). Six years or thereabouts since the introduction of the directory policy for Teams, the lack of a complete GUI means that administrators must use PowerShell to access and update the other policy settings, including group creation.

For instance, to find out the set of users allowed to create groups and the name of the group defined in the policy, we can use this code:

$Values = Get-AzureADDirectorySetting | ?{$_.DisplayName -eq "Group.Unified"}
$GroupId = $Values.Values |?{$_.Name -eq "GroupCreationAllowedGroupId" } | Select -ExpandProperty Value
Write-Host ("The name of the group defined by policy to control group creation is {0} and its object identifier is {1}" -f (Get-AzureADGroup -ObjectId $GroupId).DisplayName, $GroupId)
Get-AzureADGroupMember -ObjectId $GroupId

The name of the group defined by policy to control group creation is GroupCreationControl and its object identifier is 12cb915b-2365-4bed-baf6-6257b3543273

ObjectId                             DisplayName                 UserPrincipalName                     UserType
--------                             -----------                 -----------------                     --------
bff4cd58-1bb8-4898-94de-795f656b4a18 Tony Redmond                Tony.Redmond@office365itpros.com      Member
edc6b121-44b8-4261-9ca7-3603a16caa3e Andy Ruth (Director)        Andy.Ruth@office365itpros.com         Member
43d08764-07d4-418c-8203-a737a8fac7b3 Global Tenant Administrator GblAdmin@office365itpros.com          Member

To modify the group used to control group creation, we must update the directory policy. For example, this code retrieves values for the group we want to use and the current settings and uses the values with the Set-AzureADDirectorySetting cmdlet to update the directory policy.

$ObjectId = (Get-AzureADGroup -SearchString "Group Creation Allowed").ObjectId
$Settings = Get-AzureADDirectorySetting | ? {$_.DisplayName -eq "Group.Unified"}
$Settings[“GroupCreationAllowedGroupId”] = $ObjectId
Set-AzureADDirectorySetting -Id $Settings.Id -DirectorySetting $Settings

Outlook Creation

The GroupCreationEnabled setting in the OWA mailbox policy assigned to mailboxes was the original control mechanism for group creation (OWA was the first client to support Office 365 Groups, as they were named in 2014). This setting persists today and must be True to allow users to create new groups with an Outlook client.

This article contains a more comprehensive treatment of the steps to control the creation of Microsoft 365 Groups.

Not Much Impact?

I suspect that the changes being made won’t affect many of the tenants who control group creation. Tenants that allow users to create groups and teams as they wish probably won’t be affected either, but they have other issues to cope with like a higher proportion of aging and obsolete groups. In any case, the change is a reasonable one to introduce, even if I wish Microsoft would spend some time on other obvious deficiencies, like the lack of a GUI for the Groups directory policy.


Learn how to exploit the Office 365 data available to tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

]]>
https://office365itpros.com/2021/08/09/updates-group-creation-settings-azure-ad-admin-center/feed/ 3 50983
Microsoft Launches Preview of App Governance for Cloud App Security https://office365itpros.com/2021/07/21/microsoft-preview-app-governance/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-preview-app-governance https://office365itpros.com/2021/07/21/microsoft-preview-app-governance/#comments Wed, 21 Jul 2021 01:00:00 +0000 https://office365itpros.com/?p=50737

Applying Governance to Graph-Based Apps

Update (November 3): The App governance add-on is out of preview and generally available.

In mid-July, Microsoft introduced the preview of an app governance add-on for Microsoft Defender for Cloud Apps (MCAS), describing the new capability as a “security and policy management capability designed for OAuth-enabled apps that access Microsoft 365 data through Microsoft Graph APIs.”

There’s no doubt that tenants can accumulate a collection of Graph-enabled apps over time. The apps come from Microsoft, ISVs, and line of business apps. Indeed, any PowerShell script you write to interact with the Graph APIs gains its permissions through consent granted to an app registered with Azure AD. The net result is that you can end up with hundreds of registered apps, all with Graph permissions, some of which you might not know much about. App governance aims to deliver a structured management framework for those apps, leveraging information taken from Azure AD and MCAS.

Microsoft research clearly shows that attackers use illicit consent grants for Graph-based apps to extract and abuse data. Given the likelihood that organizations will have more Graph-based apps to manage over time, it’s important that administrators understand app usage in their tenant. Unfortunately, the need to review and analyze app usage often falls down task lists, which is the hole the app governance add-on attempts to close.

The Need for MCAS

MCAS isn’t included in any Office 365 plan. Office 365 E5 includes Office 365 Cloud App Security (OCAS), a cut-down version of the full-blown MCAS. Both operate on the same basis of data gathered from user and app activity, but MCAS delivers more functionality and covers more apps. For this pleasure, tenants need to pay more to license MCAS, unless they’ve already invested in Microsoft 365 E5, Enterprise Mobility and Security E5, or one of the other licenses which cover MCAS. You need MCAS to use the new add-on, which doesn’t work with OCAS.

Fortunately, Microsoft offers organizations the chance to run a 30-day trial for MCAS by signing up through the Purchase services section of the Microsoft 365 admin center. After starting the MCAS trial and assigning some licenses to accounts with suitable administrator roles, you can go ahead and start a trial of the add-on. Curiously, the add-on allows a 130-day trial, which might be due to its desire to capture and analyze usage data for apps over a reasonable period. Of course, if you sign up for both trials, MCAS expires after 30 days, and you won’t be able to use the add-on afterwards.

Using App Governance

App governance runs within the Microsoft 365 admin center. If your account isn’t licensed or doesn’t hold one of the necessary compliance roles, you’ll be told this unhappy news if you attempt to access the page. Licensed administrators see a preview of the app situation in the tenant (Figure 1).

App Governance overview
Figure 1: App Governance overview

I had recently been through an audit of apps based on grabbing app data from Azure AD and reviewing the data through Microsoft Lists, so there are fewer apps present in my tenant than existed previously. As I reviewed the data set, I found a couple of additional apps that I could disable or remove. You can disable an app by viewing its properties through App governance; to remove it, you need to use the Azure AD admin center. Disabling is a good first step to removing a potentially problematic app as you can easily enable the app if someone reports that a business case exists for its use.

In my tenant, app governance detected 33 high privileged apps and 13 overprivileged. Microsoft’s definitions for these categories are:

  • High privilege: Consent has been granted to the app for Graph permissions that allow the app to access data or change key settings in the organization.
  • Overprivileged: Consent has been granted to the app for Graph permissions the app doesn’t use.

To examine details of an app to understand why it falls into a certain category, click Apps, and peruse the list of apps to select and view the app properties (Figure 2).

Browsing the set of Graph-enabled apps
Figure 2: Browsing the set of Graph-enabled apps

As you can see, the portal includes several filters to limit the set of displayed apps. The set of available filters misses one to show disabled apps. This means that if you need to find a disabled app, perhaps to reenable it if the app had been disabled in error, you either need to know the name of the disabled app or do a lot of checking to find the right app.

Probing Permissions

Mmany apps fall into the high privilege category because they read user information. For example, the app used by Microsoft Ignite conference attendees to register has permission to see the user’s email and profile. Apps created by ISVs to read and report tenant data need access to the directory, and that is flagged as a high privilege permission because attacker apps also use the permission to find targets. Even Microsoft’s own Information Barriers app is flagged as high privilege because it has the Directory.Rewrite.All and Groups.Rewrite.All permissions. As always, understanding the context of what an app does is necessary to understand why it needs permissions.

App governance allows tenant administrators to automate checks by creating policies to monitor the creation of overprivileged or high privilege apps. This functionality works like the other alert policies available in the Microsoft 365 compliance center with the exception that the input data focuses on apps rather than actions. As you can see in Figure 1, policies quickly flag new apps which violate criteria. But as pointed out above, you then need to check the app to figure out if a problem really exists.

Permission Glitches

The add-on is a preview, so glitches are expected. For example, app governance flagged an app written to support adding organizational contacts to new user mailboxes as overprivileged. When I examined details of the app (Figure 3), the unused permission is Contacts.ReadWrite. This is odd because that’s the exact permission needed to write a new contact record into a mailbox.

Details of an app marked as overprivileged
Figure 3: Details of an app marked as overprivileged

Apart from app details and permissions, App Governance promises to show data about usage and users. Taking users first, I thought this information to be quite useless. The information shown on Figure 4 tells me that 237 consented users exist (Azure AD accounts with data the consents granted to the app covers). This figure includes both tenant and guest accounts and results because an administrator granted consent to the app for the entire organization (if consent is given for individual accounts, they are listed here). The five priority users are those marked as priority accounts. None of the priority accounts (including my own) had any trace of data uploaded or downloaded using the app. Given the app is Microsoft’s Graph Explorer, which I use to test Graph API queries almost daily, this was surprising.

User data reported for an app
Figure 4: User data reported for an app

After being disappointed with the data available for users, I didn’t hold out much hope for the Usage (beta) tab. And my expectations were met as precisely nothing showed up here. Instead, App governance informed me that no data was present. Oh well, it’s a preview.

DIY App Governance

As mentioned above, it is relatively simple to perform a DIY audit of Microsoft 365 Graph-enabled apps. Home-grown knowledge of apps used in a tenant is an advantage MCAS can’t deliver, but to exploit that knowledge, some work is necessary to acquire, refine, and understand the app inventory – and to keep on checking on a systematic basis.

App governance extends simple auditing by including policy-based management, categorizing apps based on the permissions they hold, and delivering some insights into app usage. Although still just a preview with all that implies, if your organization has MCAS, the add-on is a useful enhancement. If not, although the need to monitor the granting and usage of permissions in Graph-enabled apps is a real need, you might be able to construct your own method to achieve the goal.


Stay updated with developments across the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. We do the research to make sure that our readers understand the technology.

]]>
https://office365itpros.com/2021/07/21/microsoft-preview-app-governance/feed/ 2 50737
Microsoft Security Report Points to Basic Authentication as Root of BEC Attacks https://office365itpros.com/2021/06/17/business-email-compromise/?utm_source=rss&utm_medium=rss&utm_campaign=business-email-compromise https://office365itpros.com/2021/06/17/business-email-compromise/#respond Thu, 17 Jun 2021 01:49:00 +0000 https://office365itpros.com/?p=50315

Business Email Compromise, Phishing, Inbox Rules, And Forwarding

A June 14 report from Microsoft’s Threat Intelligence Center (MSTIC) highlights the issue of basic authentication once again, this time in the context of business email compromise (BEC) attacks. Essentially, successful phishing using email like an invoice request or missed voicemail results in the collection of user credentials. Attackers use the credentials to sign into mailboxes and create an inbox rule to forward copies of messages containing terms like invoice, payment, or statement to their system. Another inbox rule then cleans up the copies of the forwarded messages so that the mailbox owner doesn’t see them in their Sent Items folder. I have experience of such an attack in a company where I worked, where attackers used the technique to copy messages from the CFO’s mailbox and eventually attempt to send a BEC message to secure funds.

There’s no surprise in learning that phishing is an ongoing problem and an attack vector used by people wishing to gather confidential data like user credentials with the aim of achieving some illegal gain.

Basic Authentication Still in Place

The sad fact is that many Microsoft 365 tenants continue to allow people to use a combination of basic authentication with antiquated connection protocols like POP3 and IMAP4 to access Exchange Online mailboxes. Microsoft is doing its best to cajole organizations to turn off basic authentication for as many connection protocols as possible, and has offered hard evidence of why basic authentication is so bad. Moving to modern authentication (MFA) reduces the likelihood of success for a password spray attack. Better again, using multi-factor authentication blocks 99.9% of account compromise attacks. And adding conditional access policies to the mix improves things even more.

All of which makes it hard to understand when organizations continue along a dangerous path that only benefits hackers.

The MSTIC report explains how the attackers likely use POP3 or IMAP4 to test credentials (MFA stops this happening) before creating the rules in the mailbox. Microsoft recently clamped down on email forwarding by blocking the ability of users to configure forwarding unless allowed by the outbound spam filter policy. The report isn’t clear if any of the organizations where Microsoft found problems used the outbound spam filter policy to block forwarding, but notes that because of the clampdown, the threat of BEC campaigns using mail forwarding rules is significantly reduced.

Checklist for Tenant Administrators

The introduction of forwarding blocks in the outbound spam policy is a big step forward. However, it’s also true that users can argue the case for exceptions and build a case to be allowed forward some email outside the organization. With an eye on minimizing risk, what should tenant administrators do? Here’s a checklist:

The most important steps are:

  • Configure the outbound spam policy with restricted exceptions to suppress as much forwarding as possible.
  • Use MFA to protect all user accounts. Remember the point above that using MFA eliminates much of the vulnerability of user accounts to attack. You can use PowerShell to find and report on the MFA status of accounts.
  • If you haven’t already done so, configure Entra ID to use Security Defaults. Microsoft enables all new tenants with Security Defaults to make sure that basic steps like enabling MFA for administrator accounts is done. If your tenant is like mine and already uses conditional access policies, you won’t be able to enable Security Defaults (Figure 1), but that’s OK because you’re already well on the way to protecting the tenant. Entra ID evaluates conditional access policies after a successful sign-in, so they won’t stop an attacker penetrating. However, they can stop attackers accessing sensitive information from unmanaged devices or unknown locations. Conditional access policies require Entra ID P1 licenses.

Enabling Entra ID Security Defaults

Business Email Compromise
Figure 1: Enabling Entra ID Security Defaults
  • Microsoft has upgraded the POP3 and IMAP4 protocols to support modern authentication. If people insist on using these protocols, get them to upgrade to a client which supports modern authentication.
  • Monitor what’s happening in the tenant. If you have Office 365 E5, you can use Microsoft Cloud App Security for Office 365. The point is that administrators should use whatever data and tools are available to check the tenant. Even a periodic browse through the Office 365 audit log can turn up unexplained or suspicious events which deserve investigation.

The MSTIC report points out that Microsoft Defender for Office 365 includes a standard alert policy to detect and report suspicious forwarding activity to tenant administrators. Another alert tells administrators when users create a rule to forward email (Figure 2). These alerts should be actioned whenever they happen.

An alert because a user creates an inbox rule to forward email
Figure 2: An alert because a user creates an inbox rule to forward email

Check Mailboxes

If you don’t have Microsoft Defender for Office 365, you can use PowerShell to scan for accounts configured with forwarding addresses or with inbox rules to forward email. The outbound spam policy blocks any attempt to forward email unless the user is listed as an exception in the policy. Even so, it’s good to know where forwarding in configured via mailbox settings or rules. Here’s some code to look for forwarding configured in mailboxes and to check inbox rules with forwarding actions.

[array]$Mbx = (Get-ExoMailbox -RecipientTypeDetails UserMailbox, SharedMailbox -Properties ForwardingSmtpAddress -ResultSize Unlimited)
Write-Host $Mbx.Count "user and shared mailboxes found. Now checking..."
$NumberMbxWithRules = 0; $NumberForwards = 0
ForEach ($M in $Mbx) {
    Write-Host "Processing" $M.DisplayName
    $Rule = $Null
    If ($M.ForwardingSmtpAddress -ne $Null) { # Mailbox has a forwarding address
       $NumberForwards++
       Write-Host $M.DisplayName "is forwarding email to" $M.ForwardingSmtpAddress.Split(":")[1] } 
    $InboxRules = (Get-InboxRule -Mailbox $M.Alias | ? {$_.ForwardTo -or $_.ForwardAsAttachmentTo })
    If ($InboxRules -ne $Null) {
       Write-Host "Processing inbox rules"
       ForEach ($Rule in $InboxRules) {
          $Ex = $Null
          $ForwardTo = @()
          $ForwardTo = ($Rule.ForwardTo | ? { ($_ -Match "SMTP") -or ($_ -Match "EX:") } )
          $ForwardTo += ($Rule.ForwardAsAttachmentTo | ? {($_ -Match "SMTP") -or ($_ -Match "EX:")})
          If ($ForwardTo.Count -gt 0) {
             ForEach ($Recipient in $ForwardTo) {
                If ($Recipient -Match "EX:") {
                   # Recipient known in Exchange directory
                   $Ex = (Get-Recipient -Identity ($Recipient-Split "Ex:")[1].trim("]}")) 
                   $EmailAddress = $Ex.PrimarySmtpAddress }
                Else  {
                  # Simple SMTP address
                   $EmailAddress = ($Recipient -Split "SMTP:")[1].Trim("]") 
                   $Ex = (Get-Recipient -Identity $EmailAddress) }
             }
             Write-Host $M.RecipientTypeDetails $M.DisplayName "has a rule to forward email to" $EmailAddress -ForegroundColor Red
             # Remove the rule if the address is unknown to the directory
              If ($Ex -eq $Null) {
                 Remove-InboxRule -Identity $Rule.Identity -Confirm:$False
                 Write-Host "Rule" $Rule.Name "removed from mailbox!" }
              Else {
                 Write-Host "Destination is known to the tenant directory. Please remove" $Rule.Name "manually if necessary" }
             $NumberMbxWithRules++ }
       }
     }
}

Comment out the relevant lines if you don’t want to remove the inbox rules from user mailboxes. You can download the script  from GitHub and amend it to suit the needs of your organization.

A Long Road to Remove Basic Authentication

Microsoft announced their intention to remove basic authentication from Exchange Online connectivity protocols in September 2019. It’s taken a lot of effort so far to educate, convince, and move customers. The signs are that even more effort will be necessary to complete the transformation. If you’ve been hanging back, maybe now’s the time to consider jumping in to improve the security of your tenant. After all, you wouldn’t like to be the subject matter for the next MSTIC report.

Update (September 1): Microsoft is granting tenants the ability to get a three-month extension before retiring basic authentication. See this article for more detail. January 1, 2023 is the new drop-dead date.


Learn about protecting Exchange Online and the rest of Office 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s importance and how best to protect your tenant.

]]>
https://office365itpros.com/2021/06/17/business-email-compromise/feed/ 0 50315
How to Use Authentication Contexts with Microsoft 365 Sensitivity Labels https://office365itpros.com/2021/06/10/authentication-context-ca/?utm_source=rss&utm_medium=rss&utm_campaign=authentication-context-ca https://office365itpros.com/2021/06/10/authentication-context-ca/#comments Thu, 10 Jun 2021 01:49:00 +0000 https://office365itpros.com/?p=50189

Protect Most Confidential SharePoint Online Sites

Adding to their container management capabilities, a feature for sensitivity labels demonstrate how to use authentication contexts with Entra ID conditional access policies to ensure secure access to information in SharePoint Online sites.

An authentication context is a way to tag information which needs special attention. First introduced in March 2021, authentication contexts are additional information required by a service provider before it grants access to a resource. Microsoft positions authentication contexts as a method to “target policies for data and actions within an app.” Put another way, authentication contexts allow organizations to apply more granular control to targeted data.

As implemented for sensitivity labels, authentication contexts link conditional access policies to let applications like SharePoint Online know that users must provide some extra information before they can access information in labelled sites. Let’s work through an example.

Define an Authentication Context

The first thing to do is to define an authentication context. In the Security section of the Entra ID admin center, open the Protection section, select Conditional Access and choose Authentication context. I created a context called Require MFA (Figure 1). The name is what you’ll see in apps like sensitivity labels. The ID for the context shown towards the bottom of the screen (c1 in this case) is an internal value written into the settings of sensitivity labels which use authentication contexts.

Defining an authentication context in Entra ID.
Figure 1: Defining an authentication context

The Publish to apps checkbox is set, meaning that this authentication context is visible to apps like sensitivity labels and can be used by conditional access policies.

Create a Conditional Access Policy

The next step is to create a conditional access policy to use the authentication context to force multi-factor authentication. Conditional access policies can range from very simple to very complex. To prove that everything works as expected, I created a simple policy which blocks access to resources tagged with the authentication context unless the user authenticates with MFA. The new thing here is that you select the authentication context instead of apps (Figure 2). The requirement to use MFA is selected in the Grant section (not shown here).

A conditional access policy with an authentication context
Figure 2: A conditional access policy with an authentication context

Another easy thing to include in a conditional access policy to protect sensitive data is to include a terms of use (TOU) check to force users to read and acknowledge conditions governing access before they gain access to a site.

Updating the Sensitivity Label

To protect SharePoint Online sites with the conditional access policy, we configure a sensitivity label with the authentication context. Figure 3 shows the UI for sensitivity labels where we’ve selected the authentication context.

Linking an authentication context to a sensitivity label
Figure 3: Linking an authentication context to a sensitivity label

Any attempt to access a site with the label causes SharePoint Online to look at the label settings to see if an authentication context is specified. If one is found, SharePoint Online queries Entra ID to find which conditional access policy is associated with the authentication context and invokes the policy. In our example, attempts to access the site succeed if the user authenticates with MFA and fail otherwise.

Using PowerShell to Assign Authentication Contexts to Sites

The value of Sensitivity labels is that they make it easy to assign a set of different controls to containers, including conditional access policy protection to SharePoint Online sites. However, if your tenant doesn’t use sensitivity labels (yet), you can update sites with PowerShell. After you assign a label with an authentication context to a site, SharePoint Online updates two site settings:

  • ConditionAccessPolicy: Holds the name of the conditional access policy protecting the site. When using an authentication context, this value is “AuthenticationContext.”
  • AuthenticationContextName: Holds the name of the selected authentication context. As per Figure 1, it is “Require MFA.”

Check the values by running the Get-SPOSite cmdlet:

Get-SPOSite -Identity https://office365itpros.sharepoint.com/sites/SuperConfidential | ft con*, aut*

ConditionalAccessPolicy AuthenticationContextName
----------------------- -------------------------
  AuthenticationContext Require MFA

Now we know the properties to update, we can update other sites using the Set-SPOSite cmdlet:

Set-SPOSite -Identity https://office365itpros.sharepoint.com/sites/ProjectAjax -AuthenticationContextName "Require MFA" -ConditionalAccessPolicy "AuthenticationContext"

Testing the Block

To test that everything worked as expected, I used Teams. Many SharePoint sites created today are linked to Teams, so it seemed like a good test scenario. As expected, when I tried to access a site assigned the sensitivity label without using MFA, the Teams Files channel tab failed to connect and displayed an error (Figure 4).

The Teams Files channel tab is blocked because of a conditional access policy
Figure 5: The Teams Files channel tab is blocked because of a conditional access policy

Microsoft says that they are upgrading the Teams Files channel tab to prompt for MFA authentication when necessary. This will make access smoother and avoid users seeing the instant fail in the current experience.

When I tried to open the site using the SharePoint Online browser interface, it opened successfully. This puzzled me for a moment until I realized it was because the account had gone through a self-service password reset (SSPR) challenge and that the credentials gathered through that process satisfied the MFA requirement. This is because Microsoft now uses combined security information for MFA and SSPR (if your organization doesn’t use combined registration, you can enable it using these instructions). When I encountered the SSPR “your organization needs more information” challenge, it didn’t immediately make me think that MFA was involved, but it was!

To confirm that Entra ID enforces the conditional access policy for the site, you can check the Entra ID sign-in logs. Figure 5 shows that Entra ID invoked the policy because a user covered by the policy signed into SharePoint Online. The sign-in record doesn’t capture details of the site, but if only one sensitivity label uses the conditional access policy and you know who signed in, you can put two and two together to know what happened.

Entra ID sign-in record showing that the conditional access policy matched when accessing the SharePoint Online site.
Figure 5: Entra ID sign-in record showing that the conditional access policy matched when accessing the SharePoint Online site

Increasing Control

Linking sensitivity labels with conditional access policies increases the granularity of control a label can exercise over SharePoint Online sites and increases the usefulness of sensitivity labels for container management. Multiple conditional access policies can use a context, which opens a bunch of different possibilities about how to control access in different circumstances.

Given the amount of confidential information stored in SharePoint Online, it’s nice to be able control conditional access so easily and a good example of how Microsoft is steadily building up the container management capabilities for sensitivity labels. Make sure that you have the necessary licenses before you use the feature!


Stay updated with developments across the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. We do the research to make sure that our readers understand the technology.

]]>
https://office365itpros.com/2021/06/10/authentication-context-ca/feed/ 1 50189
How to Find Accounts with Assigned Licenses for Individual Microsoft 365 Applications https://office365itpros.com/2021/06/08/report-licenses-individual-o365-accounts/?utm_source=rss&utm_medium=rss&utm_campaign=report-licenses-individual-o365-accounts https://office365itpros.com/2021/06/08/report-licenses-individual-o365-accounts/#comments Tue, 08 Jun 2021 01:57:00 +0000 https://office365itpros.com/?p=50009

The Science of Licensing Microsoft 365 User Accounts

The basics of Office 365 licensing are well known. Users access services through service plans bundled in composite plans like Office 365 E3 or E5 or individual offerings like Azure AD Premium P1. Users must have the relevant licenses to access a service like Exchange Online or Teams. Information about the licenses assigned to users are stored in their Azure AD accounts. This context helps us understand how to begin answering questions about licensing that isn’t available in the Microsoft 365 admin center (Figure 1).

Licensing information for a tenant as listed in the Microsoft 365 admin center
Figure 1: Licensing information for a tenant as listed in the Microsoft 365 admin center

The admin center tells you what licenses you have, the licenses assigned and available, and the accounts with assigned licenses. You can export lists of users with a selected license to a CSV file for reporting purposes or to import into Power BI for analysis. But one thing you can’t do is to find out what users have licenses for applications assigned through a composite license.

Individual Application Service Plans

Take the example of Teams, Exchange Online, SharePoint Online. These are core services bundled into the Office 365 E3 and E5 plans. You could assume that everyone with an E3 or E5 license can use these applications, but that’s not true because administrators can remove the service plans for applications from individual user accounts (a service plan is effectively a license for a specific application bundled into a plan; you can’t buy a service plan). Take the example shown in Figure 2. The user has an Office 365 E3 license but the service plans for Bookings, Forms, and Kaizala have been removed.

Viewing licenses for individual service plans removed from a user account
Figure 1: Viewing licenses for individual service plans removed from a user account

It’s relatively common to find that organizations remove individual service plans from users until they are ready to deploy an application. For instance, you might want to use Exchange, SharePoint, and OneDrive for Business immediately but want to block user access to Teams, Forms, Stream, and other applications bundled in Office 365 E3 or E5 until local support is ready and user training is available.

Accessing License Information with PowerShell

While the admin center doesn’t support reporting of service plans for individual applications, it’s possible to do this with some straightforward PowerShell. The key is to discover how to retrieve the licensing information from Azure AD accounts.

Licensing information is in the AssignedPlans property of an Azure AD account. If we examine the property, you’ll see a bunch of assignments and deletions as licenses are added and removed from the account.

(Get-AzureADUser -ObjectId Andy.Ruth@office365itpros.com).AssignedPlans

AssignedTimestamp   CapabilityStatus Service            ServicePlanId
-----------------   ---------------- -------            -------------
28/01/2021 22:11:05 Deleted          OfficeForms        2789c901-c14e-48ab-a76a-be334d9d793a
28/01/2021 22:11:05 Deleted          MicrosoftKaizala   aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1
28/01/2021 22:11:05 Enabled          CRM                95b76021-6a53-4741-ab8b-1d1f3d66a95a

The ServicePlanId is the important piece of information because it stores the unique identifier (a GUID) for the plan. Microsoft publishes an online list of application service plan identifiers for reference. The point to remember is that the same service plan identifier is always used. For instance, 2789c901-c14e-48ab-a76a-be334d9d793a is always Forms Plan E3 (the license for the Forms application included in Office 365 E3).

To confirm this, let’s use the Get-AzureADSubscribedSku cmdlet to retrieve the set of licenses known in a tenant.

$Licenses = (Get-AzureADSubscribedSku)
$Licenses | Select -Property SkuPartNumber, ConsumedUnits -ExpandProperty PrepaidUnits | Format-Table

SkuPartNumber                ConsumedUnits Enabled Suspended Warning
-------------                ------------- ------- --------- -------
STREAM                                   4   10000         0       0
EMSPREMIUM                               5       5         0       0
ENTERPRISEPACK                          22      25         0       0
FLOW_FREE                                3   10000         0       0
POWER_BI_STANDARD                        5 1000000         0       0
ENTERPRISEPREMIUM_NOPSTNCONF             5       5         0       0
TEAMS_EXPLORATORY                        0     100         0       0
SMB_APPS                                 2       3         0       0
RIGHTSMANAGEMENT_ADHOC                   3   50000         0       0

The online documentation tells us that the name of the Office 365 E3 SKU is ENTERPRISEPACK. It is license number three in our list, so we can look at this object to find out what’s included. As expected, the Service Plan Identifier for FORMS_PLAN_E3 is 2789c901-c14e-48ab-a76a-be334d9d793a.

$Licenses[2].ServicePlans | Format-Table ServicePlanName, ServicePlanId

ServicePlanName              ServicePlanId
---------------              -------------
POWER_VIRTUAL_AGENTS_O365_P2 041fe683-03e4-45b6-b1af-c0cdc516daee
CDS_O365_P2                  95b76021-6a53-4741-ab8b-1d1f3d66a95a
PROJECT_O365_P2              31b4e2fc-4cd6-4e7d-9c1b-41407303bd66
DYN365_CDS_O365_P2           4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14
MICROSOFTBOOKINGS            199a5c09-e0ca-4e37-8f7c-b05d533e1ea2
KAIZALA_O365_P3              aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1
MICROSOFT_SEARCH             94065c59-bc8e-4e8b-89e5-5138d471eaff
WHITEBOARD_PLAN2             94a54592-cd8b-425e-87c6-97868b000b91
MIP_S_CLP1                   5136a095-5cf0-4aff-bec3-e84448b38ea5
MYANALYTICS_P2               33c4f319-9bdd-48d6-9c4d-410b750a4a5a
BPOS_S_TODO_2                c87f142c-d1e9-4363-8630-aaea9c4d9ae5
FORMS_PLAN_E3                2789c901-c14e-48ab-a76a-be334d9d793a
STREAM_O365_E3               9e700747-8b1d-45e5-ab8d-ef187ceec156
Deskless                     8c7d2df8-86f0-4902-b2ed-a0458298f3b3
FLOW_O365_P2                 76846ad7-7776-4c40-a281-a386362dd1b9
POWERAPPS_O365_P2            c68f8d98-5534-41c8-bf36-22fa496fa792
TEAMS1                       57ff2da0-773e-42df-b2af-ffb7a2317929
PROJECTWORKMANAGEMENT        b737dad2-2f6c-4c65-90e3-ca563267e8b9
SWAY                         a23b959c-7ce8-4e57-9140-b90eb88a9e97
INTUNE_O365                  882e1d05-acd1-4ccb-8708-6ee03664b117
YAMMER_ENTERPRISE            7547a3fe-08ee-4ccb-b430-5077c5041653
RMS_S_ENTERPRISE             bea4c11e-220a-4e6d-8eb8-8ea15d019f90
OFFICESUBSCRIPTION           43de0ff5-c92c-492b-9116-175376d08c38
MCOSTANDARD                  0feaeb32-d00e-4d66-bd5a-43b5b83db82c
SHAREPOINTWAC                e95bec33-7c88-4a70-8e19-b10bd9d0c014
SHAREPOINTENTERPRISE         5dbe027f-2339-4123-9542-606e4d348a72
EXCHANGE_S_ENTERPRISE        efb87545-963c-4e0d-99df-69c6916d9eb0

Reporting Accounts Licensed for an Application

Now that we know how service plan identifiers work and how to find their values, we can use this knowledge to build a script to interrogate Azure AD user accounts to find license data for an application.

Not everyone likes inputting GUIDs, so we’ll make it easier by allowing an application name to be used for the query. The code creates a hash table of service plan identifiers and names (feel free to add more if you want) and then retrieves details of Azure AD user accounts. We ask the user to enter an application to check and validate the response against the hash table. Finally, we loop through the set of Azure AD accounts to check if the license is in their assigned set and report the details. Here’s the code (you can download it from GitHub):

$Plans = @{}
$Plans.Add(“199a5c09-e0ca-4e37-8f7c-b05d533e1ea2”, “Bookings”)
$Plans.Add(“efb87545-963c-4e0d-99df-69c6916d9eb0”, “Exchange Online”)
$Plans.Add(“5dbe027f-2339-4123-9542-606e4d348a72”, “SharePoint Online”)
$Plans.Add(“7547a3fe-08ee-4ccb-b430-5077c5041653”, “Yammer”)
$Plans.Add(“882e1d05-acd1-4ccb-8708-6ee03664b117”, “Intune”)
$Plans.Add(“57ff2da0-773e-42df-b2af-ffb7a2317929”, “Teams”)
$Plans.Add(“2789c901-c14e-48ab-a76a-be334d9d793a”, “Forms”)
$Plans.Add(“9e700747-8b1d-45e5-ab8d-ef187ceec156”, “Stream”)
$Plans.Add(“b737dad2-2f6c-4c65-90e3-ca563267e8b9”, “Planner”)
Write-Host “Finding Azure AD Account Information”
$Users = Get-AzureADUser -All $True -Filter "Usertype eq 'Member'"
CLS
$Product = Read-Host "Enter the Office 365 application for a license check"
if (!($Plans.ContainsValue($Product))) { # Not found
   Write-Host “Can’t find” $Product “in our set of application SKUs”; break }
Foreach ($Key in $Plans.Keys) { # Lookup hash table to find product SKU
   If ($Plans[$Key] -eq $Product) { $PlanId = $Key }
}
$PlanUsers = [System.Collections.Generic.List[Object]]::new() 
ForEach ($User in $Users) {
  If ($PlanId -in $User.AssignedPlans.ServicePlanId) {
    $Status = ($User.AssignedPlans | ? {$_.ServicePlanId -eq $PlanId} | Select -ExpandProperty CapabilityStatus )
    $ReportLine  = [PSCustomObject] @{
          User       = $User.DisplayName 
          UPN        = $User.UserPrincipalName
          Department = $User.Department
          Country    = $User.Country
          SKU        = $PlanId
          Product    = $Product
          Status    = $Status } 
    $PlanUsers.Add($ReportLine) }
}
Write-Host "Total Accounts scanned:" $PlanUsers.Count
$DisabledCount = $PlanUsers | ?{$_.Status -eq "Deleted"}
$EnabledCount = $PlanUsers | ? {$_.Status -eq "Enabled"}
Write-Host (“{0} is enabled for {1} accounts and disabled for {2} accounts” -f $Product, $EnabledCount.Count, $DisabledCount.Count)
$PlanUsers | Sort User | Out-GridView

The Graph Alternative

You can also use the Users Graph API to fetch license information for Azure AD accounts by running a call like:

https://graph.microsoft.com/v1.0/users?$filter=userType eq 'Member'&$select=id, displayName, licenseassignmentstates, assignedplans

The code to check the AssignedPlans data for a product identifier is the same. Although the Graph is usually faster than PowerShell cmdlets, in this instance only one call is needed, and the speed difference is marginal.

As ever, if you plan to use the Graph to fetch data, testing call syntax and returns using the Graph Explorer tool is a good thing to do. Figure 3 shows the result of querying the Graph to return user license data.

The Graph Explorer runs a query to retrieve license information for a user account
Figure 3: The Graph Explorer runs a query to retrieve license information for a user account

Processing Licenses in Different Plans

Because the script looks for a specific service plan identifier, it finds every instance of a licensed application. In other words, if you search for an application like Exchange Online, which included as EXCHANGE_S_ENTERPRISE (efb87545-963c-4e0d-99df-69c6916d9eb0) in both Office 365 E3 and E5), the report will list accounts enabled for Exchange in both plans. If you want to differentiate between the two plans, you need to check the AssignedLicenses property of each account for the identifier of the plan. For instance, looking at Microsoft’s reference list, we find that:

  • 6fd2c87f-b296-42f0-b197-1e91e994b900 is the identifier for Office 365 E3.
  • c7df2760-2c81-4ef7-b578-5b5392b571df is for Office 365 E5.
  • 26d45bd9-adf1-46cd-a9e1-51e9a5524128 is for Office 365 E5 without audio conferencing.

The script available from GitHub includes code to output the names of license SKUs.

Outputting the License Data

The information in the report can be saved to a CSV file or viewed online. Figure 4 shows the result of the script as viewed through the Out-GridView cmdlet. We can see that the user we removed the Forms license in Figure 1 is reported accurately.

Reporting license data
Figure 3: Reporting license data

You might not need to interrogate Azure AD for details of individual licenses very often, but if you do (as when preparing to enable an application for a bunch of users), it’s much faster to get the information with PowerShell than using the admin center GUI.


For more great information about how licensing works, subscribe to the Office 365 for IT Pros eBook.

]]>
https://office365itpros.com/2021/06/08/report-licenses-individual-o365-accounts/feed/ 2 50009
Microsoft Lays Out Future for Azure AD PowerShell Module https://office365itpros.com/2021/06/03/microsoft-graph-powershell-sdk/?utm_source=rss&utm_medium=rss&utm_campaign=microsoft-graph-powershell-sdk https://office365itpros.com/2021/06/03/microsoft-graph-powershell-sdk/#comments Thu, 03 Jun 2021 01:48:00 +0000 https://office365itpros.com/?p=50127

Microsoft Graph PowerShell SDK is the Future

For anyone who’s ever used the Azure AD or Microsoft Online Services (MSOL) PowerShell modules to write PowerShell code to automate some aspect of tenant administration, Microsoft’s June 2 announcement about their future direction for Azure AD PowerShell was big news. In a nutshell, Microsoft is focusing on the Graph APIs for identity management. As a consequence, any software which leverages the Azure AD Graph API, like the Azure AD module, is on the runway to deprecation.

Important Points for the Next Year

Last year, Microsoft announced that they would no longer support or provide security updates for the Azure AD Graph API after 30 June 2022. Now they are being more specific about what this end of support decision means for customers. The following points are important:

  • Microsoft’s future investments for identity management are focused on the Microsoft Graph SDK for PowerShell. This is a wrapper around the Graph APIs and is already in use for purposes like setting tenant privacy options for the Insights API.
  • The Azure AD and MSOL modules will not be supported for PowerShell 7.
  • New identity APIs will be available through the Microsoft Graph PowerShell SDK (Figure 1).
  • Microsoft’s investments will center on user, group, and application management, plus role-based access control (RBAC), which is important in terms of making sure that administrators don’t need all-powerful permissions to get work done. Microsoft 365 uses an increasing number of role groups to assign administrative work to different accounts.
  • Microsoft also says that they will invest in usability for the Microsoft Graph PowerShell SDK, which is a good thing because the SDK cmdlets aren’t quite as approachable as those in other modules. The documentation is not in good shape either. See my articles covering basic Azure AD user account management and group management for details.

 Connecting to the Microsoft Graph PowerShell SDK
Figure 1: Connecting to the Microsoft Graph PowerShell SDK

Microsoft says that their goal is that “every Azure AD feature has an API in Microsoft Graph so you can administer Azure AD through the Microsoft Graph API or Microsoft Graph SDK for PowerShell.” They don’t say that every feature will be accessible through the Microsoft Graph PowerShell SDK. In some cases, you’ll need to run pure Graph API calls, but that’s easily done using PowerShell (for an example, see this article on accessing Azure AD access reviews from PowerShell.

Update August 1, 2022: Microsoft has pushed out the previously announced retirement date for the license management cmdlets in the Azure AD and MSOL modules (August 26, 2022) to March 31, 2023. They have delayed the retirement of the Azure AD Graph API until the end of 2022 to give customers extra time to adjust.

It’s Different With the Graph

The net takeaway is that tenants need to review any PowerShell scripts which use the Azure AD or MSOL modules to prepare plans to upgrade scripts to use the Microsoft Graph PowerShell SDK or Graph API calls in the future. Given the number of Office 365 tenants, the pervasive use of PowerShell to automate operations, and the core position of Azure AD in those operations, it’s likely that millions of scripts will need upgrades. I know that I have a bunch of scripts to review and will discuss how the upgrade process proceeds in future articles. Already, I know it won’t be simply a case of replacing all occurrences of Azure AD cmdlets with equivalent Graph SDK calls, like replacing Get-AzureADUser with Get-MgUser. Parameters and output are likely to be different and code will need to be adjusted to cope.

While upgrading scripts is a big job, each script is a one-time activity. Interactive access is another issue. Today, it’s easy to run Connect-AzureAD to connect to Azure AD and then run whatever cmdlets you need to interrogate the directory. The equivalent actions with the SDK are:

First, you connect to the Graph and set the scope (permissions) needed to interact with Azure AD. Unless a suitable access token is available, this starts a device authentication sequence.

Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All"
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code D7DPGD3WL to authenticate.

Opening a web page and inputting the code causes another dialog to appear to confirm consent for the operation (Figure 2).

App consent required to use the Microsoft Graph PowerShell SDK
Figure 2: App consent required to use the Microsoft Graph PowerShell SDK

After consent is granted, you can then go ahead and issue commands. For example, here’s how to fetch a list of guest accounts:

$Guests = Get-MgUser -Filter "UserType eq 'Guest'"

Like most Graph commands, the amount of data returned is constrained to 100 items, so if you want more, you need to specify the All parameter.

The bottom line is that some more up-front thought is needed (to set permissions) before connecting to the Graph SDK and that the authentication flow is not as seamless as it is when running Connect-AzureAD. No doubt this is an area where Microsoft might look at to remove some rough edges.

Time to Prepare Upgrades

Losing support for the Azure AD and MSOL modules sometime in 2022 is a concern, but we’ve seen other instances when Microsoft has extended support to allow customers extra time to get work done, and anyway, losing support doesn’t mean that code will suddenly stop working. Scripts will continue to run. You just won’t be able to ask Microsoft to fix bugs.

One thing you can guarantee in the cloud is that change happens. This is just another example of how that change occurs.


The Office 365 for IT Pros team will document our learning with upgrading PowerShell scripts from the Azure AD module to use the Microsoft Graph PowerShell SDK in the months ago. It should be fun… Subscribe now to make sure that you stay abreast of developments.

]]>
https://office365itpros.com/2021/06/03/microsoft-graph-powershell-sdk/feed/ 12 50127
How to Find Guest Accounts Blocked by the Azure AD B2B Collaboration Policy https://office365itpros.com/2021/05/17/azure-ad-b2b-collaboration-policy/?utm_source=rss&utm_medium=rss&utm_campaign=azure-ad-b2b-collaboration-policy https://office365itpros.com/2021/05/17/azure-ad-b2b-collaboration-policy/#comments Mon, 17 May 2021 01:58:00 +0000 https://office365itpros.com/?p=49689

Blocking Guests We Don’t Want to Collaborate With

Updated 12 June 2023

In an earlier post, I cover the basics of updating the Azure AD B2B collaboration settings for a Microsoft 365 tenant. Azure AD B2B collaboration external settings allow the tenant to define a deny list of domains they do not want guest accounts to come from or an allow list to define a restrictive set of domains they’re willing to accept guests from. In my experience, most tenants use a deny list. Once implemented, any attempt to add a new guest account from one of the blocked domains will fail. This happens for applications like Teams and Outlook, and administrative interfaces like the Azure AD admin center (Figure 1).

The Azure AD admin center stops an administrator adding a new guest from a blocked domain
Figure 1: The Azure AD admin center stops an administrator adding a new guest from a blocked domain

Azure B2B Collaboration settings work well and no new guest users from domains featuring on its blacklist can be added. However, it does nothing to stop existing guests from those domains continuing to be members of groups and teams within your tenant. Microsoft doesn’t have a facility to detect and remove problem guest users, but it’s relatively easy to do with PowerShell.

The Find Bad Guests Script

We’ve posted a new script called FindBadGuestsFromBlockedDomains.PS1 in the Office 365 for IT Pros GitHub repository. The script works as follows:

  • Read the Azure AD B2B Collaboration settings to find if a blacklist of banned domains exists. If some domains are on the blacklist, we continue.
  • Find the set of Microsoft 365 Groups (including Teams) with guest members.
  • Examine the membership of each group to check if any of the guests come from banned domains.
  • Report the results.

When the script finishes processing the set of groups, it generates some basic statistics (Figure 2) and a CSV file.

Results of scanning for guests from domains blocked by Azure AD B2B Collaboration settings
Figure 2: Results of scanning for guests from blocked domains

Cleaning Up Banned Guests

The CSV file (Figure 3) contains the Azure AD object identifier for each guest account found from a banned domain. This is important because you can use this to drive a removal process if necessary.

Contents of the CSV file detailing guests from blocked domains
Figure 3: Contents of the CSV file detailing guests from blocked domains

Before removing a guest account, remember what it will do:

  • Remove the guest from memberships of all groups/teams they belong to.
  • Remove access to any documents, folders, or lists shared using the guest account.

Before deleting anything, you should review the contents of the CSV file carefully to check that each account really should be deleted. Any guest account that you want to keep should be removed from the file. The updated file can then act as the input for a removal process. For instance, this PowerShell code reads the CSV file and removes the accounts included in the file.

$BadAccounts = Import-Csv c:\temp\BadGuestAccounts.CSV
ForEach ($Account in $BadAccounts) {
   Write-Host "Removing" $Account."Guest Email"
   Remove-AzureADUser -ObjectId $Account.ObjectId }

After removing problem accounts, the remaining guest accounts in the tenant comply with the Azure AD B2B collaboration settings. If you decide to remove guest accounts, it’s probably a good idea to email the group/team owners to let them know what you plan to do, just in case a guest account is required.

Like any of our scripts, the code is written to explain a principal and demonstrate how to construct a solution to a problem. I’m sure the code can be improved, notably by adding better error handling. But it does work (at least in our tenant).


The Office 365 for IT Pros eBook has lots of intensely practical advice to help administrators run tenants. Subscribe to make sure that you benefit from our knowledge.

]]>
https://office365itpros.com/2021/05/17/azure-ad-b2b-collaboration-policy/feed/ 3 49689
Microsoft Stops Set-User Updating Phone Numbers for Azure AD Accounts https://office365itpros.com/2021/05/11/set-user-stops-working/?utm_source=rss&utm_medium=rss&utm_campaign=set-user-stops-working https://office365itpros.com/2021/05/11/set-user-stops-working/#comments Tue, 11 May 2021 01:11:00 +0000 https://office365itpros.com/?p=49788

Change Made without Warning for Security Reasons

Without any warning, Microsoft seems to have introduced a restriction to the Set-User cmdlet in the Exchange Online management PowerShell module. The change happens when you connect a new PowerShell session to Exchange Online and the cmdlets are downloaded into a session.

Security Problems Updating Work or Mobile Numbers

Any attempt to update a user’s business or mobile phone numbers with Set-User now generates an error saying that for security reasons these properties cannot be updated through Exchange Online. Instead, administrators are forced to update the properties through the Azure AD admin center or by using the Azure AD PowerShell module.

Set-User -id $User -Phone "+1 454 146 1412"
Phone and Mobile Phone for users with Recipient Type Details "UserMailbox" cannot be updated in Exchange Online for security reason. Please do it in Azure Active Directory.
    + CategoryInfo          : NotSpecified: (Jessica.Chen@office365itpros.com:UserIdParameter) [Set-User], ShouldNotUpdate...eInExoException
    + FullyQualifiedErrorId : [Server=AM4PR0401MB2289,RequestId=39d0dbcb-05d1-42e6-b8ea-4bc78fc58816,TimeStamp=10/05/2
   021 22:22:12] [FailureCategory=Cmdlet-ShouldNotUpdatePhoneMobilePhoneInExoException] 1D58FC00,Microsoft.Exchange.Management.RecipientTasks.SetUser
    + PSComputerName        : outlook.office365.com

Set-user -id $User -MobilePhone "+1 464 147 4433"
Phone and Mobile Phone for users with Recipient Type Details "UserMailbox" cannot be updated in Exchange Online for
security reason. Please do it in Azure Active Directory.
    + CategoryInfo          : NotSpecified: (Jessica.Chen@office365itpros.com:UserIdParameter) [Set-User], ShouldNotUpdate...eInExoException
    + FullyQualifiedErrorId : [Server=AM4PR0401MB2289,RequestId=4cffcdc2-5bc0-4d17-83bf-a4d7bb67d2a5,TimeStamp=10/05/2
   021 22:22:21] [FailureCategory=Cmdlet-ShouldNotUpdatePhoneMobilePhoneInExoException] 1D58FC00,Microsoft.Exchange.Management.RecipientTasks.SetUser
    + PSComputerName        : outlook.office365.com

Oddly, Set-User is still able to update other phone numbers such as a user’s phone or alternative number. You can also update someone’s pager number (if they still use one) and their fax number. The fax number also appears as a property for an Azure AD account, so if Microsoft decided to block the business and mobile numbers, it’s strange that they left the fax number alone.

Disruption to Scripts

Set-User has been part of Exchange PowerShell since Exchange 2007. The cmdlet is a method to update account properties stored in Active Directory and Azure Active Directory which are important to Exchange (because they appear in address lists). Changing behavior without warning is disruptive to organizations because it might impact scripts used for production purposes, such as taking a feed from a HR system and updating user accounts.

Microsoft’s error message implies that the change happened for security reasons, but as they haven’t explained any detail about why it is a security problem to allow Set-User to update phone numbers, it’s hard to assess what’s going on here. If it’s a problem for Set-User to update telephone numbers, why is it OK for Set-AzureADUser to do the same?

Set-AzureADUser -ObjectId Jessica.Chen@office365itpros.com -TelephoneNumber "+1 550 771 1314" -Mobile "+1 466 146 1453"

Roles and Permissions

Accounts need different permissions to run the two cmdlets. Accounts holding the Exchange administrator role can update mailbox properties (some of which synchronize with Azure AD) but can’t do so using Azure AD interfaces like the Azure AD PowerShell module. It could be that Microsoft wants to tighten the ability of users with workload-specific roles to update Azure AD.

Although I can’t prove this, I suspect that the tightening is at the heart of problems reported with the Set-CsUser cmdlet since the release of V2.3.0 of the Microsoft Teams PowerShell module last month (see this Microsoft Technical Community post for some details of user issues).

Communications Failure

Microsoft is much better at communicating change within Office 365 today than they used to be, notably through the Microsoft 365 roadmap and the notifications posted to the Microsoft 365 admin center. This change came out of the blue and landed without warning. People don’t like surprises and always react better if the logic behind an update is clearly explained. Everyone will get behind a change which helps to improve security – unless they find out when their scripts stop working.

]]>
https://office365itpros.com/2021/05/11/set-user-stops-working/feed/ 1 49788