Reporting User and Group Assignments for Enterprise Applications

A reader asked how to report user and group assignments for enterprise apps. As it turns out, this isn’t particularly difficult, if you know where to look. Our script uses the Graph SDK to check service principals, filters out the apps to check, and extracts the user and group assignments before reporting what it finds.

A New Approach to Reporting Exchange Mailbox Statistics

Exchange mailbox statistics reports are usually produced using PowerShell cmdlets. However, using Graph usage data is a faster way to process mailboxes because it avoids the need to fetch mailbox statistics by running a cmdlet for each mailbox. This article describes how to speed things up in a way that will probably benefit larger organizations most, but every Exchange Online tenant can probably benefit.

Report Email Proxy Addresses for Exchange Online Mail-Enabled Objects

This article explains how to use PowerShell to report the email proxy addresses assigned to Exchange Online mail-enabled objects. Creating the list is straightforward, but figuring out how to use the list afterwards might need more creativity. To get things going, we show how to load the list into a hash table to resolve email addresses into display names.

Reporting the Storage Used by Loop Workspaces

When Microsoft put the Loop app into preview, they didn’t impose any restrictions in terms of licensing or workspace storage. MC678308 announces that Loop workspace storage will count against the tenant SharePoint Online storage quota. This article explains how to use the Get-SPOContainer cmdlet to fetch information about Loop workspaces and the storage they consume.

Reducing the Memory Footprint of Exchange Online PowerShell

The Exchange Online developers issued three recommendations to improve performance and reduce memory consumption for Exchange Online PowerShell sessions, specifically those used by automated scripts that don’t involve human interaction. I think two of the recommendations are very practical and worth implementing by everyone, even if you think everything is good with PowerShell.

Using Microsoft Graph SDK Cmdlets to Create a SharePoint Online List

An article last week discussed how to create SharePoint lists with the PnP.PowerShell module. In this article, we do the same with cmdlets from the Microsoft Graph PowerShell SDK. The results achieved with the Graph SDK aren’t as good as those gained with PnP.PowerShell. Some of the SDK cmdlets don’t function as expected and the resulting list is not as functional as the one generated by PnP. Oh well…

Creating a Teams Directory in a SharePoint Online List

This article explains how to create SharePoint lists using cmdlets from the PnP.PowerShell module. The original data comes from a script to create a Teams Directory in HTML and CSV format files. The CSV data is imported into SharePoint to populate a list in a communications site. Everything works very smoothly, which begs the question why this kind of import isn’t done more often. Perhaps it’s because people don’t know that it’s possible. They do now.

Teams and Microsoft Exchange PowerShell Modules Clash Over Required DLL

After updating a bunch of PowerShell modules, I was dismayed to find a PowerShell module clash caused by a dependency on the Microsoft.Identity.Client DLL. The Exchange Online management module wanted a higher version of the DLL than the one loaded by the Teams module, so the Connect-ExchangeOnline cmdlet barfed. It’s easy to understand the logic behind the problem, but it’s hard to understand why Microsoft let it happen.

How to Control the Creation of Microsoft 365 Groups with the Microsoft Graph PowerShell SDK

Microsoft suggests that allowing every user to create new Microsoft 365 groups. That’s mad. Controlling group creation through policy settings is the only way to go. It will avoid group sprawl (or team sprawl) and avoid a lot of administrative effort that will otherwise be devoted to cleaning up the mess of unused and unwanted groups. This article explains how to update policy settings to control group creation using cmdlets from the Microsoft Graph PowerShell SDK.

How to Execute Bulk Updates of Primary SMTP Address for Distribution Lists

Like any mail-enabled object managed by Exchange Online, distribution list proxy addresses determine if Exchange can deliver messages to an object. Sometimes the proxy addresses aren’t correct or need adjustment, such as in the case when an organization wants to make sure that all distribution lists have primary SMTP addresses from a specific domain. This article explains how to use PowerShell to adjust the primary SMTP address when necessary.

Microsoft 365 Groups with Long Names Cause Graph Errors

Microsoft 365 group display names longer than 120 characters will cause problems for Graph API requests attempting to fetch the groups. A workaround exists, which is to make the request an advanced query rather than a regular one. But the question really should be “who needs group display names that are longer than 120 characters?”

How to Block User Access to Microsoft 365 PowerShell Modules

The question of how best to block PowerShell access for Microsoft 365 user accounts deserved some consideration. The answer lies in service principals for the enterprise accounts created by Microsoft to allow PowerShell modules to authenticate with Entra ID. By restricting access to an assigned security group, you effectively block access to anyone outside that group.

How to Remove Licenses From Disabled Accounts with PowerShell

This article explains how to use PowerShell to remove licenses from disabled accounts, including some caveats such as not removing Exchange Online licenses. Organizations might want to do this to save money on Microsoft 365 license fees while an account is temporarily unused. Removal of Exchange Online licenses can result in the loss of a mailbox, and you don’t want that to happen if you’re disabling accounts just because someone is on a long-term sabbatical or other leave of absence.

How to Create Dynamic Microsoft 365 Groups (and Teams) for Departments

This article explains how to use PowerShell to create dynamic Microsoft 365 groups (and teams) based on the departments assigned to Entra ID user accounts. Creating a new group is easy. The trick in team-enablement is to wait for the synchronization between Entra ID and Teams to finish before you go ahead. After that, it’s plain sailing.

Microsoft Removes Exchange Online User Photo Cmdlets

Microsoft announced that they will deprecate the user photo cmdlets from Exchange Online from November 30, 2023. Microsoft Graph PowerShell SDK cmdlets replace the EXO cmdlets because user photo data is stored in Entra ID. Although inconvenient for those who need to update scripts, this is part of an effort to rationalize how Microsoft 365 handles user profile information.

How to Convert Custom Background Images for Teams 2.1

The Teams 2.1 client uses a different folder and naming convention for custom background images. People who switch must move their images, so here’s a script to do the job by resizing images to meet Teams requirements, renaming the files to comply with the new naming scheme, and copying the files from the old to the new folder, It’s PowerShell, so you can change the code as you like.

How to Update Shared Mailbox Owners About Quota Usage

An old script created to report quotas for user mailboxes provided the basis for email-based reporting of shared mailbox quotas. The old script used just Exchange Online PowerShell. This versions mixes Exchange Online and the Graph SDK and throws in some certificate-based authentication to boot to allow the script to send email from something other than the signed-in account.. It all comes together, using chunks of code from other scripts to speed up writing. It’s the PowerShell way…

How to Monitor New Members Added to Teams

I was asked how easy it would be to write a PowerShell script to monitor new teams members and reject any additions that met specific criteria. Easy, we said, so we set to creating a script to interrogate the unified audit log to find new member events. Once that was done, it’s a matter of analyzing the events to find if we should reject the addition of any of the added members.

How to Analyze User Email Traffic by Internal or External Destination

After writing a previous article about using PowerShell to analyze message trace data, I was asked about analyzing user (or mailbox) sending patterns to discover who’s sending email and where they’re sending messages to. As in many similar situations, PowerShell is a great tool to use because of its flexibility. This article explains how to generate a per-mailbox report of how many messages are sent and the percentage of internal versus external, plus the external domains the email goes to.

How to Create Dynamic Administrative Units with PowerShell

A reader asked how they could create dynamic administrative units for every department in their directory. A PowerShell script does the job, even if some constraints in how Entra ID processes membership rules means that the rules can’t be quite as precise as I would like them to be.

Chasing Performance When Reporting Teams SharePoint Site URLs

It’s possible to use PowerShell to create a report detailing the SharePoint Online site URLs used with Teams. My first attempt used the Exchange Online module, but is the Graph any faster? As it turns out, not really. At least, not for interactive sessions using the Microsoft Graph PowerShell SDK (things are different when running SDK code using a registered app). I tried several approaches, but Graph permissions got in the way every time.

Use Message Trace Data to Analyze Email Traffic

This article describes how to use PowerShell to extract and analyze Exchange Online message trace data to figure out the volume of traffic to outbound domains and from inbound domains. You might think that this is the same information as available in the Exchange admin center mail flow report, but it’s not. Once again, the value of PowerShell in retrieving and using data is evident.

Monitor and Report Additions to Teams Membership

A question about how to report specific changes to Teams memberships gave another excuse to use PowerShell with the unified audit log to deliver a solution. The idea is that you can check audit log entries to see when specific user accounts join the membership of Teams. Once you’ve found that data, it’s a simple matter of creating email to share the results. All done with a few lines of PowerShell…

Filtering Against the Entra ID Employee Hire Date Property

A new preview capability supports filtering against the Azure AD employee hire date property (Entra ID). Two different filter types are available to support the PowerShell ge and le operators. One filter checks against a set date, the other uses a calculated date. Both work well, and hopefully this development means that the Entra ID developers will enable the same capability for the Get-MgUser cmdlet.

Managing Assigned Licenses for Deleted User Accounts

A reader asked why some deleted Microsoft 365 user accounts appear to have assigned licenses. That seemed strange because licenses are freed up for reuse when accounts are deleted, so we took a look behind the scenes to find out why some deleted user accounts keep license information in their properties and some do not.

Reporting Retention Tags for Exchange Online Mailbox Folders

Exchange retention tags can be assigned to mailbox folders. In this article, we explain how to retrieve details of folder and personal tags assigned to folders plus the default archive and delete tags defined in the mailbox retention policy. We also explore if it’s possible to report retention tags assigned to individual messages and conclude that it’s not worthwhile.

Retrieving Azure AD (Entra ID) Privileged Identity Management Role Assignments

PIM, or Privileged Identity Management, is a solution for managing the assignment of privileged Entra ID roles to users and groups. PIM role assignments can be active or eligible. If you report “normal” role assignments, you only see the currently active set. Some more processing is needed to fetch the PIM assignments. Here’s our version of a script to do the job for holders of the Exchange administrator and Global administrator roles.

Microsoft Graph PowerShell SDK V2.0 Reaches General Availability

The Microsoft Graph PowerShell SDK V2 attained general availability on July 4, 2023. Microsoft did a horrible job of announcing the news, but now that the SDK V2 is available, it’s time to migrate scripts from earlier versions. Splitting the V1.0 and beta cmdlets into different modules is a big difference, as is renaming the beta cmdlets. But other points exist to consider as you migrate from the Microsoft Graph PowerShell SDK V1 to V2.

How to Report Renewal Dates for Microsoft 365 Subscriptions

Up to now, the Microsoft Graph PowerShell SDK has not included a cmdlet capable of reporting the renewal dates for Microsoft 365 subscriptions. A new beta Graph subscriptions endpoint is a method to retrieve the renewal information. Even if you can’t use an off-the-shelf cmdlet, you can still get the data.

Assigning OneDrive Storage Quotas Based on Group Membership

Although SharePoint Online doesn’t support the allocation of OneDrive storage quotas via group membership, this is an easy solution to code with PowerShell. In this article, we discuss the steps needed to use groups to set a desired storage allocation for group members and how to apply those allocations to OneDrive for Business accounts. If you don’t want to use groups, Azure AD administrative units or even Exchange Online dynamic distribution lists would work too.

How Administrators Can Remove Meetings On Behalf Of Users

Sometimes administrators need to intervene and cancel meetings on behalf of users. That’s why the Remove-CalendarEvents cmdlet exists. The cmdlet scans a user mailbox to find meetings organized by the user for a defined period and cancels the events. Meeting participants receive a cancellation notice. It’s a useful cmdlet to know about, just in case.

The Right Way for Scripts to Request Permissions with the Microsoft Graph PowerShell SDK

Using Connect-MgGraph scopes to request a precise set of permissions at the start of a PowerShell script is the right way to make sure that the script can run and access the data it needs to process. Two schools of thought exist. Is it best to use the Scopes parameter to define the set of permissions when connecting with Connect-MgGraph, or should you go ahead and connect and check afterward? I favor the first approach, but either way works.

Azure AD Access Token Lifetimes and Long-running PowerShell Scripts

Sometimes, long running PowerShell scripts encounter the problem of Azure AD access token lifetime expiration. In other words, the default lifetime of tokens issued by Azure AD is too short to allow the script to complete before the token expires. Two solutions exist. Use a token lifetime policy to prolong access token lifetimes or check in code for potential expiration and renew when necessary.

Reporting the Assignment of Container Management Labels

Container management labels apply settings to the Microsoft 365 Groups to which they are assigned. This article describes how to generate a report about the container management labels assigned to groups. The report highlights groups that don’t have labels and those that don’t have owners.

Microsoft Removes Remote PowerShell for Compliance Sessions

Following the removal of Remote PowerShell connections for Exchange Online, Microsoft is removing Remote PowerShell for the compliance endpoint. The change to REST-based cmdlets is expected to deliver better performance and reliability. The changes are implemented in V3.2 of the Exchange Online management module, which should be available on May 1.

Microsoft Releases Cmdlet to Retrieve Disposition Review Items

The Get-ReviewItems cmdlet (in the Exchange Online management module) is available to export details about disposition review items in either a pending or disposed state. It’s possible that you don’t care very much about records management, retention labels, or disposition processing, but if you do, you’ll be glad that the new cmdlet exists.