In 2021 Microsoft released an update to SharePoint guest sharing that stopped it using its own SharePoint created guest accounts and would start to use Entra ID Guest Accounts. The accounts in Entra are subject to Conditional Access Policies (and Secure Defaults), MFA Trust, Authentication Methods and Authentication Strengths, and Access Policies and a host of other governance settings. The guests in SharePoint are not subject to these, and indeed are therefore weaker in a security viewpoint (no MFA requirement, just One Time Passcodes by email) and no governance.
If your tenant was created in 2023 or later, then this setting was turned on by default. But it is only turned on in older tenants if the administrator changes the EnableAzureADB2BIntegration setting from $false to $true. This blog post will encourage you to change this setting in older tenants, but cover the issues that can occur and how to resolve them.
In older tenants it is really important to ensure that, if you allow external sharing from OneDrive or SharePoint sites (including files in Teams sites, but nothing to do with adding external members to Teams, as that uses Entra ID guest accounts regardless), you should turn this option on via SharePoint Online PowerShell (Set-SPOTenant) so that your guest sharing is secure.
I would argue that if you do not allow external sharing at the moment, you should turn this on anyway, just in case in the future you do allow some sharing – it fixes the issue before it becomes an issue! If you have no external sharing at the moment then turning this on does not change your sharing position at all, but ensures that if you enable sharing later on, then you will do sharing security properly. If you are in this place you can do this without any of the issues this post will go on to describe!
So what is the problem (apart from insecure sharing to external guests, and that is problem enough)? The problem is that if you turn this option on now (post 1st July 2025) then any previously created external sharing in SharePoint Online will stop working and will need to be reshared by the user and the original guest will not have access until the document is reshared. During this resharing, a guest account for the user will be created in Entra ID and now the external user will be subject to Entra ID governance rules.
All the above is the implication of this change if made after 1st July and also true for any tenant EnableAzureADB2BIntegration was previously enabled in and where a guest user was not created in Entra ID for any existing share. This is because where there is already a guest account in Entra ID for the user none of these issues occur. This issue with sharing being blocked only applies to SharePoint Guests and not Entra ID Guests.
Sharing With B2B Integration Turned Off
So lets take a look at the sharing process looks like before this option is turned on, and how that works (and which account is used) and what happens as we create guests in Entra ID for these users. And finally how we can use this information to ensure that changing to EnableAzureADB2BIntegration causes no issues to your external users.
Final note before we start – this has no impact on anonymous sharing, and is just for external (outside your tenant) sharing. It also has no impact on sharing inside your tenant.
SharePoint Online Guests
So lets start. Firstly, the experience of sharing and receiving an external sharing invite and logging in as the external user to SharePoint Online:
- First step is having something to share, and in this case its a simple Word document saved to SharePoint Online. Your site needs to allow external sharing, as though the global SharePoint default might allow external sharing, the specific site you are testing it might not:

- Once you have the document you click “Share” and enter an external email address. In this scenario we are sharing to an external user (brian.reid@ei…com) with SharePoint Guests and not Entra ID Guests – so ensure that you pick a user who does not have a guest/external member account in your source Entra ID directory:

- The following screenshot shows that this user is not found in the Entra ID directory. Only my user account in the directory is listed if I search for my name (I’m sharing in this blog post to my other accounts in other tenants with similar names!), so brian.reid@ei…com is not listed:

- The external user gets an email informing them of the shared content. This email can change based on the state of the EnableAzureADB2BIntegration setting, but often you cannot tell from the initial email how the sharing is configured:

- We will only ever see an “Open” button when SharePoint Online guest sharing is in place. So we click Open to see the document, and this prompts us to confirm our email address and then onward to login. In SharePoint Online guest sharing, authentication is always One Time Password (OTP) email based:


At this point, having entered the email address that the document was shared to, and the OTP that was subsequently sent to that same email address, we are able to open and view or edit the document depending upon the permissions granted when it was shared.
Even though there is no “brian.reid@ei…com” user in the source tenant (Entra ID), that email owner was able to login and access the document. An email based OTP was used, and no Conditional Access or other governance rules took effect.
Entra ID Guests
So lets changes things up a bit. We still have EnableAzureADB2BIntegration disabled, but this time we are going to create a guest user in Entra ID and share the document to this user. In this example, this is a new user and we have not previously shared content in SharePoint to.
In this example we are going to make the guest account via the Entra ID admin portal, but we could do this via PowerShell (Graph) or via a variety of end user locations such as adding a user to Teams or by having the user synced in from another tenant via Cross-Tenant Sync (part of Multi-Tenant Organizations, MTO).
- Create a new guest user. For this example we are requiring the external user to get an invitation and they will accept this first. This process still works even if you do not send the invite, or use Cross Tenant Access Settings where you can control the showing (or not) of invitations.

- The external user will get an invitation email and an object will be created in Entra ID for this user, in “pending acceptance” for the Invitation State property.
- When the user clicks the button in the email to accept the invitation they will get a privacy prompt that they need to accept.
- The Entra ID user will get fully created, and a hidden Guest Mail User object will be created in Exchange Online for this email address (as long as it does not clash, for example with an existing Mail Contact for this email address)
- Finally we are ready to test SharePoint Online sharing when an Entra ID guest already exists. So we share the same document as earlier with this new email address (brian@nb…co) – this time, the SPO Sharing box will auto-suggest the recipient. This did not happen last time, as the previous external user was not in Entra ID:

- The external user gets the document sharing invitation. This email is the same as previously apart from this time it has both an “Open” and “Share” button. This is because the SharePoint setting “Allow guests to share items they don’t own” is enabled in the source tenant! The reason why this email has these two options is that this time the email has been sent to the Entra ID guest and the “guests can share” option is turned on. If this option was turned off, the email would still go to the guest, but it would just show “Open”.

- Now from this point, everything is different. Even though the sharing email above is similar, the authentication process is Entra ID based and not email OTP based:

- The user sees a prompt for their username (if they are not already logged in) with the logo from the sharing organization.

- The prompt for password, or passwordless OTP (shown above) or passkey continues for the user to login, with the logo being for their organization
- In this example the MFA Trust option is configured on the External Identities > Cross-Tenant Access Settings > Default Settings > Inbound on the source tenant. This means that MFA is performed in the users tenant and not the source/sharing tenant. This means that the guest user does not need to configure MFA for each and every tenant they are accessing shared content in. This is not a requirement for external sharing or MTO, but it certainly makes the end user experience so much more workable and means IT does not need to deal with MFA requests for guest users either!
SharePoint Guests Added To Entra ID After Sharing
This final scenario before we change the B2B Integration settings in SharePoint Online to $true is a combination of the above. We will share a document to a new user (a third user in this continuing example in this blog post) that does not exist in Entra ID and then invite them to Entra ID.
We will do this carrying on from the end of the second example above. In this scenario the option “Allow guests to share items they don’t own” is enabled and so the sharing email in the previous example contained a “Share” button as well. Clicking this when the B2B Integration (EnableAzureADB2BIntegration) setting is $false, will invite the user as a SharePoint Guest and will not create an Entra ID guest. We can see this because there is an Email OTP prompt and no Entra ID guest user is created. This is identical to first scenario above.
But unlike the first scenario where we stopped with only a SharePoint Guest for that user, we will now invite this third user to Entra ID as a guest. This is a valid scenario where this guest might be invited to join a Team or M365 Unified Group. The Team/Group scenario requires an Entra ID guest and will not work with the SharePoint guest objects for simple SharePoint sharing.
The pictures are the same as the second scenario above, so I am not repeating them here – but in this example the login to access the shared document (the “Open” link in the email) does not trigger an email OTP prompt, but instead signs the user in via Entra ID. Specifically in my example, I had logged into Outlook Web Access for my third user and clicked “Open” and I was instantly signed into the other tenant and given access to the document with no further prompts. This was because MFA from the home tenant was trusted, and I had completed the Conditional Access policy requirements when opening Outlook. Now the guest user is in Entra, and so single sign-on (SSO) was able to happen.
Finally for clarity, I was able to look at the sign in logs in the sharing tenant and see that the guest user in Entra had signed in and that the Conditional Access policy I have in that tenant for “MFA for Guests” had been triggered. None of this would have been possible for a SharePoint Guest.
Changing B2B Integration
So with the above in mind, this means that I can change EnableAzureADB2BIntegration to $true without having to reshare documents to external users as long as those users are created in Entra ID as guests first of all.
A Microsoft Message Center post MC1089315 published in June 2025 mentions how enabling B2B Integration will break SharePoint guest sharing and the content will need to be reshared. The findings above mean that if I know who all the active SharePoint Online guest sharing users are, I can create a guest invitation for them before changing EnableAzureADB2BIntegration to $true. The users sharing will continue and will not be blocked, contrary to what the Message Center post says. It works because we are making Entra ID Guests for all the SharePoint Online guests!
If you do not create the guest user in Entra ID though, the target user will be unable to access the shared resource until it is reshared with them, and the resharing process triggers the invitation of the new guest account.
So all you need to do to avoid any issues before turning on EnableAzureADB2BIntegration is to find all your active SharePoint guests and invite them to Entra ID! So we will finish this blog seeing how we can best do this. And for this there are a number of steps. We are therefore going to do the following:
- Get a list of SharePoint Guests in SharePoint Online
- Get a list of SharePoint Guests in OneDrive
- Find any Mail Contact in Exchange Online that matches these SharePoint Guests
- Delete the Mail Contact
- Create Entra ID users (via an invitation without an email)
- Update the new Guest Mail User object in Exchange Online with the deleted Mail Contact properties
- Finally, enable EnableAzureADB2BIntegration
Auditing SharePoint External Sharing
There are two ways to do this. One is to look in the audit logs for anyone logging into SharePoint Online/OneDrive from outside your tenant domains, and collating these usernames for creating into Entra ID. The second option is to look at what has been shared externally from SharePoint Online/OneDrive and collate a list of external users that the content has been shared with.
The first of these will return active users in the audit log period (180 days). The second of these will return all user who have had content shared with them regardless of activity in the last 180 days – so we will look at this second option in this blog post.
Getting this information is done via SharePoint Online PowerShell and PNP SharePoint PowerShell, and needs to be collected per SharePoint Online site that allows external sharing. So first, lets get a list of all SharePoint Online sites that allow external sharing.
Listing All SharePoint Sites With External Sharing
Connect-SPOService -Url https://tenant-admin.sharepoint.com
Get-SPOSite -Limit All | Select URL, SharingCapability | Where-Object {$_.SharingCapability -ne "Disabled"} | Export-CSV SitesWithGuestSharing.csv -NoClobber -NoTypeInformation
The above, run in PowerShell 5 (not PowerShell 7 or later) will login to your SharePoint admin site (change tenant-admin for your correct tenant URL). Then it will get a list of all sites that allow guest sharing. These are all sites that are not set to “Disabled”. The values that are returned mean the following:
- ExternalUserAndGuestSharing = Anyone
- ExternalUserSharingOnly = New and Existing Guests
- ExistingExternalUserSharingOnly = Existing Guests
- Disabled = Only people in your organization
External Guests can exist in any of the first three types of SharePoint sites with that SharingCapability setting. External guests arguably can exist in SharingCapability=”Disabled” sites as well, just only from a time when the site did allow external sharing (if it ever did) as now it no longer does.
The above script results in a CSV file with all the sites that could contain SharePoint guests listed. This list will be used in the script after the OneDrive section.
Listing All OneDrive Sites
Note that the above script does not include OneDrive. If external sharing from OneDrive is possible then you should use the following script to append all the OneDrive (Personal) sites to the CSV file created in the script above:
Connect-SPOService -Url https://tenant-admin.sharepoint.com
Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'" | Select URL, SharingCapability | Where-Object {$_.SharingCapability -ne "Disabled"} | Export-CSV SitesWithGuestSharing.csv -NoClobber -NoTypeInformation -Force -Append
Listing All SharePoint Guests in All SharePoint Externally Sharable Sites
To find all the SharePoint Online guests we need to iterate through the list of sites that are externally sharable, and for each site enumerate the list of guests.
As we see from above, there are two types of guests, the SPO Guests and the Entra ID Guests. We will use the “PNP PowerShell” module to retrieve the email address of all SPO Guests in all externally sharable sites. An SPO Guest is one with “spo%3aguest” in their user name (note, if they have “#ext#” in their username they are an Entra ID Guest and therefore already in Entra ID).
Note: Only guests who have logged in at least once will be returned in the results. If a document has been shared with a user but they have never clicked the “Open” link then they are not discoverable as a SPO Guest in SharePoint Online.
The basics of getting a list of SPO Guests is shown below – this looks at just the root SharePoint site as an example – each site has its own list. This uses PNP SharePoint PowerShell module and not the Microsoft SharePoint Online module that was used above. This module runs in PowerShell 7 or later.
Connect-PnPOnline -Url https://[tenant].sharepoint.com -Interactive [-ClientID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx]
$users = Get-PnPUser
$guests = $users | Where-Object { $_.LoginName -like "*#ext#*" }
$spoguests = $users | Where-Object { $_.LoginName -like "*spo%3aguest*" }
This ends up with a variable called $spoguests that contains all the SharePoint Online guests in the site. It also returns, for info and not required for this blog post, all the external guests permissioned in the site as well (the $guests variable).
The full script to do this, iterating through all the sites, and granting to the user of the script ($UserAccount) Site Admin permissions so that a list of users can be retrieved is as follows:
$results = @()
$allSites = Import-CSV -Path SitesWithGuestSharing.csv
$UserAccount= "pnp-admin@tenant.com" # Change to your account
$i = 1; $total = $allSites.Count
foreach ($site in $allSites) {
Write-Progress -Activity "Finding SharePoint Guests" -Status "$i Completed" -PercentComplete (($i/$total)*100)
Write-Host "Checking site:" $site.Url
Connect-PnPOnline -Url $site.Url -Interactive # -ClientID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Set-PnPTenantSite -Url $site.url -Owners $UserAccount
# The above adds the current account as "site admin"
$users = Get-PnPUser
Write-Host "Found" $users.count "users in the site"
# Remove-PnPSiteCollectionAdmin -Owners $UserAccount
# Remove script user as site collection admin again. Commented out, so by default leaves the $UserAccount user as site collection admin
$guests = $users | Where-Object { $_.LoginName -like "*#ext#*" }
$spoguests = $users | Where-Object { $_.LoginName -like "*spo%3aguest*" }
Write-Host "Found" $spoguests.count "SPO Guests in the site"
foreach ($spoguest in $spoguests) {
$results += [PSCustomObject]@{
SiteUrl = $site.Url
UserDisplayName = $spoguest.LoginName
UserEmail = $spoguest.Email
Title = $spoguest.title
ID = $spoguest.id
Expiration = $spoguest.expiration
}
}
$i++
}
# Remove duplicates and export to CSV
$results = ($results | sort UserEmail -Unique)
$results | Export-Csv -Path "SharePointGuestUsers.csv" -NoTypeInformation -Force -Append
This results in a file called SharePointGuestUsers.csv that lists all sites that contain a SharePoint Online guest, one row per guest (so some sites will appear many times in the results). The important column in the CSV is the UserEmail column.
To finish and clean up, this script will remove the $UserAccount from Site Admin permissions on each site (the Site Collection Administrator). This will restore the site to their original permissions.
# Optional - remove $UserAccount from Site Admin role on each site
$i = 1; $total = $allSites.Count
foreach ($site in $allSites) {
Write-Progress -Activity "Removing Site Admin" -Status "$i Completed" -PercentComplete (($i/$total)*100)
Connect-PnPOnline -Url $site.Url -Interactive # [-ClientID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx]
Remove-PnPSiteCollectionAdmin -Owners $UserAccount -ErrorAction SilentlyContinue
$i++
}
Finding Mail Contact Objects That Will Clash With Our New Guests
Before we can invite each SPO Guest in the CSV file into Entra ID, we should check if any of these SharePoint Guests also existing as a Mail Contact object in Exchange Online. A Mail Contact will clash with the invited guest and result in the guest existing in Entra ID but not existing in Exchange Online, which it should do. The next script will create a list of all Mail Contacts that match SharePoint Guests and store the LegacyExchangeDN value for each (so you can add it back to the Guest Mail User object that will be created in Exchange Online). The script will also delete the discovered Mail Contact object:
Connect-ExchangeOnline -UserPrincipalName $UserAccount
$results = @()
$AllGroups = Get-Group
$spoguests = Import-CSV -Path ".\SharePointGuestUsers.csv"
$i = 1; $total = $spoguests.Count
foreach ($spoguest in $spoguests) {
Write-Progress -Activity "Finding Mail Contacts" -Status "$i Completed" -PercentComplete (($i/$total)*100)
$exists = Get-MailContact $spoguest.UserEmail -ErrorAction SilentlyContinue
if ($exists -ne $null) {
Write-Host "SPO Guest user"$spoguest.UserEmail"( ID:"$spoguest.id") exists as a mail contact in Exchange Online"
If ($exists.IsDirSynced) {Write-Host -BackgroundColor Red "WARNING: This contact is synced from Active Directory"}
$existsContact = Get-Contact $exists
$GuestGroups = $AllGroups | where-Object {$_.Members -contains $exists} # Get all groups this contact belongs to
$results += [PSCustomObject]@{
UserEmail = $spoguest.UserEmail
LegacyExchangeDN = $exists.LegacyExchangeDN
HiddenFromAddressListsEnabled = $exists.HiddenFromAddressListsEnabled
FirstName = $existsContact.FirstName
LastName = $existsContact.LastName
Name = $exists.Name
DisplayName = $exists.DisplayName
IsDirSynced = $exists.IsDirSynced
Alias = $exists.Alias
MemberOf = $GuestGroups.Name -join ";"
}
Remove-MailContact $spoguest.UserEmail -Confirm:$false -ErrorAction SilentlyContinue
}
$i++
}
# Export LegacyExchangeDN of each deleted mail contact to CSV
$results | Export-Csv -Path "SharePointGuest-ExistingAsMailContacts.csv" -NoTypeInformation
Note that the above will not delete Mail Contacts that have synced from on-premises Active Directory/Exchange Server (via Entra Connect Sync). So if you also have a hybrid directory in place, and Mail Contact objects in Exchange Server and synced to Exchange Online, then run the above script again in Exchange Server to delete these Mail Contact objects as well.
Create Entra ID Guests To Replace The SharePoint Online Guests
Finally, once you have your list of SharePoint Online guest users and all matching Mail Contact objects deleted you can use the following script to import them into Entra as an Entra Guest object. Each of these users will be created in a pending state (Invitation State = “Pending Acceptance”) and a matching “Mail User” object will be created in Exchange Online. The next time the external user uses their sharing link to access SharePoint Online they will login as the Entra Guest account (so Conditional Access policies, if you have any that target guests, will take effect) and the user object in SharePoint Online will be updated to a Guest Object and not a SharePoint Guest Object.
You can create all these invitations in bulk without actually sending an invitation email to the recipient using the following script (Microsoft Graph PowerShell):
Connect-MgGraph -Scopes 'User.ReadWrite.All' -NoWelcome # -TenantID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$spoguests = Import-CSV -Path ".\SharePointGuestUsers.csv"
$exoContacts = Import-Csv -Path "SharePointGuest-ExistingAsMailContacts.csv"
$UserAccount= "admin@tenant.com"
$i = 1; $total = $spoguests.Count
foreach ($spoguest in $spoguests) {
Write-Progress -Activity "Inviting Entra ID Guests" -Status "$i Completed" -PercentComplete (($i/$total)*100)
$Body = @{
'InvitedUserEmailAddress' = $spoguest.UserEmail
'InvitedUserSponsors' = $UserAccount
'InviteRedirectUrl' = $spoguest.siteurl
'SendInvitationMessage' = $false
}
Write-Host "Inviting SPO Guest user"$spoguest.UserEmail" ( ID:"$spoguest.id")"
$newGuest = New-MgInvitation -BodyParameter $Body
$i++
}
Write-Host -BackgroundColor Yellow -ForegroundColor Black "These newly invited users where created on"@(Get-Date)
Connect-ExchangeOnline -UserPrincipalName $UserAccount
# If the SPO Guest was also a contact, update the Mail User object in Exchange Online with the previous Mail Contact properties
$i = 1; $total = $exoContacts.Count
foreach ($exoContact in $exoContacts) {
Write-Progress -Activity "Updating Mail Contacts" -Status "$i Completed" -PercentComplete (($i/$total)*100)
$Hidden = [Bool]::Parse($exoContact.HiddenFromAddressListsEnabled)
$LegDN = $exoContact.LegacyExchangeDN
Set-MailUser $exoContact.UserEmail -EmailAddresses @{Add="x500:$LegDN"} -HiddenFromAddressListsEnabled $Hidden -DisplayName $exoContact.DisplayName.Trim() -Alias $exoContact.Alias.Trim()
Set-User $exoContact.UserEmail -FirstName $exoContact.FirstName.Trim() -LastName $exoContact.LastName.Trim() -Confirm:$False
if ($exoContact.MemberOf -ne "") {
$Groups = $exoContact.MemberOf -split ";"
foreach ($group in $groups) {
Add-DistributionGroupMember $group -Member $exoContact.UserEmail -BypassSecurityGroupManagerCheck -ErrorAction SilentlyContinue
}
$i++
}
Note that due to an module loading order issue in PowerShell you cannot use the same session that you have loaded the PNP SharePoint module in. You can get around this by closing PowerShell and reopening it, or loading the Graph and Exchange modules before you loaded PNP PowerShell and calling one cmdlet with it, for example:
Connect-MgGraph -Scopes 'User.ReadWrite.All' -NoWelcome # -TenantID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Get-MgUser -UserId $UserAccount | Out-Null
Connect-ExchangeOnline -UserPrincipalName $UserAccount
# Continue with the PNP script above at this point
Enabling EnableAzureADB2BIntegration
From this point forward you now return the the main point of this article. Once you have created Entra guest accounts for SharePoint Guests, you can enable the EnableAzureADB2BIntegration setting to $true. Now, unlike the Message Center post in July 2025, external users will not get an error when trying to access their resources and instead access will happen seamlessly (apart from needing to consent to permissions, which you always need to do when accessing as a guest the first time). In a Multi-Tenant Organization scenario, the permission consent dialog can be skipped.
It is important to create all the new Entra Guests and then set EnableAzureADB2BIntegration to $true without any real gap. If you leave some time between these two actions (or between exporting the list of guests and creating a new guest) its possible that a user will share a document to another external user and so a new SPO Guest will be created. Once you have set EnableAzureADB2BIntegration to $true, new sharing events will result in Entra Guests created instead, but what you need to avoid is SPO Guests being created that you have not discovered and therefore no matching Entra Guest for these accounts will be made. If this happens, these users will be subject to the warning from Microsoft about needing the content reshared with the external user.
Set-SPOTenant -EnableAzureADB2BIntegration $true
Finally, to finish, I appreciate that we have possibly made hundreds or thousands of new Entra Guests via these scripts and csv files. My suggestion here is that if a user does not access the documents they had shared with them within (say) 3 to 6 months they are unlikely to do so further into the future and so you could delete all the Entra Guests that remain in a “Pending Acceptance” state that where created around the date and time that you ran the above invitation script. The above script echoes the date it was run on at the end of the script. Take a note of this and three to six months later delete pending invitation guests from your Entra ID to clean it up.
Photo by Pixabay: https://www.pexels.com/photo/black-rotary-phone-207456/
Leave a Reply