Understanding External Access to Documents in an Office 365 Tenant (Part 1)

Office 365 with Teams

What Office 365 Tells Us About Sharing

A recent exercise to analyze the potential leakage of information from an Office 365 tenant following a hacking attack posed the question: “with whom outside the company do we share documents and files?” It’s a great question, and it’s one that has no obvious answer. The usage data for SharePoint Online available in the standard Office 365 reports tells us who shares documents inside and outside the tenant (Figure 1), but it tells us nothing about what they share.

Office 365 Sharing Admin Center
Figure 1: Office 365 Sharing report (image credit: Tony Redmond).

Email Sharing

Before we consider how to discover more about the sharing habits of tenant users, we need to understand how sharing happens within Office 365.

Sharing has always been a big part of email. Users attach files to messages and send to all and sundry on an as-needed basis. Message tracking logs have been part of Exchange for twenty-odd years, but (and rather bizarrely) have never captured attachment names. A transport agent might do the trick, but you cannot install transport agents within Exchange Online. Content searches can also find messages sent with attachments, but this is an activity best done during a formal investigation when you have some knowledge about what you are looking for.

Given that users will continue to share documents by email, if you want to protect sensitive documents, you have a choice of data loss prevention rules, message encryption (applied by users or by transport rules), or rights management templates. Later this year, Microsoft will unify Office 365 classification labels and Azure Information Protection labels to allow automatic application of a protection template when users assign labels to messages.

Document Sharing

Getting back to documents, when you think about the volume of sharing that occurs within Office 365, you can only conclude that more sharing will happen over time. We encourage users to keep their files online in OneDrive for Business and SharePoint Online libraries instead of using local storage (or antiquated network shares). Microsoft has worked hard to make the sharing mechanism simple and easy to understand. Users get further encouragement from Outlook and OWA to use of smart attachments, where links to documents replace copies of files. And when documents live online, all sorts of interesting things can happen, like real-time co-authoring or Autosave (which can be a boon and a problem).

But the biggest influence on the increased use of SharePoint Online and OneDrive for Business is Teams, and to a lesser degree, Office 365 Groups. Both applications, which are only available in the cloud, replace the complexity of SharePoint’s browser interface with the simple idea that Files are where you put files, including those you want to share with others. Groups has its own take on Files, but either way, easier and more approachable interfaces have helped SharePoint usage grow.

In terms of numbers, Microsoft says that over 200,000 organizations now use Teams. Well, they all use Files and SharePoint Online, and I bet they all do some sharing.

SharePoint Sharing Mechanics

SharePoint has a long history of being able to share with external users. Two kinds of sites exist within Office 365: old-style and modern. The modern sort use Office 365 Groups to manage membership while the old-style manage permissions based on user accounts.

In either case, the same kind of controls limit sharing outside the tenant, including the ability to share with external users known to the tenant directory. In other words, Azure Active Directory guest user accounts. You can add guest users through the Azure Active Directory portal or by issuing an invitation to an email address outside your tenant through Teams or Office 365 Groups.

Checking for Sharing

SharePoint Online synchronizes information about tenant and guest users from Azure Active Directory to its own directory (SPODS). SharePoint then uses that information to manage site membership for old-style sites. We can check this information with the Get-SPOUser cmdlet (to read all users) or Get-SPOExternalUser cmdlet (just guests).

Using Get-SPOUser

As an example, here’s some PowerShell using the Get-SPOUser cmdlet to scan down through all sites in a tenant and report guest users.

$Sites  = Get-SPOSite -Limit All
$Report = @()
ForEach ($Site in $Sites) {
        Write-Host "Examining" $Site.Url    
	$Users = Get-SPOUser -Limit All -Site $Site.Url -ErrorAction SilentlyContinue
        ForEach ($U in $Users) {
          If ($U.LoginName -like "*#EXT#*" -or $U.LoginName-like "*urn:spo:guest*") {
               $ReportLine = [PSCustomObject][Ordered]@{
                User            = $U.DisplayName
                UPN             = $U.LoginName
                Site            = $Site.Url }
              $Report += $ReportLine  }  
     }}

We use two tests to check for guest users. The first looks for guest accounts in the tenant directory. The second is for accounts that gain access through time-sensitive codes created to share without creating a guest account, which is the new approach taken by SharePoint Online and OneDrive for Business since late 2017

The output is an ordered array, so we can look at it in different ways. For instance, to we can sort by user principal name to see what sites each external user can access.

$Report | Sort UPN, Site | Select UPN, Site

UPN                                            Site
---                                            ----
brianr_test.com#ext#@tenant.onmicrosoft.com    https://tenant.sharepoint.com/sites/exchangegoms
brianr_test.com#ext#@tenant.onmicrosoft.com    https://tenant.sharepoint.com/sites/exchange
brianr_test.com#ext#@tenant.onmicrosoft.com    https://tenant.sharepoint.com/sites/O365Grp-Grp

A record generated for one-time access looks like this:

urn:spo:guest#[email protected]          https://tenant.sharepoint.com/sites/seattlecoffee

One thing this exercise revealed for my tenant is that if you remove an external user from an Office 365 group, SharePoint does not remove their user profile from this site. Apart from making the output of Get-SPOUser unreliable for any site managed by an Office 365 Group, this doesn’t matter too much because the group controls access to the site.

Using Get-SPOExternalUser

We must be able to use Get-SPOExternalUser then to extract a reliable list of external people who have access to our SharePoint sites? Well, here’s some code using Get-SPOExternalUser. This cmdlet is funky because it only returns 50 objects. This might have been OK for on-premises SharePoint where site sharing is limited, but it’s not acceptable for SharePoint Online where an Office 365 Group can have up to 2,500 members. In any case, here’s some code to scan for external SharePoint users.

$Sites = @()
$Sites = (Get-SpoSite -Limit All | ? {$_.SharingCapability -ne "Disabled" -and $_.Template -eq "Group#0"})
$Report = @()
Write-Host "Processing" $Sites.Count "sites..."
ForEach ($Site in $Sites) {
   Write-Host "Site:" $Site.Url "Title:" $Site.Title "Template:" $Site.Template
   $ExtUsers = $Null
   Try { 
       for ($i=0;;$i+=50) {
            $ExtUsers = (Get-SpoExternalUser -Site $Site.Url -PageSize 50 -Position $i -ErrorAction Stop | Select DisplayName, Email, WhenCreated)
        }}
   Catch {
   }
   # $ExtUsers = (Get-SpoExternalUser -Site $Site.Url -PageSize 50 | Select DisplayName, Email, WhenCreated)
   If ($ExtUsers.Count -ne 0) {
   ForEach ($E in $ExtUsers) {
   $ReportLine = [PSCustomObject][Ordered]@{
           User            = $E.DisplayName
           Email           = $E.EMail
           Group           = $Site.Title
           Site            = $Site.Url
           Count           = $ExtUsers.Count
           WhenCreated     = $E.WhenCreated
           Type            = "SPOSite"
        }
      $Report += $ReportLine }         
      } 
}

Once again, we generate an ordered array. Get-SPOExternalUser outputs the creation date of the guest user account in the tenant. It would be nicer if it told us when a user gained access to a site.

$Report | Sort Email, Site | Format-Table User, Site, WhenCreated

Email          Site                                                     WhenCreated
-----          ----                                                     -----------
Vasil Michev   https://tenant.sharepoint.com/sites/brk3001              29/09/2016 23:22:09
Vasil Michev   https://tenant.sharepoint.com/sites/exchangegoms         29/09/2016 23:22:09
Vasil Michev   https://tenant.sharepoint.com/sites/exchange99           29/09/2016 23:22:09
Vasil Michev   https://tenant.sharepoint.com/sites/mailfilterpatent     29/09/2016 23:22:09

Get-SPOExternalUser suffers from the same problem as Get-SPOUser – it reports external access to a site when that access vanished some time ago because a guest user left the membership of an Office 365 Group.

SharePoint Online Cmdlets Need Some Work

My attempt to find out who outside the tenant has access to information in SharePoint sites is somewhat successful. However, neither cmdlet we used reports correct information when a site is under the control if an Office 365 Group. That’s not good and Microsoft should fix the underlying synchronization problem.

We need a different approach to crack this problem. We’ll discuss a workable solution in Part 2 of this series.

Follow Tony on Twitter @12Knocksinna.

Want to know more about how to manage Office 365? Find what you need to know in “Office 365 for IT Pros”, the most comprehensive eBook covering all aspects of Office 365. Available in PDF and EPUB formats (suitable for iBooks) or for Amazon Kindle.

p