-
Notifications
You must be signed in to change notification settings - Fork 247
Microsoft 365 Inactive Users Check Script
The m365-inactiveusers-get.ps1 script is a comprehensive PowerShell tool designed to analyze user activity within Microsoft 365 tenants. It identifies inactive users, tracks license assignments, monitors external/guest user access, and generates detailed reports to help administrators maintain security and optimize license usage.
- Identifies users who haven't signed in for a specified number of days (default: 90 days)
- Tracks users who have never logged in
- Monitors external/guest user activity
- Categorizes users by activity status (Active, Inactive, Never Logged On)
- Detects unlicensed users
- Shows detailed license assignment information
- Helps identify opportunities for license optimization
- HTML Dashboard: Interactive web-based report with visual statistics
- CSV Export: Detailed data export for further analysis
- Console Output: Real-time progress and summary statistics
- Search Functionality: Filter users in HTML report
- Tracks guest/external user last login times
- Monitors external collaborator access patterns
- Identifies unused external accounts
- PowerShell: Version 5.1 or later
- Operating System: Windows 10/11, Windows Server 2016+
Microsoft.Graph.AuthenticationMicrosoft.Graph.UsersMicrosoft.Graph.Reports
The script will automatically install missing modules if needed.
The following Microsoft Graph API scopes are required:
-
User.Read.All- Read all user profiles -
Directory.Read.All- Read directory data -
AuditLog.Read.All- Read audit log data -
Reports.Read.All- Read usage reports
-
Download the Script
# Download from GitHub repository Invoke-WebRequest -Uri "https://raw.githubusercontent.com/directorcia/ciaops/master/check-inactive-users.ps1" -OutFile "check-inactive-users.ps1"
-
Set Execution Policy (if needed)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Run with default settings (90-day threshold, includes guests, generates HTML report)
.\check-inactive-users.ps1# Check for users inactive for 30 days
.\check-inactive-users.ps1 -InactiveDays 30# Run analysis without guest/external users
.\check-inactive-users.ps1 -IncludeGuests:$false# Generate reports but don't open browser automatically
.\check-inactive-users.ps1 -OpenReportInBrowser:$false# Enable detailed logging and transcript recording
.\check-inactive-users.ps1 -DebugMode# Generate only CSV export without HTML report
.\check-inactive-users.ps1 -GenerateHtmlReport:$false# 30-day threshold, exclude guests, silent mode
.\check-inactive-users.ps1 -InactiveDays 30 -IncludeGuests:$false -OpenReportInBrowser:$false# Full analysis with debug logging for troubleshooting
.\check-inactive-users.ps1 -DebugMode -InactiveDays 60| Parameter | Type | Default | Description |
|---|---|---|---|
DebugMode |
Switch | $false |
Enable detailed logging and transcript recording |
InactiveDays |
Integer | 90 |
Number of days to consider a user inactive (1-365) |
IncludeGuests |
Switch | $true |
Include guest/external users in the analysis |
GenerateHtmlReport |
Switch | $true |
Generate interactive HTML dashboard report |
OpenReportInBrowser |
Switch | $true |
Automatically open HTML report in default browser |
The script creates timestamped files in the parent directory (../):
-
Filename:
inactive-users-report-YYYY-MM-DD-HHMM.html -
Content: Interactive dashboard with:
- Visual statistics cards
- Searchable user tables
- Color-coded status indicators
- Categorized user sections
-
Filename:
inactive-users-YYYY-MM-DD-HHMM.csv -
Content: Detailed data export with columns:
- DisplayName
- UserPrincipalName
- UserType (Member/Guest)
- AccountEnabled
- ActivityStatus
- LastSignIn
- DaysSinceLastSignIn
- IsUnlicensed
- Licenses
- CreatedDate
-
Filename:
check-inactive-users-YYYY-MM-DD-HHMM.txt - Content: Detailed execution log with timestamps
- Debug Transcript: Additional file when DebugMode is enabled
- Active Users: Users who signed in within the threshold period
- Inactive Users: Users who haven't signed in for X days
- Never Logged In: Users who have never accessed the system
- Unlicensed Users: Users without any license assignments
- External/Guest Users: External collaborators and their access patterns
- Total Users: Complete user count
Each category includes comprehensive user information:
- Full name and email address
- Last sign-in date and time
- Days since last activity
- License status and assignments
- Account status (enabled/disabled)
- User type (member/guest)
- Account creation date
- No Sensitive Data Storage: Script doesn't store passwords or tokens
- Temporary Files: All generated files contain user metadata only
- Local Processing: All analysis performed locally
- Least Privilege: Requests only necessary Graph API permissions
- Read-Only Access: Script only reads data, never modifies user accounts
- Audit Trail: All activities logged for compliance
- License Information: Shows license types but not detailed entitlements
- Activity Data: Limited to last sign-in dates, no browsing history
- External Users: Tracks access patterns for security monitoring
# Clear existing Graph modules
Get-Module Microsoft.Graph* | Remove-Module -Force
# Re-run the script
.\check-inactive-users.ps1# Connect with admin account first
Connect-MgGraph -Scopes "User.Read.All","Directory.Read.All" -TenantId "your-tenant-id"
# Then run the script
.\check-inactive-users.ps1# For tenants with many users, exclude guests to improve performance
.\check-inactive-users.ps1 -IncludeGuests:$falseWhen DebugMode is enabled, the script provides:
- Detailed module loading information
- API request/response logging
- Individual user processing details
- Performance timing information
- Identify dormant accounts that may pose security risks
- Monitor external user access patterns
- Track accounts that have never been used
- Find unused licenses that can be reclaimed
- Identify users who may not need premium licenses
- Optimize subscription costs
- Generate regular user activity reports
- Document user access patterns for audits
- Maintain records of external collaborator activity
- Clean up inactive accounts
- Monitor onboarding effectiveness
- Track user adoption patterns
# Create scheduled task for weekly reports
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\check-inactive-users.ps1 -OpenReportInBrowser:`$false"
$Trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 9AM
Register-ScheduledTask -TaskName "M365 Inactive Users Report" -Action $Action -Trigger $Trigger# Integrate into larger automation workflows
$Results = .\check-inactive-users.ps1 -GenerateHtmlReport:$false -OpenReportInBrowser:$false
# Process results programmatically
$InactiveUsers = Import-Csv "..\inactive-users-*.csv" | Where-Object { $_.ActivityStatus -eq "Inactive" }- โ Comprehensive user activity analysis
- โ Interactive HTML dashboard
- โ External/guest user monitoring
- โ License assignment tracking
- โ Automatic browser opening
- โ Debug and logging capabilities
- โ CSV export functionality
- โ Configurable thresholds
- GitHub Issues: Report bugs or request features
- Documentation: Refer to this guide for detailed usage
- Community: PowerShell and Microsoft 365 communities
- Fork the repository
- Create feature branches
- Submit pull requests
- Follow PowerShell best practices
This script is provided as-is under the MIT License. Use at your own risk. No guarantees or warranty provided.
Generated by: CIAOPS Inactive Users Check Script
Author: Anthony Fontanez
Website: www.ciaops.com
Repository: https://github.com/directorcia/ciaops