Last Update: March 13, 2021
As part of the development of the Office 365 for IT Pros eBook or to support the creation of blog posts, we write a lot of PowerShell scripts. The code is intended to demonstrate how things work or how to accomplish tasks. Some years ago, we started to put the scripts in our GitHub repository. Feel free to download and use the scripts with the caveats that:
- These are not production-ready scripts. You’ll need to do some work to prepare them for use in your environment. For instance, the scripts come with scant if any error handling. We also don’t tend to write code in functions because we’re trying to show how to get work done without attempting to educate everyone to be professional programmers.
- Always distrust PowerShell code downloaded from the internet. Never run anything in production until you’ve tested the code.
- We write the code when we are investigating a topic. Sometimes we go back and revisit code if we need to, such as someone prompting us with a question. We do not always use the latest and greatest technique in scripts to perform certain tasks, such as the fastest way to find individual groups. We keep programming recommendations updated in the Office 365 for IT Pros eBook.
Now that you understand the rules of the game, here are details of some of the scripts in the repository (feel free to improve our code). We’ve noted where you can find more information about the concepts illustrated in a script in an Office 365 for IT Pros or Petri article. Most of the scripts are referenced in the Office 365 for IT Pros eBook.
Add Teams to the Microsoft 365 Groups Expiration Policy
AddTeamstoGroupsExpirationPolicy.ps1: Shows how to add all the teams in a tenant to the Groups expiration policy.
Analyze SendAs Audit Events Against Permissions
AnalyzeSendAsAuditData.ps1: Analyzes the audit records created for SendAs actions against the permissions which exist on shared and user mailboxes to figure out which permissions are used and which are not. See this post for more information.
Archive Microsoft 365 Groups (and Teams)
ArchiveMicrosoft365Groups.PS1: Microsoft has a method to archive inactive Teams. We illustrate another approach in this script, which puts groups into an archive state by removing all the members except a special archive account. See this post for more information.
Report SharePoint Online Activity for a User
AuditSPOOperationsByUser.PS1: This script shows how to use the events from the Office 365 audit log to generate a report about the SharePoint Online activities for individual users (like creating and editing documents, sharing files, and so on). See this post for more information.
Analyze Partially Indexed Items
ComplianceSearchPartiallyIndexedItems.ps1: It’s useful to understand how well indexing copes with the documents and files loaded into Office 365. This is a version of a Microsoft script to analyze the partially indexed items in a tenant. See this post for more information.
Convert Exchange Distribution List to a Microsoft 365 Group
ConvertDLtoO365Group.PS1: This script converts an Exchange Online distribution list to a Microsoft 365 Group. Not all lists can be converted and this isn’t a perfect example of how to do the job, but it works.
Decrypt Protected SharePoint Online Documents (Graph Version)
DecryptProtectedSPODocuments-Graph.PS1: This script shows how to use a mixture of PowerShell and Microsoft Graph API calls to find the protected (encrypted) documents in a SharePoint document library and decrypt them by removing the assigned sensitivity label.
Decrypt Protected SharePoint Online Documents (PnP Version)
DecryptProtectedSPODocuments.PS1: This version of the script shows how to use the SharePoint PnP module to find documents in a SharePoint library which are then decrypted. The Graph version (above) is more powerful, but this does the job. The code was used as an example in this article.
Retrieve Messages from the Service Communications API
FetchServiceMessagesGraph.ps1: Creates a report of service notifications (the kind posted to the Microsoft 365 message center) for new updates and changes to workloads. The data is fetched using the Service Communications API.
Find Send and Search Records
FindCrucialSendAndSearchRecords.PS1: Examples of using the Search-UnifiedAuditLog cmdlet used in Chapter 21 of the Office 365 for IT Pros eBook.
Find Inactive Distribution Lists
FindInactiveDLs.PS1: An example of how to check if distribution lists are in active use. The message trace data stored by Exchange Online is used to check if a distribution list is active (defined as being used in the last 10 days, which is how long message trace data is available online). See this post for more information.
Report MailItemsAccessed Audit Records
FindMailItemsAccessedAuditRecords.PS1: Microsoft defines MailItemsAccessed as a high-value audit event. Accounts need Office 365 E5 licenses before Exchange Online logs these events for a mailbox. This script extracts audit log data and reports it for MailItemsAccessed events. See this post for more information.
Find Inactive Guest Accounts by Activity (V1)
FindObsoleteGuestsByActivity.ps1: Given the number of guest accounts created in tenants, it’s a good idea to keep an eye on the accounts and remove those which aren’t used. This script uses audit data and message trace data to figure out if guests are accessing documents or receiving email, which can help you understand if the accounts are active. See this post for more information.
Find Inactive Guest Accounts by Activity (V2)
FindObsoleteGuestsByActivityV2.ps1: A more developed version of the original script which includes a comparison against the age of the guest account and checks what Microsoft 365 Groups a guest belongs to. The guest is only flagged if the account is more than 365 days old (easily adjusted). Use this version in preference to V1.
Find Microsoft 365 Groups with Guests When a Sensitivity Label Blocks Guest Access
FindOffice365GroupsWithBadGuests.PS1: You can apply a sensitivity label to a group, team, or site that blocks guest access but the action does nothing to remove guests already in the group membership. This script scans for guests in groups with labels blocking guest access and reports what it finds. See this post for more information.
Find Who Deleted Email
Find Guest Accounts Older Than a Year
FindOldGuestUsers.ps1: A script to scan through all guest accounts in a tenant and report those more than a year old. The report includes the names of the groups that the guest account belongs to. See this post for more information.
Find Orphan OneDrive for Business Accounts
FindOrphanOneDriveSites.PS1: A script to scan OneDrive for Business accounts in a tenant to find ones that are not owned by accounts known to Azure AD. If any orphaned accounts are found, they are reassigned to a nominated account, which can then be used to open and review the content stored in the accounts. See this post for more information.
Find Potential Problems in Azure Active Directory (for a tenant)
FindPotentialDirectoryProblems.PS1: This script scans Azure Active Directory to look for accounts which don’t have common attributes (like phone numbers or departments) populated. The idea is that the People Card and other Microsoft 365 features depend heavily on accurate Azure AD data, so it’s a good idea to make sure that the basics are done for all accounts. See this post for more information.
Find and Report (by Email) New Guests Added to Teams in the Last Week
FindReportGuestsAddedTeams.PS1: This script searches the Office 365 audit log to find details of guest accounts added to Teams in the last week (the date range is configurable by setting a variable). If any guests are found, they are checked to see if they are new guest accounts. If they are, their details are emailed to the person who added the guest to ask if the addition is really necessary (or whatever other text you like). See this post for details.
Report Messages Sent Using the SendAs Permission
FindSendAsAuditRecords.ps1: This script finds audit records logged when people use the SendAs mailbox permission to send messages from shared mailboxes or other user mailboxes they have delegate access to. Answering the question of who sent that message from a mailbox is a pretty frequent request and this is one solution.
ReportSendAsAuditEvents.PS1: is another take on the topic, including details of SendAs events for group mailboxes. This article explains why a different approach is needed to report these audit events in Exchange Online than on-premises.
Report Apps and Tabs Installed in Teams
FindTabsAndAppsInTeams.ps1: A script to show how to use the Graph API for Teams to find the tabs and apps installed in the channels in every team in an organization. We wrote this script as a demonstration of how to process large numbers of teams in an organization. See this post for more information.
Report Updated Service Notifications
FindUpdatedOffice365Notifications.ps1: During the latter half of 2020, a theory developed that Microsoft announced a bunch of Teams features which didn’t ship for a long time. To test the theory (and write this article), we created a script to retrieve notifications posted to the Microsoft 365 message center and look for updates, comparing the original announcement date with the date of updates to know how long a delay was.
Report Use of Anonymous (Anyone) Sharing Links
Report Who Added Guests to Microsoft 365 Groups and Teams
FindWhoAddedGuestsToGroups.ps1: A script to search the Office 365 audit log to find records captured when new guest members are added to a Microsoft 365 group (or team).
Report Who Added Guests Through SharePoint Sharing
FindWhoCreatedGuestsThroughSPOSharing.ps1: Guests can be added to a tenant by sharing a SharePoint Online document. This script reports any guest added by SharePoint sharing in the last 90 days together with the document shared.
Generate a Directory of Teams
GenerateTeamsDirectory.ps1: Teams doesn’t publish a directory of teams within an organization. This script creates a listing of Teams which could be given to users. In larger organizations, it would be best to replace the call to Get-Team with the Teams Graph API. The script was featured in this article.
Get Details of Azure AD Access Reviews for Teams and Groups
GetAzureADAccessReviewDetailsGraph.PS1: A script to analyze the progress of an Azure AD Access Review for all Microsoft 365 Groups and Teams. The number of groups needing review is reported along with the number of deny and approve decisions plus the decisions still to be made.
Get Bing Images for Teams Custom Backgrounds
GetBingImagesTeamsBackgrounds.PS1: Bing publishes nice images on a daily basis to use as the background for its home page. The same images often make good custom backgrounds for Teams meetings. This script downloads and installs the Bing daily images in the folder used for Teams custom backgrounds and removes old images after 30 days. See this article for more information.
Report User Statistics with the Graph API
Two versions exist of this script, which is designed to show how to use the Graph activity API to extract data about user activity and create a report (described in this article). The original GetGraphUserStatisticsReport.PS1 works, but it’s quite slow when you get to processing data for thousands of user accounts. We rewrote a bunch of stuff (details in this this article) to speed things up and produced GetGraphUserStatisticsReportV2.PS1. By using PowerShell hash tables for lookups, the script is much faster and is capable of processing 30,000 or more accounts (the most we’ve tested).
Report Holds in Place for a Mailbox
GetHoldsOnMailbox.PS1: A script referenced in Chapter 19 of the Office 365 for IT Pros eBook to interpret the set of holds which exist on a mailbox and tell you where the holds originate.
Get Last Activity Times for Mailboxes
GetLastActiveTimeMailboxes.PS1: A variation of the script referenced in this article to use the data revealed by the Export-MailboxDiagnosticsLogs cmdlet to report the last activity date for mailboxes. The need for more accurate activity data exists because the LastLogonDate reported by the Get-MailboxStatistics cmdlet is so inaccurate for cloud mailboxes.
Report Planner Information for a User Account
Planner has a Graph API, but you must be a member of a plan to be able to retrieve plan data. We have two sample scripts to show how to use the API to report Planner data. GetPlansForUser-DeviceCode.PS1 uses a device code and delegated permissions while GetPlansForUser.PS1 does it without a device code. See this article for more information.
Report Security Alerts
Report User Sign-Ins from the Graph
Analyze the Last Logged-In Time for Guest Accounts
LastLoggedOnByExternalUsers.ps1: A script to search the Office 365 audit log to look for guest user connections to a tenant. We also look at message trace data to discover if any email is being sent to guest accounts.
Report the Last Time the Managed Folder Assistant Processes Mailboxes
MFAReportMailboxes.ps1: The Exchange Online Managed Folder Assistant (MFA) is responsible for processing mailboxes to remove information according to retention policies. The MFA works on a workcycle basis and should process mailboxes at least once weekly. Normally, the cycle operates more often. The script reports the last time each user mailbox was processed and how many items were removed by MFA. A mailbox is only processed if it holds more than 10 MB of user data, so some user mailboxes are not processed.
Post New Microsoft 365 Roadmap Items to a Teams Channel
PostNewMicrosoft365RoadmapItems.PS1: A script to read the RSS feed for the Microsoft 365 roadmap, unpack the items found in the roadmap, and post any items created in the last 7 days (configurable) to a Teams channel using the inbound Webhook connector. See this post for more information.
Purge Exchange Online Messages Using a Content Search Action
PurgeMessagesWithContentSearch.PS1: Microsoft is busy getting rid of the Search-Inbox cmdlet, and the replacement is to use a content search to find items you want to purge and a content search action to purge the found items. This script shows how to do the job. This post covers the basics.
Rename Microsoft 365 Groups
RenameMicrosoft365GroupsNamingPolicy.PS1: If you implement a naming policy for Microsoft 365 Groups, you might have some existing groups whose display names don’t comply with the new policy. This script is an example of how to loop through groups to check names and adjust them if necessary.
Report Active Teams
Update ReportActiveTeams.ps1: This script uses the compliance records created when someone posts in a channel conversation to figure out if a team is active (obviously, if no conversations are happening, the team is probably not active).
Report Activity Alert Audit Events
Report Admin Accounts Not Protected by MFA
ReportAdminAzureADAccountsNoMFA.PS1: This script looks for Azure AD accounts that hold an administrative role and then checks if the accounts are protected by multi-factor authentication. A report (CSV) is generated for accounts which should be enabled for MFA. See this post for more information.
Report File Updates for a Chosen SharePoint File
ReportAuditRecsFileUpdates.PS1: Search the Office 365 audit log for file update records for a specific document stored in SharePoint Online or OneDrive for Business. The intention is to be able to report who last changed a document. Used as an example in Chapter 21 of the book.
Report Audit Records for Group Creation
ReportAuditRecsGroupCreation.PS1: Searches the Office 365 audit log to find events recorded for the creation of new Microsoft 365 groups. Example cited in Chapter 21 of the book.
Report Audit Records for Guest Access to SharePoint Documents
ReportAuditRecsGuestDocAccess.PS1: The script grabs the FileAccessed records from the audit log and filters them to find document accesses by guest accounts. After stripping out access to common files like SharePoint aspx components, we report the remaining records. Example used in Chapter 21 of the book. In large tenants you’re likely to have many more than 5,000 events in a 90 day period, so can can either keep on fetching records until they are all gathered or reduce the period.
Report the Membership of a Microsoft 365 Group
ReportMembershipM365Group.PS1: One of our most common requests is a way to report the membership of a Microsoft 365 Group. This script creates a nice HTML report of the membership and owners. It also outputs a CSV file for you to do your own analysis. See this article for more information.
Report the Membership of all Microsoft 365 Groups (and Teams) in a Tenant
ReportM365GroupMemberships.PS1: This script checks every licensed user account and guest account in a tenant to figure out what memberships they hold in Microsoft 365 Groups. The output is a printable HTML report and two CSV files. One with summary per-user data, the other detailing every individual membership of a group.
A Graph API version of the script is also available. The functionality is the same, but the script runs 50% faster.
Report Audit Records for User Sign-ins
ReportAuditRecsUserSignIns.PS1: Searches the Office 365 audit log to find events for user sign ins (including connections to Teams). Example used in Chapter 21 of the book. The opposite is to look for failed user sign-ins, and we can do that with ReportAuditRecFailedSignIn.PS1.
Report License Assignments to User Accounts
ReportLicenseAssignmentsToUsers.Ps1: An example of how to use the license assignments stored for user accounts to create a report. It’s a very simple script that only counts some license types and you’d have to extend it to deal with the different licenses which might be used in a tenant.
Report Non-Standard Permissions Assigned to Mailboxes
ReportMailboxPermissionsMailboxes.PS1: A script to report Full Access, SendAs, and SendOnBehalf of permissions assigned to user and shared mailboxes. It’s a good idea to run this kind of script from time to time to make sure that permissions assigned to a mailbox for a reason don’t linger there after the reason passes. See this post for more information.
Report Usage of User Mailbox Quota
ReportMailboxQuotaUsed.Ps1: A script to scan user mailboxes and report what percentage and amount of the quota assigned to the mailbox is used. The output is a CSV file. The use of the script is described here.
Report OneDrive for Business Storage Usage
ReportOneDriveStorageUsage.PS1: A simple script to grab the set of OneDrive for Business sites in the tenant and create a report of how much quota is used by each site and how how much remains. All explained in this post.
Report Permissions on Exchange Folders
ReportPermissionsFolderLevel.PS1: A script to check folders in Exchange mailboxes to find any folder-level permission assignments (for example, the ability to read the calendar folder). The output is a CSV file. This is not a fast script to run, but it can create some valuable insight as explained in this post.
Report Permissions on Exchange Online Mailboxes
Report Quarantined Messages
ReportQuarantinedMessages.PS1: Scan for messages in quarantine (for all mailboxes) and report what’s found. A CSV file is generated that can be edited and then used as the input to the Release-QuarantineMessage cmdlet to release good messages. It’s all explained in this post.
Report Audit Records for Recoverable Items
ReportRestoreRecoverableItemsAudit.PS1: Administrators can recover mailbox items on behalf of users using an EAC option or the Restore-RecoverableItems cmdlet. This script reports the audit records generated when these events occur. See this article for more information.
Report Assignment of Retention Labels to Documents
ReportRetentionLabelAuditEvents.PS1: Scans the Office 365 audit log to look for events captured when retention labels are assigned to items. The script differentiates between labels applied by policy and those applied by users. This is an example cited in Chapter 21 of the book.
Report SharePoint Online Retention Policies
ReportSPORetentionPolicies.PS1: An example used in Chapter 19 of the book to report the retention policies which apply to SharePoint Online sites.
Report SharePoint Online Storage Quota by Site
ReportSPOSiteStorageUsage.PS1: This script scans the sites found in a tenant and reports the storage used and percentage of quota for each site. The output also includes the site name, owners, and template (type). See this article for more information.
ReportSPOSiteStorageUsedGraph.PS1: Does much the same as the other script except that it uses Graph API calls instead of cmdlets from the SharePoint Online module. The use of the script and the differences encountered when using the Graph is explained in this article.
Report Audit Data for Sensitivity Labels
ReportSensitivityLabelsAuditRecords.ps1: A script to extract the audit records for assignments of sensitivity labels to documents and containers (Teams, Groups, and Sites) plus label mismatches. From January 2021, Office Online, desktop, and mobile apps generate these records.
Report Email Addresses Assigned to Teams Channels
ReportTeamsChannelEmailAddresses.ps1: A channel can be assigned an email address to allow people to send email to it. The Graph API is the only way to report these email addresses, which is what this script does. More information about what the script does is available in this Petri.com article.
Report Creation of New Teams by Email
ReportTeamsCreationbyEmail.ps1: A script to look back over the last 90 days and find audit records for the creation of new teams. An email message is created with details of the new team and is sent to a nominated recipient. See this article for more details.
Report eDiscovery Cases
ReporteDiscoveryCases.Ps1: Create a report about eDiscovery cases (core and advanced). Used as an example in Chapter 20 of the Office 365 for IT Pros eBook.
Report Managers and Their Direct Reports
ReportManagersAndDirectReports.PS1: Generate HTML report and CSV file detailing managers and their direct reports as known in the tenant’s Azure AD.
Report SharePoint Online Retention Policies
SPOSitesRetention.ps1: A script to report the retention policies which apply to SharePoint Online and OneDrive for Business in an Office 365 tenant. Used as an example in Chapter 19 of the Office 365 for IT Pros eBook.
Use Search-Mailbox to Remove Items from Mailboxes
SearchAndRemoveItemsMailboxes.PS1: Microsoft has deprecated the Search-Mailbox cmdlet, but it’s still available in Exchange Online. This script illustrates how to use Search-Mailbox to search a set of mailboxes and remove items found by a query. In this case, it was to find meetings in user mailboxes, which is why we wrote the script.
Send Email About Deleted Stream Videos
SendMessageAboutDeletedStreamVideos.PS1: A script to report the set of videos waiting for permanent deletion in the Stream recycle bin and send email about these videos to the tenant administrator. The idea is to make sure that people don’t remove videos without some oversight. An HTML report is also generated. See this article for more information.
Email Microsoft 365 Group Owners About Obsolete Groups
SendMsgToGroupOwners.ps1: This script takes the $Report output from the Teams and Groups Activity report script and creates an email to the owners of groups marked as potentially obsolete to tell them about this sad state of affairs.
Send a Welcome Email to New Mailboxes
Teams and Microsoft 365 Groups Activity Report (PowerShell Edition)
TeamsGroupsActivityReport.ps1: This script was created soon after the launch of Office 365 Groups and published in the TechNet Gallery. Its documentation is available here. The script was moved to GitHub after the retirement of the TechNet Gallery and is now at version 4.8. This version uses PowerShell exclusively and is therefore limited by the speed constraints of some cmdlets like Get-UnifiedGroup. It works, but the Graph-based version is much faster.
Teams and Microsoft 365 Groups Activity Report (Graph Edition)
TeamsGroupsActivityReportV5.PS1: The Graph-based (and much faster) edition of the Teams and Microsoft 365 Groups Activity Report script. To gain speed and be able to process tens of thousands of groups in a reasonable time, the original script was rewritten to use Graph API calls whenever possible. As such, it’s a good working example of how to swap out heavy PowerShell cmdlets for more performant Graph calls in a script.
Update Auditing Configurations for Exchange Online Mailboxes
UpdateMailboxAuditing.PS1: Mailbox auditing should be enabled for every Exchange Online mailbox with an Office 365 E3 or above license, but sometimes the auditing configuration isn’t quite what you need or want. This script processes mailboxes to set the auditing configuration to the desired state.
Update Email Signatures for OWA
UpdateOWASignatures.ps1: How to create a corporate email signature containing Azure AD attributes like name, job title, and telephone number which will be used by OWA (not Outlook). This script creates a HTML form of the signature and writes it into user mailbox settings. See this post for more information.
Update PowerShell Modules Used by Office 365
UpdateOffice365PowerShellModules.PS1: The engineering groups who create PowerShell modules for Office 365 workloads (Azure AD, SharePoint, Teams, and Exchange Online) publish updates regularly. This script checks for updates available in the PowerShell Gallery and downloads and installs the updates. See this article for details.
Update Email Signature for an Outlook for Windows Desktop Client
UpdateOutlookSignature.PS1: Outlook for Windows stores its signature information in the system registry. This script shows how to create a new signature and update the registry. See this post for details.
Restructure Sensitivity Labels for Container Management
UpdateSensitivityLabelsForGroups.PS1: Sensitivity labels can be used for container management (Teams, Groups, and Sites). If you decide to use labels for this purpose, you might want to create a separate set of labels reserved for container management and then need to replace labels already in place with new labels. All explained in this Petri.com article.
Update Subscriber Settings in Microsoft 365 Groups Used by Teams
UpdateSubscribersInGroupsUsedByTeams.PS1: Group subscriber settings dictate what email notifications members receive for things like calendar events. Teams doesn’t update subscriber settings, so you end up with issues like people complaining that they don’t receive invitations to channel meetings. The script is explained in this post.