Monday, August 29, 2022

Error adding authorized senders for distribution group

A client has a distribution group in Exchange Online with many members that restricts who can send to the group. This is a common scenario and works quite well.

Configuring specified senders is done in Delivery management. In the example below, Byron Wright and Jeff Smith are allowed to send. Normally to add another sender, you search for them, add, and then save.

Delivery management settings for a distribution group that shows specified senders option.

When we were adding an additional user, we got the following error:

There are multiple recipients matching the identity "<username>". Please specify a unique value.
Error executing request: There are multiple recipients matching
the identity "<user>". Please specify a unique value.

This was verify confusing because we knew all of the email addresses were unique. However, when searching, I found a document mentioning the same error for creating rules in OWA. The cause of the error was multiple recipients having the same display name.

Sure enough, we went through the list of specified senders and found several that had duplicates with the same display names (student and staff accounts for example). After we changed the duplicate display names and synced them up to Azure AD we could add and remove specified senders as expected.

The recipient indicated in the error message is not necessarily the identity with the duplicate Display Name. If you attempt to remove users one by one and save the changes, the successful save indicates which is a duplicate. If you're using the method, make sure to note the allowed senders before you start editing.

Otherwise, you can also use the Admin center search bar to see if there are duplicates for a name. This lets you search across recipient types for users, contacts, groups, and teams.

There seems to be some inconsistency in how the uniqueness of users is evaluated. It seems that when you initially add a user it's based on the email address and the display name issue only pops up when you go to edit the list afterwards. For example, we could add (Bob Smith) as a sender even though there was another Bob Smith. But after doing that we'd get the error if we attempted to edit the list.

Tuesday, July 12, 2022

Is my domain name attached to a tenant?

A common issue is verifying whether a domain name is already attached to a Microsoft 365/Azure AD tenant. If you don't check ahead of time, you often find that you can't add a new domain name to a tenant at a critical time during a project.

To check whether a domain name is already in Microsoft 365:

If there is a tenant ID, then it's already registered.

This often gets us to the point where no one knows for sure what tenant and who might be able to log in. It might have been created for volume licensing or a Power BI trial. There's really no way to know.

Instructions on how to get the domain name back:


Monday, May 2, 2022

Mailbox moves between Exchange Online tenants

For the last several years I've been involved mostly in tenant to tenant migration projects. These projects typically include migration of email, teams, and SharePoint. My focus is on email migration.

For migration, there are a number of third party tools such as MigrationWiz (Bit Titan) and On Demand Migration for Email (Quest ODME) that can be used. I don't know all of the details for all tools, but at least in the case of ODME, the migration is copies mailbox data, but doesn't synchronize it. So, if you migrate data from source to target and the user later deleted data from the source, it is not deleted in the target. Occasionally, this is annoying and causes confusion for users.

Microsoft has tenant-to-tenant mailbox moves in Preview. This type of move is a migration batch like moving mailboxes between on-premises Exchange and Exchange Online. In this case, you get true syncing which is a better quality move. It looks like a bit of a pain to setup and manage, but I expect the experience will improve over time.

The documentation claims that mailbox permissions like Full Access are maintained as long as users are part of the same migration batch. It does not mention inbox rules.

Another interesting item that's coming up is Microsoft 365 cross-tenant SMTP domain sharing. This  allows an email domain to exist in two Microsoft 365 tenants simultaneously and will make it easier to manage incremental migrations between tenants when you want to maintain the same email address. The feature is currently in private preview, but is scheduled to be moved into public preview in June 2022.

You can monitor the development status at:

Saturday, February 12, 2022

Query recently created users in Azure AD

Recently had a project where we wanted to identify users created an automated process in the last day. This script gets the job done.

#Gather a list of recently created users

#specify time that will be compared against -24 is the most recent 24 hours
#you can use the option funtion addDays for a longer time period
#Note that time from AzureAD is UTC

$time = (get-date).ToUniversalTime().AddHours(-24)

$users = Get-AzureADUser -All

$newusers = New-Object Collections.Generic.List

foreach ($u in $users) {
    # Write-Host $u.ExtensionProperty.createdDateTime
    If ([datetime]$u.ExtensionProperty.createdDateTime -gt $time) {

Write-host "There are " $newusers.count " new users"

Friday, February 4, 2022

Dell XPS 13 9380 Pulsating Fan

Short version: BIOS 1.17.0 released Jan 2022 appears to fix pulsating fan issue for Dell XPS 13 9380 in Windows 11

Update: I'm still seeing the pulsating fan occasionally, but less than before the BIOS update.

I recently upgraded my Dell XPS 13 9380 to Windows 11. The entire process was smooth and fast. I was pleasantly surprised by how well it went.

About an hour after the upgrade, as the computer was going to sleep, the fan started to turn on and off at about 1 second intervals. This pulsating stopped if you woke up the computer or (oddly) if you unplugged it from power.

When in doubt, update all drivers and firmware. So, I used Dell Support Assist to download and update all the drivers and firmware. There were about 10 updates. And after applying updates and a restart all seemed good for about 24 hours.

The next afternoon, the fan started to pulsate again. Some Windows Updates had applied since the Dell updates were installed and I was concerned that might be causing the issue. In desperation, I ran Support Assist again, and it showed two updates to apply. One of which was BIOS firmware version 1.17.0.

The BIOS update showed in the history as having been installed yesterday, but it must not have applied properly. This time, the BIOS update applied properly and the problem appears to be resolved.


Monday, November 22, 2021

User Profile Ramifications when Renaming Users on Azure AD-Joined Computers

I'm starting to work more with devices that are Azure AD-joined rather than domain-joined. One of my key questions was what happens to user profiles when an Azure AD user sign-in name (UPN) is changed. I was pleasantly surprised by how well it worked.

For my testing, I created an Azure AD user and signed in to create a profile. During sign-in, I created a PIN for authentication. While signed in, I also configured an Outlook profile and OneDrive. Then I tried changing the domain portion of the username and the userid portion of the username. The results were the same:

  • I could still sign in with the PIN.
  • I could sign in as the same user (username displayed on sign-in screen) with the password.
  • I could sign in with the new username (typed in) and password.

After signing in:

  • The workplace account was updated to the new username.
  • Outlook was still able to sign-in without user intervention and updated the account.
  • OneDrive continued to function without user intervention and updated the account.
  • The same Windows 10 user profile was retained.


Wednesday, November 17, 2021

Managing Microsoft 365 Licenses by using Microsoft Graph

Microsoft has announced that after June 2022, the MSOL and AzureAD cmdlets for managing user licenses in Microsoft 365 will cease working. These cmdlets rely on management functionality that is being retired. To manage licenses programmatically, you need to start using Microsoft Graph.

Here is the announcement:

Microsoft Graph is a web-API that you can use to manage Microsoft 365 users, groups, and services. If you're a programmer, then perhaps the idea of building a web request to perform administrative tasks sounds like a good idea. However, for an admin guy like me that typically uses PowerShell cmdlets for management tasks, building web requests is a bit painful. Fortunately, the Microsoft Graph PowerShell SDK has been released that provides PowerShell cmdlets to access Microsoft Graph features.

To get more information about the Microsoft Graph PowerShell SDK:

 Connecting with Microsoft Graph

Just like you use Connect-AzureAD or Connect-MsolService, for Microsoft Graph, you use Connect-MgGraph. When you connect, you need to specify a scope that defines your permissions. So, unlike previous versions, the connection does not automatically gain the full permissions based on your roles like Global Admin. I haven't experimented with exactly which scopes are required to manage user licenses. However, I can confirm that the following example does work.

Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.ReadWrite.All"

To get more information about Microsoft Graph scopes:

License Structure and Naming

If you've been managing licenses through the web interface in Microsoft 365 or the MSOL cmdlets, you're used to seeing license names such as Office 365 E3. When you manage licenses by using Microsoft Graph, you need to know the SkuId property of the licenses available in your tenant. You can obtain the SkuId for a license by using Get-MgSubscribedSku as shown in the following figure. The SkuPartNumber property is a more user friendly name that you can recognize.

Within each licenses type, there are also service plans. These correlate with apps provided by a license such as Exchange Online (Plan 2). To enable or disable the service plans, you need to use the ServicePlanId for a  service plan. If you place your subscribed SKUs in a variable, you can view the service plans included in the SKU as shown in the following figure.

To get a list of generally available SKUs and their service plans:

Viewing Assigned Licenses

You can view the licenses assigned to a user by using the Get-MgUserLicenseDetail cmdlet as shown in the following example:

Get-MgUserLicenseDetail -UserId

The results of this command return the users license assigned to the user. An array of licenses is returned if multiple licenses have been assigned. Within each license returned, you can view the ServicePlans property to see if any service plans have been disabled for a user.

You can also query assigned license information by using Get-MgUser. The licensing information isn't returned by default and you need to specify that the AssignedLicenses property will be retrieved as shown in the figure below. Notice that these results list the service plans that are disabled for a license.

Querying Users with Assigned Licenses

If you want to query all of the users with a specific license, you can do this by using Get-MgUser with a filter for a specific SkuId. The example below shows the syntax.

Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq 78e66a63-337a-4a9a-8959-41c6654dfb56)" -Property AssignedLicenses,UserPrincipalName,Id

When you are filtering based on AssignedLicenses there are some limitations on the results returned. By default, only 100 results are returned. If you use the PageSize parameter, you can specify up to 999 results are returned as shown below.

Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq 78e66a63-337a-4a9a-8959-41c6654dfb56)" -PageSize 999

If you have a larger tenant, and you try to use the All parameter to return results larger than these limits, you will be the following error Get-MgUser : The specified page token value has expired and can no longer be included in your request.To avoid this error, you need to query a list of all users and then filter by using Where-Object as shown below.

$allusers = Get-MgUser -All -Property AssignedLicenses,UserPrincipalName,Id,DisplayName
$A1plusUsers = $allusers | Where-Object {$_.AssignedLicenses.SkuId -contains "78e66a63-337a-4a9a-8959-41c6654dfb56"}

Modifying Assigned Licenses

To add or remove licenses for a user, you use the Set-MgUserLicense cmdlet. When you run the cmdlet, you need to provide the following parameters:

  • UserId. The user being modified. You can specify the user by the object Id or UserPrincipalName.
  • AddLicenses. A hash table that specifies the SkuId of a license being added and the ServicePlanId of any service plans that are being disabled.
  • RemoveLicenses. A string that identifies the SkuId of a license being removed.

The following code shows how to build a hash table for the AddLicenses parameter. This specifies a license SkuId and a service plan that's disabled in the license.

$A1FacultySku = @{
    SkuID = "94763226-9b3c-4e75-a931-5c89701abe66"
    DisabledPlans = "9aaf7827-d63c-4b61-89c3-182f06f82e5c"

The following code lists a SkuID that will be disabled.

$A1PlusFacultySku = "78e66a63-337a-4a9a-8959-41c6654dfb56"

The command that modifies the user license is below. Note that the UserId parameter will accept a UPN also.

Set-MgUserLicense -UserId $User.Id -AddLicenses $A1FacultySku -RemoveLicenses $A1PlusFacultySku

The RemoveLicenses and AddLicenses parameters are mandatory. If you don't provide an empty array, you'll get an error such as Set-MgUserLicense : One or more parameters of the function import 'assignLicense' are missing from the request payload. The missing parameters are: removeLicenses. If you don't want to remove any licenses, you need to provide an empty array for RemoveLicenses as shown below. If you are only removing licenses, you need to provide an empty array for the AddLicenses parameter.

Set-MgUserLicense -UserId $ -AddLicenses $A1FacultySku -RemoveLicenses @()

If you want to modify the disabled plans for a licenses, you build a new hash table with the license and all of the plans you want disabled. Then you apply the new hash table with the AddLicenses parameter. The new license assignment overwrites the existing license assignment.

If you want to add multiple licenses, you can provide a comma separated list of hash tables. I have not explicitly tested, but I think providing an array with the hash tables would also work.

If you want to remove multiple licenses, create an array with the SkuIDs that you want to remove.