Figure 1: Signing into OWA with Rio in the background
According to Microsoft roadmap item 61054, the new image is “1% the size of the previous default image which will reduce bandwidth requirements and improve perceived page load times.” The change is intended to benefit users in bandwidth-constrained locations. Deployment starts in early April and full deployment should be achieved in early May.
Important to Tell Users
Normally the change in a background image isn’t worth commenting upon, but given the number of phishing attempts that trick unwary users into entering their credentials into a false site, it’s important that people are informed about the change and expect to see the new slimmed-down background image, which is startlingly different in its plainness (Figure 2).
Figure 2: The new slimmed-down Azure Active Directory sign-in
Do It Yourself Sign-In Backgrounds
A sign-in to Azure Active Directory has two phases: collect
the username and then collect the password. The screens displayed differ
depending on what you connect to:
If you connect using a generic URL for an Office 365 service, like outlook.office.com, the Azure Active Directory sign-in page first captures the username and then captures the password. This is the page that is changing.
If you connect using a domain variable, like outlook.office.com/office365itpros.com, Azure Active Directory checks if branding is specified for the tenant and applies it when displaying pages to collect the username and then the password.
Tenants that add customized elements for the sign-in page, usually some branding elements like logos or corporate colors, don’t need to recustomize their sign-in page after Microsoft updates the Azure Active Directory sign-in page.
Applying custom branding is easy to do. I created the effect shown in Figure in less than ten minutes. The trick is to select the graphics you need in advance and make sure that they are the right dimensions (1920 x 1080 pixels for the background, less than 300 KB).
Figure 3: A customized sign-in for Office 365
FIDO2 Keys
The availability of FIDO2 keys has authentication easier for me recently. I have keys for both USB and USB-C from eWBM (Goldengate G310 and G320) and Yubico. Both work really well as a second source for multi-factor authentication against Azure Active Directory. Instead of receiving a code via SMS, I plug a key into my PC to make Azure Active Directory happy…
Figure 4: FIDO2 keys for authentication
Understanding Azure Active Directory Authentication
All of which brings me to the topic of authentication. Understanding how the authentication flow works from the time that someone sees the sign-in screen through MFA challenges and so on to reach an application is important knowledge. As we move from the era of basic authentication (simple) to modern authentication (different), it’s a good idea to refresh what we know about this important topic.
A series of videos featuring Stuart Kwan, Principal Program
Manager in the Microsoft Identity Division explain how Azure Active Directory
authentication works. These videos are available:
When
Microsoft announced in March 2019 that mailbox auditing had been enabled by
default for Exchange Online, it seemed to be a good news story. Busy Office 365 administrators
would no longer have to enable auditing for new mailboxes to have mailbox audit
events flow into the Office 365 audit log (also known as the unified audit log).
The announcement told tenants they could “search and retrieve your audit
data withSearch-MailboxAuditLog.” This was a little strange as the
cmdlet searches mailboxes and not the audit log, but it seemed like a glitch
and not a problem. All was well.
The logic for enabling mailbox auditing by default is undeniable. In July 2018, when Microsoft announced the plan to enable mailbox auditing by default, they said: “Mailboxes generating audit records can be found in the Security & Compliance Center’s Audit Log interface, or in the mailbox audit log through the Search-MailboxAuditLog cmdlet.” Given that both interfaces access the Office 365 audit log, the only reasonable interpretation was that Exchange Online would transmit mailbox audit events to the Office 365 audit log.
Office 365 E5 Events Flow,
E3 Not So Much
As it turns
out, this only happens if mailboxes have Office 365 E5 licenses. Mailboxes with
Office 365 E3 licenses can have their events sent to the Office 365 audit log,
but only if the mailboxes are explicitly enabled by running Set-Mailbox
to set the AuditEnabled property to $True. With mailbox auditing enabled by
default, brand-new E3 mailboxes report AuditEnabled to be $True. No indication
exists that anything else must be done before audit events flow from these
mailboxes to the Office 365 audit log.
It’s quite a bizarre situation. In Figure 1, we’re working with a newly-created mailbox. Because mailbox auditing is enabled by default, when Get-Mailbox queries its audit properties, Exchange reports that AuditEnabled is True and the default audit set is present. If you run Set-Mailbox to disable auditing, PowerShell reports that “no settings have been modified.” That’s strange because we just updated AuditEnabled from True to False…
Figure 1: Investigating the audit status of a mailbox
Looking for Exchange Online Audit Events
I discovered the problem when I started to look for MailItemsAccessed events. These “crucial events” capture access to mailbox items. They are recorded when accounts have specific licenses (see below). I found that some records were captured for some accounts and not for others, which caused me to look at mailbox data captured in the audit log more closely.
Although mailbox auditing is enabled by default for my tenant and all mailboxes have the default audit configuration, I found that records existed for some accounts and not for others. For instance, when testing Outlook mobile’s support for delegate access, when the SendAs permission was used to send messages for one mailbox, an audit record turned up in the audit log, but not when SendAs was used for other mailboxes. So I went looking to find out why.
The Documentation Says…
On February 20, I read the documentation for mailbox auditing and found: “By default, only mailbox audit events for E5 users are available in audit log searches in the Security & Compliance Center.” This seemed incorrect to me because I could clearly see events for E3 users in audit log searches. I pointed this out to Microsoft, who subsequently amended the text to read “Although mailbox audit logging on by default is enabled for all organizations, only users with E5 licenses will return mailbox audit log events in audit log searches in the Security & Compliance Center or via the Office 365 Management Activity APIby default.” (Microsoft emphasis).
I’m reasonably experienced with Exchange. I know something about Office 365 too, and I have conducted many searches of the audit log. Yet nowhere did I ever see the advice that: “You can use audit log searches in the Security & Compliance Center or via the Office 365 Management Activity API after you’ve manually enabled mailbox auditing on the individual mailboxes.”
The Real Situation
To be charitable, Microsoft’s documentation is still confusing.
The situation is:
Mailbox audit events for Office 365 E5 accounts are always transmitted from Exchange Online to the Office 365 audit log (including the new MailItemsAccessed event, which only appear in E5 accounts). The same is true if the accounts have Microsoft 365 E5 licenses or Microsoft 365 E3 with the Compliance-add-on.
Mailbox audit events for Office 365 E3 accounts are not transmitted by Exchange Online even when mailbox auditing is enabled by default. You can force Exchange Online to transmit the events by running Set-Mailbox to set AuditEnabled to $True for E3 mailboxes.
Events will be in the Office 365 audit log for E3 mailboxes enabled prior to the introduction of mailbox auditing by default or if you manually enabled E3 mailboxes for auditing since.
In effect, the goodness of having mailbox auditing enabled by default has been stripped away because admins still need to take action to ensure audit capture of mailbox events. The situation isn’t helped by the way that Exchange Online uses the AuditEnabled property to report the audit status for mailboxes. This property should clearly show when audit events are being sent to the Office 365 audit log.
A cynic
might say that the perspective expressed in Microsoft’s documentation is almost
Jesuitical in its nit-picking. Yes, E3 mailboxes are enabled, but only for
storing audit records in the mailboxes. If you want Exchange to move audit
records from those E3 mailboxes to the audit log, you must enable them again.
No Data Loss for Audit Events
Mailbox audit events for Office 365 E3 accounts are not
lost. They remain stored in the Audits sub-folder of Recoverable Items in the
mailbox and can be found there using the Search-MailboxAuditLog cmdlet. They
just don’t go through the ingestion process to become events in the Office 365
audit log.
Enable Exchange Online Mailboxes Again
If you want Exchange Online to send mailbox audit events for all mailboxes to the Office 365 audit log, you must make sure that E3 mailboxes are manually enabled. Because you can’t depend on the AuditEnabled property to tell you when events for a mailbox will get to the audit log, you should run Set-Mailbox to enable auditing for all user and shared mailboxes. A script like this will make sure that auditing is enabled for all user and shared mailboxes:
A more sophisticated version of the script would select only
the mailboxes with E3 licenses, but no harm is done to process all mailboxes.
Process New Mailboxes
Remember that you will need to enable auditing when you add new mailboxes. That doesn’t sit well with Microsoft’s statement that after mailbox auditing is on by default, “you don’t need to do anything to manage mailbox auditing. (Figure 2).
Figure 2: No management necessary for mailbox auditing?
The Investigation Problem
A communications snafu caused by conflict between product
announcement and implementation might not seem that serious. After all, the
mailbox audit records are there to be found in the mailboxes. But the issue
from a compliance perspective is that investigators might have depended on data
being in the Office 365 audit log when they looked for information. It is,
after all, the definitive place to look for audit information within an Office
365 tenant and the Microsoft announcements about mailbox auditing by default point
to the audit log as the font of all knowledge.
You could say that people should check the latest
documentation before embarking on an investigation to know where to look for
data. That’s fine in theory, but who says “I must check that documentation
again” when in the middle of searching for evidence. Some important pieces of
information might have remained hidden in plain view in mailboxes when
investigators went looking, and that’s not right.
Other Audit Products Suffer Too
Another problem that arises is that when events don’t get
into the audit log, they are not picked up by other products which consume
audit data. For example, the activity feed for Microsoft’s own Office 365 Cloud
App Security (OCAS) comes from the audit log, so mailbox events that don’t
reach the audit log don’t get to OCAS, nor will they be processed by any other
repository which depends on a feed from the audit log.
The missing data could create a big compliance issue for
organizations who use repositories outside Office 365 to retain audit data for accounts
longer than the standard 90-day period allowed for Office 365 E3 accounts (365
days for E5 accounts). Because the mailbox events never reached the audit log,
they never got to the other repository either.
Pity to Compromise an Excellent Idea
Enabling mailbox auditing by default is an excellent idea.
It’s the right thing to do and aligns with Microsoft’s “commitment
to providing our customers with an easy-to-use set of security features.” (July 12,
2018 blog post).
Microsoft has sown confusion in Office 365 tenants by the way mailbox audit events are processed for E3 mailboxes. Let’s hope that they can resolve this issue as quickly as possible. In the meantime, remember to manually enable those E3 mailboxes to make sure the audit log gives a complete picture for all mailbox activities.
This is an example of the work the Office 365 for IT Pros writing team puts in to discover just what happens under the cover of Office 365. Subscribe and learn from what we discover.
Make Sure The Right People Access Your Exchange Online Mailboxes
One of the recommendations made in the Office 365 for IT Pros eBook is that tenant administrators should conduct periodic reviews of permissions assigned to mailboxes to ensure that the right people (other than the mailbox owners) have access. A recent request in the Microsoft Technical Community prompted me to look at the situation again to make sure that our advice was still accurate (it is).
Scripting a Report
I responded to the original question with some quick and dirty PowerShell but decided that a better job could be done. If you use the Get-MailboxPermission cmdlet to examine permissions on an Exchange Online mailbox, several types exist:
The mailbox owner (if you’re unsure, run Get-MailboxPermission with the -Owner parameter to see this entry).
Permissions needed by Exchange Online to access the mailbox for different purposes, such as removing items during retention policy processing. These entries appear like EXOForest\Organization Management, where “EXOForest” is the name of the Exchange Online forest hosting the mailbox.
An entry for “JitUsers” (Just in time access) assigned to Microsoft support personnel when they need access to the mailbox.
System entries like NT AUTHORITY\System and NT AUTHORITY\NETWORK SERVICE.
For the purpose of this exercise we don’t care about these permissions because they exist on all mailboxes. What we’re looking for are delegated permissions used to grant non-owner accounts access to the mailbox. Vasil Michev, our esteemed technical editor, has a script in the TechNet Gallery to report non-standard permissions, but there’s always room for another PowerShell answer to a problem.
My script (the full version is available on GitHub) selects user and shared mailboxes (those most likely to have extra permissions). For each mailbox, we extract the permissions and look for those assigned to other Office 365 accounts. We store details of these permissions into a list that is written out to a CSV file after all mailboxes are processed. Here’s the basic code:
# Quick and simple script to generate a report of non-standard permissions applied to Exchange Online user and shared mailboxes
# Needs to be connected to Exchange Online PowerShell with an administrative account to run
CLS
Write-Host "Fetching mailboxes"
$Mbx = Get-Mailbox -RecipientTypeDetails UserMailbox, SharedMailbox -ResultSize Unlimited | Select DisplayName, UserPrincipalName, RecipientTypeDetails
If ($Mbx.Count -eq 0) { Write-Error "No mailboxes found. Script exiting..." -ErrorAction Stop }
# We have some mailboxes, so we can process them...
CLS
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file
$ProgressDelta = 100/($Mbx.count); $PercentComplete = 0; $MbxNumber = 0
ForEach ($M in $Mbx) {
$MbxNumber++
$MbxStatus = $M.DisplayName + " ["+ $MbxNumber +"/" + $Mbx.Count + "]"
Write-Progress -Activity "Processing mailbox" -Status $MbxStatus -PercentComplete $PercentComplete
$PercentComplete += $ProgressDelta
$Permissions = Get-MailboxPermission -Identity $M.UserPrincipalName | ? {$_.User -Like "*@*" }
If ($Null -ne $Permissions) {
# Grab each permission and output it into the report
ForEach ($Permission in $Permissions) {
$ReportLine = [PSCustomObject] @{
Mailbox = $M.DisplayName
UPN = $M.UserPrincipalName
Permission = $Permission | Select -ExpandProperty AccessRights
AssignedTo = $Permission.User
MailboxType = $M.RecipientTypeDetails }
$Report.Add($ReportLine) }
}
}
$Report | Sort -Property @{Expression = {$_.MailboxType}; Ascending= $False}, Mailbox | Export-CSV c:\temp\MailboxPermissions.csv -NoTypeInformation
Write-Host "All done." $Mbx.Count "mailboxes scanned. Report of non-standard permissions available in c:\temp\MailboxPermissions.csv"
The CSV file is stored by user mailbox and then shared mailbox (you must use a calculated expression to sort by multiple properties when the first property is sorted in descending order).
As you can see from Figure 1, the resulting CSV reports a number of FullAccess permissions assigned to mailboxes. This isn’t an issue by itself because FullAccess permission is needed by delegates to have full control over a shared or user mailbox (as in the case of Outlook Mobile delegation). However, it’s important to review each assignment to understand if it is still valid and necessary. If not, the permission should be removed.
Figure 1: Reporting mailbox permissions
This report doesn’t include folder-level permissions assigned by Outlook. These permissions can be reviewed with the Get-MailboxFolderPermission cmdlet. To find all such permissions for a mailbox, you would need to run Get-MailboxFolderStatistics to generate a list of mailbox folders and then check each folder to see if any permissions exist. I’ll cover how to do this in a future post.
For many more examples of using PowerShell to manage Exchange Online and other Office 365 components, subscribe to the Office 365 for IT Pros eBook and find some hidden jewels.
Leveraging Get-AzureADSubscribedSku to Find Office 365 E3 Accounts
I love receiving suggestions from readers. After posting my note about Microsoft’s epic failure to communicate the real facts about mailbox auditing by default, Ofir Doron pointed out a good way to create a list of Office 365 E3 accounts that could then be used to enable mailbox auditing. You still need to take care of shared mailboxes, so I’ve updated the script to process both user and shared mailboxes.
The basis of the suggestion is to use the GUID of the Office 365 E3 license to identify accounts to check. The GUID is found by running the Get-AzureADSubscribedSku cmdlet from the Azure Active Directory module to return details of the SKUs (stock control units) available in the tenant. The EnterprisePack SKU in the list is Office 365, so the SKU identifier we need to use is 6fd2c87f-b296-42f0-b197-1e91e994b900. This value seems to be the same for all tenants.
We then process those mailboxes to make sure that they are
enabled for mailbox auditing.
Leveraging Knowledge Learned
Moving on from mailbox auditing, a delight of PowerShell is
that you can repurpose some new knowledge to solve other problems. In this case,
I want to create a report of license assignments in the tenant. In other words,
which accounts have been assigned the licenses returned by Get-AzureADSubscribedSku.
This script loops through all the license SKUs to find the accounts assigned each SKU. We put things together in a PowerShell list object and output it via Out-GridView (Figure 1). You need to be connected to Azure Active Directory before running the script.
Figure 1: Quick and Easy Office 365 License Report
Simple, easy, and a great example of how a little PowerShell can go a long way. And because the code is PowerShell and available to all, you can take it and amend it to match your needs.
Need more information about how to manage Office 365 licenses with PowerShell? Look no further than the Office 365 for IT Pros eBook. It’s packed full of examples.
Some time ago, I wrote about a script to report OneDrive for Business storage for users in an Office 365 tenant. As it turns out, the code is straightforward and only needs a few lines to grab the data from SharePoint Online and create the report.
The inevitable follow-up question is “can you create the same kind of report for SharePoint Online sites?” Due to the pressing needs of other topics, it’s taken me a while to get to this question. The answer is “absolutely!” even if the code is a little more complicated.
Why You Should Monitor SharePoint Online Site Storage
Difference Processing OneDrive and SharePoint Sites
OneDrive for Business sites are owned by one person. They
only come in one form. SharePoint Online sites come in a variety of forms
(team-connected, hub, communications, private channel, and so on) and can have
multiple administrators (owners).
In addition, when you run the Get-SPOSite cmdlet to fetch a list of sites, SharePoint Online optimizes for performance by not returning all properties. If you want to know about an “expensive” property, like the connected group for a team-enabled site, or the sensitivity label assigned to a site, you must use an explicit Get-SPOSite call to the site URL. All of which complicates matters a tad.
SharePoint Admin Center Option
The SharePoint admin center includes the option to Export details of Active sites (Figure 1), so you don’t have to write any PowerShell unless you want to.
Figure 1: Export Active Sites option in the SharePoint Online Admin Center
The fun in writing your own script is that you can format the report the way that you want and include extra processing, such as returning the list of owners for a site belonging to an Office 365 group or team.
Approaching the Script
Conceptually, the code is uncomplicated:
Fetch a list of sites in the tenant with Get-SPOSite -Limit All.
Check each site, and based on its template, decide if any extra processing is needed (for instance, for team-enabled sites, fetch details of the group owners).
Populate the report by writing out the assigned quota and storage used for each site, along with its URL and owners. In many cases, the assigned quota is 25,600 GB or 25 TB (the maximum storage assignment possible for a site).
After all sites are processed, generate the report.
You can download the full script from GitHub. All suggestions about potential improvements are welcome. I’ve tested the script against 300 sites and it ran without problems in just over 2 minutes. Your mileage might vary.
Lingering Sites
I also discovered that SharePoint Online sometimes returns a
team site without an associated group. This situation might occur when a group has
been deleted and the site is retained due to an Office 365 retention policy. I
suspect it’s an edge case but included some code to handle the problem.
Report Output
The script output is a CSV file. You can slice and dice the content of the CSV to do whatever analysis is needed. If you prefer to view the report online, pipe the data to Out-GridView, which makes it easy to get a quick overview of the report, sort by different headings, and so on (Figure 2).
$Report | Out-GridView
Figure 2: The output of the SharePoint site storage report
Need more information about managing SharePoint Online with PowerShell? Check out the content of the Office 365 for IT Pros eBook!
The snippets were just that: bits of code. These bits are valuable because the nature of PowerShell and the way the community works is that you can always (try to) improve what’s gone before. As it happens, I found much the same code in examples in my Exchange Inside Out 2010 book (still available from Amazon). In any case, the point was that knowing all about FullAccess permissions assigned to users is all very well, but to get a full perspective of the permissions set on mailboxes, you should include details of the sending permissions as well.
Three Exchange Online Cmdlets Needed
It would be nice if Exchange returned all mailbox permissions with a single cmdlet, but three are needed:
Get-ExoMailbox/Get-Mailbox: Returns a list of users with the right to Send as Behalf Of for a mailbox.
Get-ExoMailboxPermission/Get-MailboxPermission: Returns permissions granted on the mailbox, like FullAccess.
Get-ExoRecipientPermission/Get-RecipientPermission: Returns a list of users with SendAs permission for the mailbox.
The script uses the REST-based cmdlets but it’s easy to convert the calls to use the older Remote PowerShell cmdlets if you prefer.
The reasons why three cmdlets are needed are hidden in the mists of time and go back to the first implementation of PowerShell in Exchange 2007. The situation is unlikely to change now.
The Combined Script
The script is shown below. It’s a modified version of the previous script and you’ll need to connect to the Exchange Online Management module with an administrator account to run it. You can also download a copy from GitHub.
# ReportMailboxSendPermissionsMailboxes.PS1
# Quick and simple script to generate a report of non-standard permissions applied to Exchange Online user and shared mailboxes
# Needs to be connected to Exchange Online PowerShell with an administrative account to run
# V1.0 16-Mar-2020
# https://github.com/12Knocksinna/Office365itpros/blob/master/ReportMailboxSendPermissionsMailboxes.PS1
CLS
Write-Host "Fetching mailboxes"
$Mbx = Get-ExoMailbox -RecipientTypeDetails UserMailbox, SharedMailbox -ResultSize Unlimited -PropertySet Delivery -Properties RecipientTypeDetails, DisplayName | Select DisplayName, UserPrincipalName, RecipientTypeDetails, GrantSendOnBehalfTo
If ($Mbx.Count -eq 0) { Write-Error "No mailboxes found. Script exiting..." -ErrorAction Stop }
CLS
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file
$ProgressDelta = 100/($Mbx.count); $PercentComplete = 0; $MbxNumber = 0
ForEach ($M in $Mbx) {
$MbxNumber++
$MbxStatus = $M.DisplayName + " ["+ $MbxNumber +"/" + $Mbx.Count + "]"
Write-Progress -Activity "Checking permissions for mailbox" -Status $MbxStatus -PercentComplete $PercentComplete
$PercentComplete += $ProgressDelta
$Permissions = Get-ExoRecipientPermission -Identity $M.UserPrincipalName | ? {$_.Trustee -ne "NT AUTHORITY\SELF"}
If ($Null -ne $Permissions) {
# Grab information about SendAs permission and output it into the report
ForEach ($Permission in $Permissions) {
$ReportLine = [PSCustomObject] @{
Mailbox = $M.DisplayName
UPN = $M.UserPrincipalName
Permission = $Permission | Select -ExpandProperty AccessRights
AssignedTo = $Permission.Trustee
MailboxType = $M.RecipientTypeDetails }
$Report.Add($ReportLine) }}
# Grab information about FullAccess permissions
$Permissions = Get-ExoMailboxPermission -Identity $M.UserPrincipalName | ? {$_.User -Like "*@*" }
If ($Null -ne $Permissions) {
# Grab each permission and output it into the report
ForEach ($Permission in $Permissions) {
$ReportLine = [PSCustomObject] @{
Mailbox = $M.DisplayName
UPN = $M.UserPrincipalName
Permission = $Permission | Select -ExpandProperty AccessRights
AssignedTo = $Permission.User
MailboxType = $M.RecipientTypeDetails }
$Report.Add($ReportLine) }}
# Check if this mailbox has granted Send on Behalf of permission to anyone
If (![string]::IsNullOrEmpty($M.GrantSendOnBehalfTo)) {
ForEach ($Permission in $M.GrantSendOnBehalfTo) {
$ReportLine = [PSCustomObject] @{
Mailbox = $M.DisplayName
UPN = $M.UserPrincipalName
Permission = "Send on Behalf Of"
AssignedTo = (Get-ExoRecipient -Identity $Permission).PrimarySmtpAddress
MailboxType = $M.RecipientTypeDetails }
$Report.Add($ReportLine) }}
}
$Report | Sort -Property @{Expression = {$_.MailboxType}; Ascending= $False}, Mailbox | Export-CSV c:\temp\MailboxAccessPermissions.csv -NoTypeInformation
Write-Host "All done." $Mbx.Count "mailboxes scanned. Report of send permissions available in c:\temp\MailboxAccessPermissions.csv"
The output is a CSV file sorted by mailbox type (user mailboxes then shared mailboxes) and mailbox name. You can also pipe the output to Out-GridView (Figure 2) to quickly sort and review the results.
Figure 1: The full set of Exchange Online mailbox permissions
A Note About Get-ExoMailbox
The call to Get-ExoMailbox is a good example of how you need to pay attention to upgrading scripts from the older Get-Mailbox cmdlet. Get-ExoMailbox speeds access to data fetched from Exchange Online by forcing coders to specify the properties that they need to process. In this case, we need the Delivery property set (to access the GrantSendOnBehalfTo property) as well as the DisplayName and RecipientTypeDetails properties, which are specified individually.
As always, feel free to customize the script code to your heart’s content. Happy scripting!
Exchange Online is a well-known product at this point. Even so, a new development can throw up something that you don’t know about, just like the property sets used by the EXO cmdlets. Stay current by subscribing to the Office 365 for IT Pros eBook and let us do the heavy lifting of staying updated.
I’m always interested in speeding up scripts. The new Exchange REST cmdlets speed things up by being more efficient at fetching large sets of mailboxes and other objects. The effect isn’t obvious when dealing with less than a hundred objects, but if you must work with ten or fifty thousand mailboxes, you’ll see objects processed at least three times faster. That is, if you master some of the quirks of the new cmdlets when you convert scripts.
Faster Loops
A post about PowerShell ForEach loops by MVP “Adam the Automator” attracted my attention when it stated that the ForEach method (introduced in PowerShell V4) is “considerably faster and is noticeably so over large sets.” In this context, faster means that the method processes objects in a loop more quickly than the classic ForEach-Object cmdlet. The method exists for arrays and collection objects, so it’s easy to see how this might be used to process sets of mailboxes, groups, teams, sites, or other Office 365 objects.
Looping Through Office 365
Groups
I decided
to test the theory with a real-world test. I choose to create a script to
create a report of the conversation or chat activity level in Office 365
Groups. The normal approach is to form a set of groups using the Get-UnifiedGroup
cmdlet and then loop through each group to retrieve information about the
group. The information for the report is stored in a PowerShell list object.
Because it
fetches a lot of information, Get-UnifiedGroup is a “heavy” cmdlet.
Another way of saying this is that Get-UnifiedGroup is a slow pig of a
cmdlet, so it needs all the speed help it can get. The test set was 200 Office
365 Groups.
Here’s the script I used, wrapped with Measure-Command to record the processing time.
$Groups = Get-UnifiedGroup -ResultSize Unlimited
$OldData = measure-command {
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file for report
$NumberTeams = 0
ForEach ($Group in $Groups) {
$LastItemAddedToTeams = "Never"; $TeamEnabled = $False
$Stats = Get-MailboxFolderStatistics -Identity $Group.Alias -FolderScope Inbox -IncludeOldestAndNewestItems
$TeamChatData = (Get-MailboxFolderStatistics -Identity $Group.Alias -IncludeOldestAndNewestItems -FolderScope ConversationHistory)
ForEach ($T in $TeamChatData) { # We might have one or two subfolders in Conversation History; find the one for Teams
If ($T.FolderType -eq "TeamChat") {
$NumberOfChats = $T.ItemsInFolder
If ($NumberOfChats -gt 0) {
$NumberTeams++
$LastItemAddedToTeams = Get-Date ($T.NewestItemReceivedDate) -Format g
$TeamEnabled = $True}}
}
$ReportLine = [PSCustomObject] @{
Group = $Group.DisplayName
Members = $Group.GroupMemberCount
Guests = $Group.GroupExternalMemberCount
NumberOutlookItems = $Stats.ItemsInFolder
LatestOutlookItem = $Stats.NewestItemReceivedDate
TeamsEnabled = $TeamEnabled
NumberTeamsItems = $NumberOfChats
LastestTeamsItem = $LastItemAddedToTeams }
$Report.Add($ReportLine) }
Write-Host $Groups.Count "Office 365 Groups processed;" $NumberTeams "have been used with Teams"}
Scripting the ForEach
Method
When you use the ForEach method, you need to change the references to the object being processed. You’ll see this in the change from $Group.Alias in the original script to $_.Alias in the updated version. In other words, we’re using a pipeline variable instead of a named variable.
$NewData = Measure-Command {
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file for report
$NumberTeams = 0
$Groups.ForEach( {
$LastItemAddedToTeams = "Never"; $TeamEnabled = $False
$Stats = Get-MailboxFolderStatistics -Identity $_.Alias -FolderScope Inbox -IncludeOldestAndNewestItems
$TeamChatData = (Get-MailboxFolderStatistics -Identity $_.Alias -IncludeOldestAndNewestItems -FolderScope ConversationHistory)
ForEach ($T in $TeamChatData) { # We might have one or two subfolders in Conversation History; find the one for Teams
If ($T.FolderType -eq "TeamChat") {
$NumberOfChats = $T.ItemsInFolder
If ($NumberOfChats -gt 0) {
$NumberTeams++
$LastItemAddedToTeams = Get-Date ($T.NewestItemReceivedDate) -Format g
$TeamEnabled = $True}}
}
$ReportLine = [PSCustomObject] @{
Group = $_.DisplayName
Members = $_.GroupMemberCount
Guests = $_.GroupExternalMemberCount
NumberOutlookItems = $Stats.ItemsInFolder
LatestOutlookItem = $Stats.NewestItemReceivedDate
TeamsEnabled = $TeamEnabled
NumberTeamsItems = $NumberOfChats
LastestTeamsItem = $LastItemAddedToTeams }
$Report.Add($ReportLine) } )
}
A Potential Speed Increase
My tests
showed that the ForEach method is faster than classic loops. The speed increase
I observed was in the-5% range over a set of ten runs. The average for the
classic ForEach loop was 8 min 30 sec while the ForEach method came in 8 min 6
sec, a gain of 24 seconds.
Two hundred
groups are a reasonable test set, but it could be that a more worthwhile speed
boost happens when processing larger sets. Your mileage might vary.
You’ll have to make your mind up if it’s worthwhile changing your code to achieve a 5% increase. The changes needed to use the ForEach method are not big and it shouldn’t take long to make the switch and test. It’s the kind of thing to consider the next time you need to refresh scripts, perhaps at the same time as you update scripts to use the new Exchange REST-based cmdlets.
We write a lot of PowerShell scripts to test code we use as examples for the Office 365 for IT Pros eBook. Benefit from working code examples to get real work done by subscribing to the eBook. It’s unique in many ways!
On February 20, I wrote about the topic of generating corporate auto-signatures for OWA. It is easy to create good-looking autosignatures and store them in user mailboxes for OWA to apply (Outlook is a different proposition). The logical question that follows is how to stop users changing their corporate-generated autosignature?
Historically, Role-based access control (RBAC) has been the go-to method when control is needed over an OWA feature. Microsoft introduced RBAC to Exchange 2010 as the control mechanism for access to features. RBAC is used today in both Exchange Online and Exchange on-premises and variations are used to control access to options in admin portals like the Microsoft 365 admin center and Microsoft 365 compliance center.
OWA and RBAC
Settings in a user role assignment policy control the elements of the user interface OWA displays to mailboxes covered by the policy. Basically, if the policy allows OWA to display the user interface for users to edit and save their autosignature, they see the option in OWA settings (Figure 1). But if we change the policy to remove the ability to update signatures, they won’t.
Figure 1: OWA settings to create and update a mailbox autosignature
User Role Assignment Policies
Office 365 tenants come with an out-of-the-box user role assignment policy (called “Default Role Assignment Policy”) which enables access to all OWA settings. Mailboxes are assigned this policy by default unless an administrator changes the assignment.
You can edit the default role assignment policy to remove access to autosignatures, but it’s usually a better idea to create a new role assignment policy and edit that, just in case you make a mistake and remove access some features that you want to keep.
Tailoring Roles
Before we create a new policy, we must create a new RBAC role to block autosignatures. Exchange breaks down the ability of users to access OWA features into a set of roles, assembled to form a policy. Each role is composed of a set of role entries. Think of a role entry as a definition of a PowerShell cmdlet and its parameters. Once a user is assigned a role, they can run the cmdlets defined in the role entries. For instance, if a role entry includes the Set-Mailbox cmdlet and some (but maybe not all) of its parameters, the user can run Set-Mailbox and use the set of allowed parameters. They run the cmdlet by using an OWA option or in PowerShell.
The connection between RBAC and cmdlets means that we must know what cmdlet is used to update autosignatures if we want to block it. As explained in my previous article, the Set-MailboxMessageConfiguration and several of its parameters are used to manipulate autosignatures. To stop users updating autosignatures, we must remove their access to those parameters.
Creating a Customized Role
The two commands shown below create a new management role based on the out-of-the-box MyBaseOptions role (which control many OWA settings). The new management role inherits all the settings from MyBaseOptions, so we then amend the settings by removing the parameters used by Set-MailboxMessageConfiguration to update autosignatures.
When users are assigned a policy containing the customized role, they will be unable to update signatures. However, we need to take one more step to stop OWA displaying the user interface for signatures. We do this by removing the right to run the Get-MailboxMessageConfiguration cmdlet. Without this cmdlet, OWA can’t fetch details of existing autosignature settings from the mailbox. Here’s the code to remove the entry from the role:
To make the new role effective, we must include it in a user role assignment policy and assigned to mailboxes. This code creates a new policy composed of our customized role and all the other default roles normally assigned to users through a policy. For instance, the MyProfileInformation role allows users to edit details of their profile while MyDistributionGroups allows users to create and edit distribution lists.
The block should become effective 15 minutes or so after the mailbox is updated with the new role assignment policy. Log into the mailbox with OWA and open the options pane. Select the View all Outlook settings link to open the fly-out window with access to all settings and go to the Compose and reply section. You should see that OWA can no longer edit the autosignature settings (Figure 2).
Figure 2: No signature settings available in OWA
The Downside of Removing the Get-MailboxMessageConfiguration Cmdlet
Eagle-eyed readers will notice that some other settings have disappeared from the Compose and reply section. This is because the Get-MailboxMessageConfiguration cmdlet returns many settings like the message format to use for new messages, the font and font size to use, and the color of text. Settings are also affected in other sections, like Layout (message organization). When you remove the ability of a user to run Get-MailboxMessageConfiguration, they lose access to everything the cmdlet returns, not just autosignatures.
The same problem would not arise if OWA used Set-MailboxMessageConfiguration to control the display of the autosignature setting. Set-MailboxMessageConfiguration is a granular cmdlet with individual parameters to control different settings, so you can trim parameters to control access to specific settings.
OWA Mailbox Policy Solves the Problem
Although RBAC doesn’t work as well as expected, OWA mailbox policies are another way to tackle the problem. OWA mailbox policies control many (but not all) aspects of how the client work. You can work with OWA mailbox policies through the Permissions section of the Exchange admin center (EAC) or PowerShell. Figure 3 shows how to disable autosignatures by unchecking the email signature box in the features section of a policy. You can either update an existing OWA mailbox policy or create a new one (better for testing).
Figure 3: Disabling OWA signatures with an OWA mailbox policy
If you want to use PowerShell, you need to set SignaturesEnabled to $False in the policy. Here’s how to create and update an OWA mailbox policy with PowerShell:
New-OWAMailboxPolicy -Name "Block Access to autosignatures"
Set-OWAMailboxPolicy -Identity "Block Access to autosignatures" -SignaturesEnabled $False
Whether you use EAC or PowerShell to block signatures in an OWA mailbox policy, don’t forget to assign the modified policy to the mailboxes you want to control. You can assign the policy by updating mailbox properties with EAC, but it’s likely that you’ll want to update multiple mailboxes and that’s when PowerShell shines. The command to assign an OWA mailbox policy to a mailbox is:
Set-CASMailbox -Identity Kim.Akers -OWAMailboxPolicy "Block Access to autosignatures"
Again, wait for 15 minutes to allow the Exchange Online servers to pick up the new policy and then test that the block is effective.
The OWA mailbox policy is enough to block users from changing autosignatures. You don’t need to update RBAC role assignments unless you also want to stop users running the Set-MailboxMessageConfiguration cmdlet in a PowerShell session. You can make your mind up how likely it is that users will decide to master PowerShell to mess with corporate autosignatures.
RBAC Fails but Another Method Succeeds
RBAC is a powerful mechanism for controlling user access to individual features. In Exchange Online, RBAC depends on the underlying cmdlets and parameters. Usually, RBAC is the best way to stop user access to features, but in this situation, the limitations of the Get-MailboxMessageConfiguration cmdlet created some unfortunate side-effects when implementing a block on autosignatures. Fortunately, OWA mailbox policies came to the rescue and implemented the block we wanted.
This is an example of how the probing minds of the Office 365 for IT Pros writing team tease out issues. Benefit from their work by subscribing to the Office 365 for IT Pros eBook!
The Lobby’s the First Stop for External Meeting Participants
In Office 365 notification MC209349 published on April 14, Microsoft announced a change to the default meeting policy to enforce lobby entry for external users. Roadmap item 63388 says:
“We are updating the default meeting policy to automatically enforce lobby for all external users who join a Teams meeting, including attendees joining via Audio Conferencing. This policy change will only impact those tenants who have not modified the default meetings policy.”
The change is rolling out to tenants now.
Teams Lobby
The “lobby” referred to in the notification is a temporary holding place for people waiting to join a meeting. Authenticated users can allow people waiting in the lobby to join a meeting. Control over who can enter a meeting without going through the lobby is set by the meeting policy assigned to the organizer’s account. If they want, the organizer can override the policy for specific meetings.
Changes Made to the Default Meeting Policy
Technically, Microsoft is updating two settings affecting participants and guests in the default meeting policy. Figure 1 shows where the changes are made in the Teams Admin Center.
Figure 1: Teams meeting policy settings for participants and guests
Behind the Scenes
MC209349 refers to the changes in PowerShell terms, where the edits are made with the Set-CSTeamsMeetingPolicy cmdlet:
AutoAdmittedUsers is set to everyoneInCompany. This means that internal users can join Teams meetings without going through the lobby. However, external users – including those from federated organizations – must wait for admittance.
AllowPSTNUsersToBypassLobby is set to False. This makes sure that dial-in users cannot bypass the lobby.
To check the values of the default meeting policy afterwards, run:
Get-CSTeamsMeetingPolicy -Identity Default
See this page for more information about settings in Teams meetings policies.
Federated Organizations
Teams external access dictates the federation between your tenant and other organizations. This could be through open federation, where you allow communications from any other tenant or closed federation, where you allow federation with tenants based on an allow or block list (but not both).
Customized Default Meeting Policies Unaffected
If you customized the default meeting policy for your tenant in the past, this change won’t overwrite or otherwise affect those customizations. Default Teams policies remain under Microsoft’s control unless a tenant wants to change a default policy. At that point, the policy is copied to the tenant and the change is applied to the copy. A tenant-customized version of a default policy always takes precedence over Microsoft’s version, which is why this change only impacts tenants who have never changed the default meeting policy.
The Office 365 for IT Pros eBook has lots of information about Teams meetings. And best of all, as things change, we update the book and make new versions available to our subscribers.
Without much fanfare, the Teams Admin Center now boasts a new Manage apps page under Teams apps (Figure 1). The new page gives Teams administrators visibility over the apps published to the Teams app store by Microsoft, third-party developers, and custom apps developed in the tenant.
Figure 1: Managing Teams apps
Teams app setup policies and app permission policies have been around for almost a year to give tenants the ability to assign users a set of apps for the app navigation bar and control whether users can access Microsoft, third-party, or custom apps. Allowing control over apps on an individual app basis builds out the Teams app management framework.
Allowing or Blocking Individual Apps
The basic idea for the app inventory is that tenant administrators can review apps and decide which they want to allow tenant users to access. By default, all apps are allowed, so the task is to review apps and block those which don’t seem appropriate or useful for the tenant. Blocked apps can’t be installed by users and won’t be displayed in the app navigation bar if included in an app setup policy.
Figure 2 shows details of a typical app (chosen at random). The important information show here is:
Publisher: The organization responsible for creating and maintaining the app.
Version: The current version of the software.
Categories: For example, Productivity or Business Management. The publisher chooses which categories an app belongs to.
Certification: The highest level of certification is Microsoft 365 certified app, which means that Microsoft has reviewed and approved the app against a set of security, compliance, and data handling standards. Wrike and Abode Sign are examples of Microsoft 365 certified apps. When an app is marked as publisher attestation, it means that the app’s publisher certifies the app based on a self-assessment report. Many apps are not currently certified, including some from Microsoft.
Capabilities: Where in Teams the app can be used. If Team, the app can be installed into a team channel. Other categories include Personal, meaning that a user can install the app for their personal use, and Group chat, meaning that the app can be installed to be shared by participants in a group chat.
App Id: Each app is assigned a unique identifier (GUID) when it is published to the Teams app store. The identifier is the same across all tenants.
Figure 2: Details of an individual Teams app
It’s surprising that just a few apps are currently certified by Microsoft or self-certified. Presumably becoming certified is something recommended by Microsoft to app developers, so perhaps it just takes time to go through the process.
If you don’t want an app to be available in the tenant, move the App status slider from On to Off.
Org-Wide App Control
The Manage apps page also includes org-wide app settings for apps. These settings are tenant settings to:
Allow third-party apps: If On, third-party apps can be installed by users. Turning this setting to Off prevents users installing third-party apps and limits them to apps provided by Microsoft.
Allow new third-party apps published to the store by default: If On, any new third-party apps published to the Teams app store are visible in the tenant’s Teams app store and are available to users, if the app permission policy assigned to their account allows third-party apps. If Off, new third-party apps do not appear in the app store.
Allow interaction with custom apps: Custom apps are those developed for your organization. If this control is On, users can install and access custom apps. If Off, they cannot (this setting also disables outgoing webhooks). This setting is Off by default for GCC tenants.
Lots of things change in Teams and elsewhere in Microsoft 365 all the time. Stay informed and up-to-date by subscribing to the Office 365 for IT Pros eBook and let us keep an eye on developments for you.
Message Center notification MC210158 (April 22) announced the availability of several improvements in the usage reports available in the Microsoft 365 admin center. Roadmap item 59845 covers analytics for the Office 365 ProPlus apps (now Microsoft 365 enterprise apps) while item 63209 covers a new card to summarize activities most used by employees working from home. This update also includes calendar events in the Exchange Online usage report. The new reports are rolling out now and are discussed in this blog post.
Remote Working Activities
Microsoft has added a card called Understanding Remote Work Elements to the home page of usage reports (Figure 1). The activities summarized in the card are those Microsoft give a good heartbeat of activities of people working from home and might help organizations understand how communications and collaboration have changed in the transition away from office-based work. For instance, email and Teams interactions have probably replaced some in-person encounters in the workplace.
Figure 1: Microsoft 365 Admin Usage Reports now show a Remote Work card
The activities also include Yammer (for some reason, Microsoft is fascinated by Yammer while most customers are not) and, more importantly, SharePoint Online and OneDrive for Business. When you’re working from home, organizations want documents stored on repositories that can be accessed anywhere. In this context, the OneDrive sync client is very important.
Like any report, it’s important to put the data in context. For example, you might conclude that Yammer activity has exploded in my tenant based on the reported 390.5% growth. That is, until you understand the low base and the fact that during the reporting period I was testing the transition of my Yammer network to Microsoft 365 native mode.
You can’t customize the data shown on the remote working card. It is what it is.
Active Users Report
The active users report helps tenants understand the overall usage pattern across a range of workloads (Figure 2). Three views are available:
Users: The number of active users for each workload.
Activity: The number of recorded activities for each workload (for instance, Exchange Online messages read, sent, and accessed by users).
Services: The overall breakdown of active and inactive users in the tenant per workload.
Figure 2: Office 365 Active Users Report
See this page for more information about using the Active Users report.
ISV Reporting Still Better
The standard usage reports are OK, especially in small to medium tenants, and it’s good to see these improvements. The fact remains that ISV products like Quadrotech Radar Reporting & Analytics invariably offer better flexibility when it comes to analyzing, graphing, and reporting Office 365 usage and other metrics about tenant operations. Both Microsoft and ISV products use the Graph as the single source of wisdom for usage information, so apart from being free, there’s no special magic in the reports available in the Microsoft 365 admin center.
Reporting and auditing is a big topic if you want to understand what’s happening in your tenant. It takes up a complete chapter in the Office 365 for IT Pros eBook.
Interrogating SharePoint and OneDrive Document Version History
A recent question asked how to use the SharePoint Online PnP PowerShell module to extract the version history of a document. The PnP (Patterns and Practices) module is a set of cmdlets designed to handle complex SharePoint provisioning and management scenarios. If you get to know PnP, you probably like it, but the nature of PnP is that its interaction with objects is more complicated than other PowerShell modules.
The usual reason why people want to look at the version history for a document is to know who made a change to its content. Given how autosave captures document updates, the number of versions available for a document stored in SharePoint Online or OneDrive for Business can be large (Figure 1).
Figure 1: Version history for a SharePoint Online document
Office 365 Audit Log is an Alternative
If you’re not used to PnP, you might find it easier to extract information about document updates from the Office 365 audit log. Every time a document is uploaded or updated in a SharePoint Online or OneDrive for Business document library, an audit event is captured that is later ingested into the Office 365 audit log. If we know the name of a document, it’s easy to search the audit log with the Search-UnifiedAuditLog cmdlet and find its audit records.
Searching for Document Change Audit Events
The PowerShell script below uses the $FileName variable to hold the name of the document to search for. If events occurred for this document over the last 90 days, the search should find events to record the initial upload of the document to the library (FileUploaded) and subsequent updates (FileModified) and views (FileAccessed). If the AutoSave feature is enabled for the document, multiple update records can accumulate over a short period. As is normal with audit records, a lot of interesting information is found in the AuditData property.
$FileName = (Read-Host "Enter file name to search")
$Records = (Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date).AddDays(+1) -Operations FileModified, FileAccessed, FileUploaded -ObjectIds $FileName -ResultSize 1000)
If ($Records.Count -eq 0) {
Write-Host "No audit records found for file names beginning with" $FileName }
Else {
Write-Host "Processing" $Records.Count "audit records..."
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($Rec in $Records) {
$AuditData = ConvertFrom-Json $Rec.Auditdata
$ReportLine = [PSCustomObject]@{
TimeStamp = $Rec.CreationDate
User = $AuditData.UserId
Action = $AuditData.Operation
SiteUrl = $AuditData.SiteUrl
Site = $AuditData.SourceRelativeUrl
File = $AuditData.SourceFileName
IpAddress = $AuditData.ClientIP
App = $AuditData.UserAgent }
$Report.Add($ReportLine) }}
Listing the Results
After analyzing the audit records, we can list the set of actions found for the document:
If your accounts have Office 365 E5 or Microsoft 365 E5 compliance licenses, audit records are available for 365 days. However, 90 days is usually enough to find out who made a change to an important document. Unless the change was overlooked and has only just been noticed!
Practical information about using PowerShell to solve common Office 365 administrative problems is a hallmark of the Office 365 for IT Pros eBook. Subscribe today and learn from our experience!
Sometimes it pays to read the release notes for a product. The Teams release notes often hold nuggets of information that don’t show up in an Office 365 Message Center notification, such as the May 1 note about channel analytics:
Channel metrics are now included in team analytics. Along with this addition comes new metrics like a running tally of posts and replies for each team and channel. We’ve also increased the time period for data to 90 days.
The Teams release notes are updated every couple of weeks or as new features appear.
Upgraded Teams Analytics
Teams analytics first appeared in the desktop and browser clients in November 2019 as a useful way for team owners and members to know if the team is active (Figure 1). Data is available to guest users too. Analytics aren’t available in the Teams mobile clients.
Figure 1: Analytics for a team
What’s changed is that Microsoft has:
Increased the time periods available for Teams reporting out to 90 days from the original 28-day limit. You can now select from 7-, 30-, and 90-day windows. The information comes from the Microsoft Graph and is the same that can be retrieved through the Activity API.
Added a drop-down list of channels to allow users to choose to view data for an individual channel (including private channels). The default view available through the Manage team option continues to show data for all channels. A team can support up to 200 channels and it’s likely that some channels will become underused over time (or are always underused). Being able to see what level of activity occurs in a channel is a useful way to decide if the channel is needed and trim some “channel debris.”
Added a new Analytics link for channels through the Manage channel option.
Analytics Data Available
The data available for channel covers the number of topic and replies posted. Team analytics track active users over time, the split between tenant users and guests and members and owners, the number of apps installed in the team, and meeting activity. The data doesn’t include messages posted to channels by Office connectors (like an RSS feed) or those that come in through email.
The Teams desktop and browser clients don’t include a way to export the analytics data. However, you can export data covering team-level activities through the Analytics section of the Teams Admin Center. The reports section of the Microsoft 365 admin center also includes Teams usage reports and Teams data is also included in the Microsoft 365 usage analytics dashboard (Power BI).
Reporting is one of our favorite topics in the Office 365 for IT Pros eBook. Everyone wants to know what data is available and how to include it in reports!
The OneDrive for Business service description (13 May 2020) lays out how much OneDrive storage Microsoft makes available to users based on their license type. In a nutshell:
Frontline users (Office 365 F3):2 GB
Small to medium plans (like Microsoft 365 Business Premium): 1 TB
SharePoint Online Plan 1 and OneDrive for Business Plan 1: 1 TB
Enterprise E1: 1 TB.
Other enterprise plans and SharePoint Online Plan 2: “Beyond 1 TB, to unlimited”
The “unlimited” tag is interesting because it implies that Microsoft will allow a properly licensed user to consume as much OneDrive for Business storage as they want, with the caveats that OneDrive “is designed to serve the needs of individual users” and “storage of data other than an individual user’s work files, including system back-ups and departmental and organizational level data, is not supported, nor is the assignment of a per user license to a bot, department, or other non-human entity.”
Setting a Default Storage Quota for OneDrive
Documents, files, and photos can certainly occupy a lot of storage, but “unlimited” really doesn’t mean what normal human beings might think. It’s more like an all-you-can-eat buffet where the physical capacity of the human stomach will eventually impose a practical limit. OneDrive’s unlimited quota is practically limited by being doled out in chunks as users need storage.
When someone’s Office 365 account is provisioned and the account has a OneDrive license, the account is assigned the default storage quota set by the tenant. The quota can be set in the OneDrive admin center (Figure 1) or PowerShell.
Figure 1: Setting a tenant default for OneDrive for Business storage quota
The minimum default storage quota is 1024 GB (1 TB). As Figure 1 shows, you can increase it to 5120 GB (5 TB). You can go higher, but rather bizarrely, the OneDrive admin center doesn’t confirm that a new value is set, nor does it signal an error if you insert a higher value (like 10240 GB). Instead, perhaps because it doesn’t want to offend, OneDrive simply ignores the attempt to set a new storage quota and reverts to the highest possible value for the default (5 TB).
One thing to be careful about is that the OneDrive admin center uses gigabytes to set storage quotas while the Set-SPOTenant cmdlet uses megabytes. To set a 5 TB default storage limit in PowerShell, we run:
Set-SPOTenant -OneDriveStorageQuota 5242880>
Don’t bother trying to go past 5 TB. OneDrive will blithely ignore your request and the limit will stay at 5 TB.
Assigning New Quotas to Existing Accounts
The default storage quota is assigned to new accounts. If the account doesn’t have a license which supports the assigned quota, OneDrive will automatically downgrade the available quota to the maximum allowed by the license. With that in mind, we can assign the new 5 TB storage quota to accounts like this:
# Get all OneDrive sites
Write-Host "Fetching OneDrive site information..."
$Sites = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'" | Sort StorageUsageCurrent -Desc
$TotalOneDriveStorageUsed = [Math]::Round(($Sites.StorageUsageCurrent | Measure-Object -Sum).Sum /1024,2)
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($Site in $Sites) {
$SiteOwners = $Null ; $Process = $True; $NoCheckGroup = $False
$SiteNumber++
$SiteStatus = $Site.Title + " ["+ $SiteNumber +"/" + $Sites.Count + "]"
$UsedGB = [Math]::Round($Site.StorageUsageCurrent/1024,2)
# And write out the information about the site
If ($Process -eq $True) {
$ReportLine = [PSCustomObject]@{
URL = $Site.URL
Owner = $Site.Title
QuotaGB = [Math]::Round($Site.StorageQuota/1KB,0)
UsedGB = $UsedGB
PercentUsed = ([Math]::Round(($Site.StorageUsageCurrent/$Site.StorageQuota),4).ToString("P")) }
$Report.Add($ReportLine)}}
# Now generate the report
$Report | Export-CSV -NoTypeInformation c:\temp\OneDriveConsumption.CSV
Moving Past Towards Unlimited
Five terabytes are nice, but it’s not unlimited. Possibly because of the bad experience of when OneDrive consumer supported unlimited storage (think of large movie libraries being uploaded), Microsoft forces tenants to go through support to have their storage boosted. You’ll have to:
Have at least one account in the tenant get within 10% of the 5 TB limit (being at 90% of quota is explicitly mentioned in the OneDrive service description).
Tell the support agent that you want the quota increased from 5 TB to 25 TB.
Expect some backwards and forwards while Microsoft support digests the request. Point to the “unlimited” statement in the OneDrive service description and be politely insistent if necessary.
Eventually Microsoft will enable a storage quota increase behind the scenes. The increase enables a new 25 TB limit for all accounts, and you will be able to set the new limit by running Set-SPOSite to set a quota of 26214400 (25 TB).
If someone reaches 90% of 25 TB, a further support request will result in single-user SharePoint Online team sites with 25 TB quota.
Tracking down nuggets of information about how Office 365 works in practice is hard. Stay updated with the Office 365 for IT Pros eBook and let us do the work for you.
Understanding Events in Office 365 Audit Log the First Step
Generating a report about some aspect of Office 365 is all very well, but it doesn’t lead to much unless there’s some action that can be easily taken due to the reported data. Take the report on Exchange Online SendAs and other permissions. It’s nice to know which accounts hold permissions over different mailboxes, but what will you do with that information?
In a small tenant, it might be easy to review the data and identify problems, like someone keeping Send As permission for a shared mailbox long past the time when their job mandates this access. In a medium to large tenant, you can slice and dice the report data to highlight issues, but it’s a lot harder to pinpoint definite problems.
Using Technology to Highlight Items
Microsoft is adding a lot of machine learning and artificial intelligence to Office 365 at present. Taking that as a hint, we can use technology to help filter the report data and identify the accounts to focus on. And best of all, this is easy to do in PowerShell.
The output from the script is a CSV file listing all the Send As, Full Access, and Send On Behalf Of permissions assigned to accounts. The first step is to read in the data from the CSV file, filtering items so that only SendAs records are loaded into an array.
Grabbing Data from the Office 365 Audit Log
The next step is to find a way to check each SendAs assignment against usage. The easiest way I know is to search the Office 365 audit log for SendAs events. Data is kept for 90 days for Office 365 E3 accounts (but only if their mailboxes are enabled). Data is kept for 365 days if an account has an Office 365 E5 license. Either way, I think 90 days is enough on the basis that if someone hasn’t used their right to impersonate another user or shared mailbox to send email in the last three months, maybe they don’t need that permission and it can be removed.
We can collect the SendAs events for the last 90 days by running the Search-UnifiedAuditLog cmdlet, unpacking the AuditData content in each audit event, and storing the data. Fortunately, we already have a script to do the job, which stores its output in another CSV file.
Comparing Audit Data with Permissions
A few lines of code later, we have the SendAs audit events loaded and we’re ready to start checking. The basic idea is to go through the assignments and check each against the audit data to see if the permission has been used. If it has, we store some usage details (last time and number of uses), and if it hasn’t, we note that fact too.
Hey Presto! After running through the permissions, we have a filtered list of accounts who haven’t used their assigned Send As permissions in the last three months and another set who have. You can review the assignments by piping the analyzed data to Out-GridView (Figure 1) or use the output CSV file for further processing.
Figure 1: Reviewing SendAs permissions that aren’t being used
You can pick up a copy of the script to analyze and filter SendAs records from GitHub. Remember that you need the other scripts to fetch SendAs records from the Office 365 audit log and report mailbox permissions to provide the two inputs.
Humans Decide Next Step
At this point, the script finishes and it’s up to the tenant administrators to decide what to do about the defunct permissions. Perhaps you want to send a polite email to users to tell them that you plan to remove the permission in a week’s time, or maybe you just go ahead and remove the permission on the basis that if anyone misses it, they’ll scream.
This is a great example of how to put together PowerShell scripts as building blocks for a solution. The code isn’t all that complex. It’s simply a matter of knowing where to find the data and how to use it. Isn’t that always the case?
Create Teams or Skype for Business Online Meetings by Default
Office 365 Notification MC213856 published on May 20 tells us that users will soon be able to configure OWA and Outlook mobile clients so that any meeting created is an online event. Given the current need to work from home, this change reflects the transition of many meetings from in-person events to online.
The feature only works when an account is connected to an Office 365 tenant with Teams or Skype for Business Online configured for online meetings. Unsurprisingly, it doesn’t work with other online meeting providers like Zoom and GoToMeeting. According to Microsoft 365 roadmap item 58132, an add-in is due in late 2020 to allow third-party online meetings to be scheduled from Outlook mobile.
Three roadmap items are covered by the announcement: 63383 (OWA), 63625 (Outlook for iOS), and 63628 (Outlook for Android). There’s no news at this point if Outlook desktop will get the same feature.
Making Online Meetings
Today, users must take an explicit action to create an online meeting. For example, in OWA, they set a slider to mark the meeting as a Teams or Skype for Business event. When this happens, the client retrieves a URI from the online provider pointing to the online “space” used for the meeting and inserts the URI into the meeting request. Other properties of the meeting request are updated to allow participants to join the meeting online.
Microsoft will release a client update for OWA at the end of May with Outlook mobile clients being updated over the June-July period. When available, the updates allow users to control whether they want to make every meeting an online event. In the meantime, some PowerShell settings are already available to control the feature at a tenant and mailbox level.
Tenant Online Meeting Setting
The Set-OrganizationConfig cmdlet manages the Exchange Online tenant configuration. The OnlineMeetingsByDefaultEnabled setting is False, meaning that online meetings are not the default. Updating the setting to True makes online meetings the default, and clients that support the setting will use it unless it is overridden by a mailbox-specific setting.
To override the organization setting on a mailbox level, run the Set-MailboxCalendarConfiguration cmdlet. The mailbox setting has the same name, but it’s Null by default, meaning that the organization setting takes precedence. You can set the value to $True to force the use of online meetings or $False to make “normal” (non-online) meetings be the default. Here’s a typical example of updating the calendar configuration for a mailbox.
If you do nothing, the organization setting will be False, and clients will work as they do today unless and until users update their calendar settings. The need to update the organization setting depends on the type of company, its meeting culture, and the prevalence of online meetings (using Teams and Skype for Business).
If you use another online meeting provider, leave the organization setting alone and don’t tell users about the calendar settings. On the other hand, if you’re deep into Teams or Skype for Business, maybe the right idea is to switch to online meetings by default. It all depends on how people work in your company.
Stay updated with developments inside Office 365 by subscribing to the Office 365 for IT Pros eBook.
Microsoft recently made an interesting change to the automated support handling capabilities of the Microsoft 365 admin center to handle requests for Exchange Web Services (EWS) throttling to be lifted for up to 90 days without human intervention.
Migrations from other platforms often use EWS to move information to Exchange Online mailboxes. When large amounts of data flow from the other platform, EWS throttling is likely to be imposed to conserve resources. It was always possible in the past to create a support request to ask Microsoft to lift throttling for EWS temporarily to allow migrations to proceed and Microsoft would invariably grant the request. Now, tenants can request throttling to be lifted through a simple automated process. Here’s how:
Go to the Help (?) section of the Microsoft 365 admin center.
Click the Need Help icon.
Enter “EWS throttling” as the search phrase.
Click Run tests when asked to check your environment (Figure 1). Essentially, the tests check what EWS throttling applies to the tenant.
Figure 1: The Support Assistant wants to run diagnostics to test the tenant for EWS throttling
The support assistant checks the tenant settings and concludes that EWS is throttled (the normal situation). You’ll then be offered the chance to update the settings to the tenant EWS policy to lift throttling for 30, 60, or 90 days.
Select the number of days you’d like to adjust the policy for and then Update Settings (Figure 2).
After a short delay, the support assistant should confirm that the settings have been changed.
Figure 2: The Support Assistant prepares to lift EWS throttling restrictions
The new setting will be effective for the tenant in about 15 minutes and you should then be able to start migration transfers at full speed.
The Support Assistant is only able to automatically lift throttling for EWS-based migrations. It can’t deal with migrations based on other protocols, such as IMAP4 (like migrations from Gmail).
I’m bemused by the solutions people proposed when asked about Teams backup. It’s reasonable to consider backing up any IT service and given the recent growth in Teams usage I have seen several requests from people looking to understand what they can do to secure Teams data. The reasons why you might want to backup a cloud service include:
Securing critical data against loss caused by an external attack (including ransomware and other malware).
Stopping rogue administrators removing or altering information.
Moving copies of data to external repositories to ensure people can work if the cloud service is unavailable for an extended period.
These are classic reasons long cited in the on-premises world. However, in the cloud, things are different because you typically don’t have the same level of access to data that you enjoy on-premises.
No Backups in Office 365
Apart from SharePoint Online, Microsoft doesn’t backup Office 365 services. Microsoft relies on its technology to protect data, so if you want a backup, you must use a third-party service. There are many services available and generally there are no problems backing up or restoring mailbox and document data. Backup for Exchange Online and SharePoint Online have roots in on-premises technology and the methods to move data in and out of mailboxes and sites are well understood. APIs, albeit never designed for cloud backups, are available, and everything works. Well, everything works until sensitivity labels and encrypted content are introduced into the mix, but that’s another discussion.
Teams is a Cloud App
Teams is a different matter. Unlike Exchange and SharePoint, Teams is a product of the cloud. It does not exist on-premises and no one ever developed backup interfaces for Teams. But more importantly, Teams is built on top of multiple Office 365 and Azure services. The data in these services is interconnected and dependent. Restoring a mailbox is simple compared to the reconstruction of a team, complete with all its channels, tabs, conversations, meetings, and so on.
Claims of Backup Vendors
Some backup vendors claim their products cover Teams. Most base their claim on copying the Teams compliance records stored in group and personal mailboxes in Exchange Online. Although it is possible to copy Teams compliance records like any other Exchange mailbox data, this is not a backup. It doesn’t even come close for two reasons:
No API exists to restore Teams compliance messages into a Teams channel conversation or personal chat. You could read the compliance records and use Graph API calls to write new messages into channel conversations and chats, but this is not a true restore because the newly-written items would be dated differently to the original and lack all the data not copied to compliance records.
Any backup vendor who insists that they deliver Teams coverage through Exchange Online exhibits a woeful ignorance of Teams technology. If a vendor doesn’t understand the strengths and weaknesses of their product, you shouldn’t use them.
The second (less common) approach is to use the beta Teams migration API to backup Teams data. I covered how BitTitan uses the API for cross-tenant migration in a Petri.com article last August (AvePoint and Quadrotech use the same API for their tenant to tenant migration products). Not much has happened since to develop the API since and the same problems exist. One glaring issue is the inability to handle Teams personal chats.
Failure to Deal with Full Scope of Teams
Both the migration API and Exchange-based backups fail to take the wide spectrum of Teams interconnected data into account. Backing up one piece of information secures that data, but that data might be useless if other connected data is not copied and available.
Table 1 lists some of the connected data used by Teams. It’s not a definitive list and other data might be needed (like OneNote) to create a comprehensive backup of Teams in an Office 365 tenant. The purpose of the list is to illustrate the wide array of user and system data consumed by Teams. If you want to backup Teams, you need to understand what data is used with Teams in your tenant. Once you know that, you can figure out how to solve the backup problem.
Teams data
Location
Backup Situation
Personal and group chat messages
Azure CosmosDB.
No backup API available.
Channel conversations
Azure CosmosDB.
No backup API available.
GIFs used in Teams messages.
Teams CDN.
No backup API available.
Documents shared in personal and group chats
OneDrive for Business.
Backed up with OneDrive for Business.
Documents shared in Teams channels (Files).
Document libraries and folders in SharePoint Online sites
Backed up with SharePoint Online.
Private channels
Separate set of SharePoint Online sites.
Backed up with SharePoint Online (if the backup product copies these sites)
Email sent to Teams channels via connector.
Azure CosmosDB and SharePoint Online,
Backed up with SharePoint Online (messages posted to channels are not backed up).
Messages posted to channels via Office connectors.
Azure CosmosDB.
No backup API available.
Teams calendar.
User and group mailboxes (Exchange Online)
Backed up with Exchange Online data.
Teams meeting recordings
Stream.
No Stream backup API available.
Teams Wiki
SharePoint Online.
Teams compliance records
Exchange Online mailboxes
Backed up with Exchange Online data.
Planner
Azure
No Planner backup API available.
Teams audit data.
Office 365 audit log.
Can be extracted with Search-UnifiedAuditLog (PowerShell).
Third-party apps.
Teams app store and third-party repositories.
Responsibility of third-party apps.
Teams membership and group object.
Azure Active Directory.
Can be backed up by reading information from Azure AD (membership of Teams private channels is not in Azure AD).
Teams policies and settings.
Azure.
Some data can be backed up by reading policies and settings with PowerShell.
Teams usage data.
Microsoft Graph.
Can be read from the Graph.
Whiteboard used in meetings
Microsoft Whiteboard service.
No backup API available.
Table 1: Teams Data is Spread across Microsoft 365 Services
In some cases, a workaround might compensate for the lack of a backup API. For instance, you could download every video from Stream and copy the video to a backup site. You could use the Graph API to copy Plans, and so on.
The problem with workarounds is that they often lack automation and the ability to scale. How many videos does a tenant store in Stream? How many are generated daily? How many plans are created and how many tasks are added, changed, or removed daily? And whiteboards?
Restore an Even Bigger Issue
Backup vendors want to sell products. Their access to your data is limited by the available APIs, so no great mystery exists as to why a comprehensive backup for Teams is so difficult to achieve. And once you have some backup data, consider that restoring Teams is even more problematic.
For more information about Office 365 backups, read Chapter 4 of the Office 365 for IT Pros eBook. Our approach can be summarized as “understand what you need to backup and why before you commit to an external backup service.”
Stream Doesn’t Support Office 365 Retention Policies
Usage of Microsoft Stream is very high at present, largely driven by storage of Teams meeting recordings and Teams Live Events. This is goodness, but the increased use is revealing some flaws in Stream, such as the lack of support for Office 365 retention policies. At their Microsoft Stream Under the hood session at the Ignite 2019 conference, the development group promised that Stream will support retention policies “in 2020.” The need to keep the service running at a time of high demand might have stopped progress in this space.
When a video owner deletes a video, it goes into the Stream recycle bin and remains there for 30 days. This period allows owners to recover videos deleted in error. After the period elapses, Stream removes the video and the content is irrecoverable.
Exploring the Stream Recycle Bin
Although Stream administrators can see videos deleted by anyone in the tenant in the Stream recycle bin (Figure 1), a danger exists that a video which should be kept might slip through the cracks and be deleted. People in the compliance world worry about this kind of thing because someone could try to remove evidence of a policy violation by deleting recordings of Teams meetings where misdoings were discussed.
Figure 1: Deleted videos in the Stream Recycle Bin
While waiting for Microsoft to bring Stream into the full Office 365 compliance framework (spanning retention policies, labels, and holds among other features), it’s possible to build a review mechanism to have someone check videos in the recycle bin to figure out if they should be kept. It’s a form of manual disposition, to use Microsoft’s term for a manual review of an item before it is disposed of.
To achieve the goal, I looked in the Office 365 audit log for StreamDeleteVideo events, which are logged when an owner deletes a video. It doesn’t take much to search for these events over the last 30 days and extract the relevant data, such as the name of the video and who deleted it.
Generating an HTML Report
After processing the audit events, I create an HTML report file (Figure 2). To help identify videos that are approaching deletion, the days since deletion and days remaining are calculated by subtracting the timestamp of the audit event from the current date. Someone creative could take other approaches to highlight entries in the list, such as using different colors for videos approaching their final deletion.
Figure 2: The HTML report about Stream deleted videos
Emailing the Report
Generating a report is one step, making sure that its content is reviewed and actioned is another. To help things along, the script emails a copy to someone selected to review videos and decide if any should be kept. Figure 3 shows the report as it appears in OWA.
Figure 3: The emailed report about Stream deleted videos viewed in OWA
Emailing reports is easy with the Send-MailMessage cmdlet. In this case, the HTML content is imported as the message body, we add message properties such as the recipients, sender, and subject, and send it off. Using Send-MailMessage in this way is a good example of the kind of script that will need to be updated when Microsoft removes basic authentication support for SMTP AUTH connections.
The script can be accessed in GitHub. Feel free to create your own version and let us know what improvements you make by posting a comment here.
The Office 365 for IT Pros eBook includes a full chapter about Stream. Like everything else in the book, the Stream content is reviewed and updated when changes happen.
Microsoft recently updated the Microsoft 365 admin center with several useful changes to improve the Groups section of the portal. Most of the changes relate to Office 365 Groups (sorry, now Microsoft 365 Groups). It’s entirely possible that these changes have escaped your attention, so let’s cover them briefly.
Restore Deleted Groups
Given the popularity of Microsoft 365 Groups as the membership service for applications like Teams, Yammer, and Planner, it’s inevitable that some mistakes will be made when removing groups or that an important group will be allowed to expire. The ability to restore deleted Microsoft 365 groups was first introduced through PowerShell cmdlets in early 2017. Soon afterwards, the feature appeared in the Exchange admin center.
Now you can restore groups in the Microsoft 365 admin center. Go to Groups and open the Deleted groups section. Any groups that have not exceeded their 30-day soft-deleted retention period are listed (Figure 1).
Figure 1: Listing deleted groups in the Microsoft 365 admin center
To restore a group, select it and either:
Use the Restore group option in the group header.
Click the group name to bring up the details pane, which has some basic information about the (display name, description, and email addresses) and click the Restore group button.
Both options perform the same processing to restore the deleted group. After a short delay, the group object is restored in Azure AD and begins the process of notifying the associated workloads to reconnect. It takes a little while for resources like the SharePoint site, a plan, or a team to be reconnected, but eventually everything comes together.
Selecting Licensed Teams Owners
Restoring deleted groups is a relatively big feature. A smaller, but still nice, feature is the way that the Add group wizard checks and displays if assigned groups owners have Teams licenses (Figure 2). Why is this important? Well, if you add someone who isn’t licensed for Teams as a group owner and then team-enable the group, that owner won’t be able to manage the team. And ownerless teams are bad.
Figure 2: Making sure that assigned group owners can use Teams
The nagging doubt in my mind is that this feature might not work so well in very large tenants when many accounts can be nominated as group owners, but I’m sure this has been tested.
Improvements in Groups Section
The Groups section in the Microsoft 365 admin center has been nicely refreshed. Some of the changes have been around for a while, but I’ll note them here. In Figure 3 we see:
The ability to edit the name and description of a selected group. This is a shortcut to calling the group details pane where you make the changes.
Edit email addresses. Those of us who like PowerShell would run Set-UnifiedGroup to do this, but normal people will find it much easier to change the primary SMTP address of a group or add new proxy email addresses here.
See the set of Teams-enabled groups. The Teams icon tells all.
Filters to show different kinds of groups. We sometimes forget the humble distribution list, but these objects are managed here too.
The sync status property tells you where a group is homed. In this case they’re all in the cloud.
Figure 3: Improved UI in the Groups section of the Microsoft 365 admin center
Usefully, you can export the filtered set of groups to a CSV file. This kills off many PowerShell scripts written to do the same job (using cmdlets or Graph calls), but there’s nothing wrong with that.
There’s nothing earth shattering in anything that Microsoft has done and it’s likely that the changes help them reduce the number of support calls that flow in to ask how to do these operations. Changes that help both Microsoft and tenants are a good thing and collectively the changes make group management just that bit easier for those who don’t manage these objects very often. Best of all, Restore Deleted Groups is useful for even hard-bitten professionals. I’ll let you decide if you fall into that category.
Changes like those described in this post add value but they can slip by without you noticing. This is why we monitor what’s going on inside Office 365 and update the Office 365 for IT Pros eBook to make sure that our subscribers are always in the know.