There is no light out here.

Dark mode is the only mode.

Which groups do users belong to? A Graph API approach

What’s that? Just another script for listing users and their group memberships. You feed it a text file with UPNs, it queries Microsoft Graph, and spits out a flat CSV like: UserPrincipalName PrimarySmtpAddress GroupName GroupEmail GroupType [email protected] [email protected] Some DL [email protected] DistributionList [email protected] [email protected] Security Group ABC [email protected] MailSecurityGroup [email protected] [email protected] Some DL [email protected] DistributionList Where’s it? On GitHub Requirements PowerShell 5.1+ or PowerShell 7+ Microsoft Graph PowerShell SDK Permissions: User.Read.All, GroupMember.Read.All, Group.Read.All

March 23, 2026 · 1 min · 73 words · Przemek

How to Update Proxy Addresses for a Cloud-Only Object

Problem If you want to add or remove (basically update) a proxy address on a cloud-only account - without an Exchange mailbox - you cannot. There is no such option in the GUI and PowerShell won’t allow it either, throwing an error: Set-MgUser : Property 'proxyAddresses' is read-only and cannot be set. Status: 400 (BadRequest) ErrorCode: Request_BadRequest Solution Use the Graph API BETA endpoint. Method: PATCH URL: https://graph.microsoft.com/beta/users/<User_ID> Request Body: 1 2 3 4 5 6 7 8 { "proxyAddresses": [ "SMTP:PrimarySMTPAddress", "smtp:Alias1", "smtp:Alias2", "smtp:Alias3" ] } Expected Response: 204 No Content An example ...

March 16, 2026 · 1 min · 122 words · Przemek

Search Tenant Objects by Domain

Domain Removal Issues If you want to remove a domain from an M365 tenant, you need to deprovision all associated objects first - easy to say, harder to do. If the domain is not federated, M365 can handle it for you - it simply removes aliases and updates the Primary SMTP address and/or UPN to the default domain (domain.onmicrosoft.com). However, this does not work for federated domains. You have to remove everything manually, which is manageable for one domain. In my case, I had to remove 150. ...

March 16, 2026 · 2 min · 267 words · Przemek

Recursive Member Count for Distribution Lists

Get-GroupMemberReport PowerShell script to audit Distribution Lists and Microsoft 365 Groups membership using Microsoft Graph API. Returns transitive (recursive) member counts - including all nested group members. Why? Get-DistributionGroupMember only returns direct members, not nested Exchange Online cmdlets have pagination timeouts on large tenants Graph API’s Get-MgGroupTransitiveMemberCount solves both problems Requirements PowerShell 5.1+ or PowerShell 7+ Microsoft Graph PowerShell SDK Permissions: Group.Read.All, Directory.Read.All Usage 1 2 3 4 5 6 7 8 9 10 11 # Distribution Lists only .\Get-GroupMemberReport.ps1 -DL # Microsoft 365 Groups only .\Get-GroupMemberReport.ps1 -M365 # Both types .\Get-GroupMemberReport.ps1 -All # Test mode - first ~100 DLs or M365 .\Get-GroupMemberReport.ps1 -DL/M365 -TestLimit 100 Output CSV file with columns: ...

February 6, 2026 · 1 min · 200 words · Przemek

Assign licenses in bulk via Graph API

Add: 1 Get-Content <file path> | foreach {Set-MgUserLicense -UserId $_ -AddLicenses @{SkuID = '2ced8a00...'} -RemoveLicenses @()} Remove: 1 Get-Content <file path> | foreach {Set-MgUserLicense -UserId $_ -RemoveLicenses @('3db7c7ead579...') -AddLicenses @{}} Check for a license SkuId: Get-MgUserLicenseDetail -UserId <UPN>orGet-MgSubscribedSku | fl SkuPartNumber, skuid File path is a TXT file containing UPNs one-per-line.

January 26, 2026 · 1 min · 51 words · Przemek

Force Removal Orphaned Contact in Microsoft 365

The Problem Classic Exchange Online scenario - trying to remove an orphaned (maybe used to be synced) object. Getting slapped in the face with error The Solution Two words: Graph API. Step 1: Get the Mail Contact ID First, we need to identify the exact object we’re dealing with: 1 Get-MailContact [email protected] | Format-List Id This will give the unique identifier for the mail contact. Step 2: Verify the Object in Graph API Better safe than sorry- let’s do a double check. Replace <ID> with the ID from Step 1: ...

January 26, 2026 · 1 min · 177 words · Przemek