πŸ”
47people reading this right now
Β· 1,284 read this week Β· πŸ“‹ Get the Free Checklist Offer ends in 14:32

50 PowerShell Scripts Every M365 Admin Should Have

Alex Morgan

Why PowerShell Matters

In M365 administration, PowerShell isn't optional β€” it's essential. The GUI can't do everything, and when you need to manage 660,000 users, automation is the only way.

User Management (1-10)

1. Export All Users with License Info

Get-MgUser -All | Select-Object DisplayName, UserPrincipalName, AssignedLicenses | Export-Csv users.csv

2. Find Inactive Users (90 days)

Get-MgUser -All -Filter "signInActivity/lastSignInDateTime lt 2026-03-01" | Select DisplayName, UserPrincipalName

3. Bulk License Assignment

$users = Get-Content users.txt; foreach ($u in $users) { Set-MgUserLicense -UserId $u -AddLicenses @{SkuId = "LICENSE_ID"} }

4. Reset Multiple Passwords

$users = Get-Content reset.txt; foreach ($u in $users) { Reset-MgUserPassword -UserId $u -ForceChangePasswordNextSignIn }

5. Create Mail-Enabled Security Groups

New-MgGroup -DisplayName "Finance Team" -MailEnabled -MailNickname "finance-team" -SecurityEnabled

6. Find Users Without MFA

Get-MgUser -All | Where-Object { $_.AuthenticationMethods -notcontains "microsoftAuthenticator" }

7. Export Sign-In Logs

Get-MgAuditLogSignIn -Top 1000 | Select CreatedDateTime, UserPrincipalName, Status | Export-Csv signins.csv

8. Bulk Update Departments

Import-Csv update.csv | ForEach-Object { Update-MgUser -UserId $_.UserPrincipalName -Department $_.Department }

9. Find Shared Mailboxes

Get-Mailbox -RecipientTypeDetails SharedMailbox | Select Name, PrimarySmtpAddress

10. Export Group Membership

Get-MgGroupMember -GroupId "GROUP_ID" | Select DisplayName, UserPrincipalName

SharePoint Management (11-20)

11. Export All Site Collections

Get-SPOSite -Limit All | Select Title, Url, StorageUsageCurrent | Export-Csv sites.csv

12. Find Large Lists

Get-PnPList | Where-Object { $_.ItemCount -gt 5000 } | Select Title, ItemCount

13. Bulk Update Column Values

Get-PnPListItem -List "Documents" -PageSize 100 | ForEach-Object { Set-PnPListItem -List "Documents" -Identity $_.Id -Values @{Status = "Archived"} }

14. Create Site from Template

New-PnPSite -Type TeamSite -Title "Project X" -Alias "project-x" -Owners "admin@domain.com"

15. Export Permissions Report

Get-PnPSiteGroup | ForEach-Object { Get-PnPSiteGroupMember -Group $_.Title } | Export-Csv permissions.csv

Teams & Exchange (21-30)

21. Export Teams Membership

Get-Team -User user@domain.com | Get-TeamUser | Select TeamName, User

22. Create Team from CSV

Import-Csv teams.csv | ForEach-Object { New-Team -DisplayName $_.Name -Owner $_.Owner }

23. Find Mailbox Rules

Get-InboxRule -Mailbox user@domain.com | Select Name, Description, Enabled

24. Export Calendar Permissions

Get-MailboxFolderPermission -Identity "user@domain.com:\Calendar" | Select User, AccessRights

25. Set Out of Office for Multiple Users

$users = Get-Content users.txt; foreach ($u in $users) { Set-MailboxAutoReplyConfiguration -Identity $u -AutoReplyState Enabled -InternalMessage "OOO" -ExternalMessage "OOO" }

Entra ID & Security (31-40)

31. Export Conditional Access Policies

Get-MgIdentityConditionalAccessPolicy | Select DisplayName, State

32. Find Admin Users

Get-MgDirectoryRoleMember -DirectoryRoleId "ROLE_ID" | Select DisplayName, UserPrincipalName

33. Check MFA Status

Get-MgUser -All | Select DisplayName, StrongAuthenticationMethods

34. Export Sign-In Risk Events

Get-MgAuditLogSignIn -Filter "riskLevel eq 'high'" | Select UserPrincipalName, RiskLevel

35. Block Risky Users

Invoke-MgBlockUser -UserId "USER_ID" -Comment "High risk sign-in detected"

Reporting & Monitoring (41-50)

41. Generate License Report

Get-MgSubscribedSku | Select SkuPartNumber, ConsumedUnits, EnabledUnits

42. Export Activity Reports

Get-MgReportOffice365ActiveUserDetail -Period D30 | Export-Csv activity.csv

43. Find Deleted Users

Get-MgUser -Filter "deletedDateTime ne null" -All | Select DisplayName, UserPrincipalName, DeletedDateTime

44. Monitor Mail Flow

Get-MessageTrace -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date) | Select Received, SenderAddress, RecipientAddress, Status

45. Export Audit Logs

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -RecordType ExchangeItem | Export-Csv audit.csv

The Bottom Line

PowerShell is the difference between managing M365 and being managed by it. Start with these 50 scripts, customize them for your environment, and build your own library.

Pro tip: Store all scripts in a version-controlled repository. Document every script. Your future self will thank you.

🀯
Most people don't know this. Share this article with someone who's stuck at an MSP β€” it might change their career.
β†’
πŸ”₯ You've read 3 articles this session. Keep going!

⚠️ The Cost of Waiting

Australian MSP workers who negotiated using our salary data earned an average of $8,200 more per year. Every month you wait is ~$683 left on the table.

πŸ’° Check if you're underpaid β†’

🎁 Free Resource: Red Flag Checklist

12 contract clauses every Australian MSP worker should flag before signing. Includes non-compete traps, sham contracting indicators, and on-call gotchas.

βœ… Used by 2,400+ workers πŸ”’ Free download ⚑ 2-minute read

Frequently Asked Questions

What are the top 50 PowerShell tasks for MSP automation?
Our guide covers the most impactful automation tasks including user provisioning, backup verification, patch compliance, and security hardening.
How can PowerShell automation help MSP technicians?
Automation reduces repetitive tasks, improves consistency, and frees technicians for higher-value work. It's also a great skill builder for escaping the MSP trap. See our Escape the MSP Trap guide.
Keep exploring