Find Inactive Users in Microsoft 365

Managing user activity within enterprise environments like Microsoft 365 is crucial for maintaining operational efficiency and security. Administrators need effective tools to monitor user engagement and quickly identify inactive Microsoft 365 accounts that may pose security risks or inflate licensing costs. This article covers necessary prerequisites and provides a step-by-step tutorial on how to use Microsoft Graph PowerShell commands to fetch and analyze inactive user data.

Prerequisites

  • Install the Microsoft Graph PowerShell SDK. You can install it using the following command if you haven't already:
  • You need administrative credentials to access and modify user licenses.

Graph PowerShell Script for Finding Inactive Users in Microsoft 365

# Interactive login
Connect-MgGraph -Scopes "User.Read.All", "AuditLog.Read.All"
# Define the inactivity threshold (e.g., 30 days)
$inactivityThreshold = (Get-Date).AddDays(-30)
Write-Host "Inactivity Threshold set to: $inactivityThreshold"
# Fetch users and explicitly request SignInActivity property
$users = Get-MgUser -All -Property "displayName, userPrincipalName, signInActivity" | Where-Object {
Write-Host "Checking user: $($_.DisplayName) with Last Sign-In: $($_.SignInActivity.LastSignInDateTime)"
if ($_.SignInActivity -ne $null -and $_.SignInActivity.LastSignInDateTime -ne $null) {
$lastSignIn = [datetime]::MinValue
if ([datetime]::TryParse($_.SignInActivity.LastSignInDateTime, [ref]$lastSignIn)) {
return $lastSignIn -lt $inactivityThreshold
}
}
return $false
}
# Check if users were found
if ($users.Count -gt 0) {
Write-Host "Found $($users.Count) inactive users."
# Output the inactive users
$users | Select-Object DisplayName, UserPrincipalName, @{Name="LastSignInDateTime"; Expression={$_.SignInActivity.LastSignInDateTime}}
} else { Write-Host "No inactive users found." } # Disconnect from Microsoft Graph Disconnect-MgGraph


How the Script Works?


Connect to Microsoft Graph

  • Connect-MgGraph: This command is used to establish a connection to Microsoft Graph..
  • -Scopes "User.Read.All", "AuditLog.Read.All": Specifies the permissions needed for the script to run. User.Read.All allows the script to read basic profile information of all users. AuditLog.Read.All is typically required to access detailed sign-in activity, which is necessary to determine user inactivity or inactive users.

Define the Inactivity Threshold

$inactivityThreshold = (Get-Date).AddDays(-30)
Write-Host "Inactivity Threshold set to: $inactivityThreshold"

  • Get-Date: Fetches the current date and time.
  • AddDays(-30): Adjusts the current date to 30 days ago. This is used to define the "inactivity threshold"; users who have not signed in since this date are considered inactive.
  • Write-Host:Outputs a message to the console showing what the inactivity threshold is set to.

Fetch Users and Explicitly Request SignInActivity Property

$users = Get-MgUser -All -Property "displayName, userPrincipalName, signInActivity" | Where-Object {
Write-Host "Checking user: $($_.DisplayName) with Last Sign-In: $($_.SignInActivity.LastSignInDateTime)"
if ($_.SignInActivity -ne $null -and $_.SignInActivity.LastSignInDateTime -ne $null) {
$lastSignIn = [datetime]::MinValue
if ([datetime]::TryParse($_.SignInActivity.LastSignInDateTime, [ref]$lastSignIn)) {
return $lastSignIn -lt $inactivityThreshold
}
}
return $false
}
  • Get-MgUser -All -Property "displayName, userPrincipalName, signInActivity": Retrieves all users from Microsoft 365 and specifically requests the displayName, userPrincipalName, and signInActivity properties.
  • Where-Object: Filters the users based on a condition
    • Inside the Where-Object block, it first prints out each user's name and last sign-in date.
    • Checks if the SignInActivity and its LastSignInDateTime are not null.
    • Tries to parse the LastSignInDateTimeinto a [datetime] object ($lastSignIn).
    • If successful, checks if this date is earlier than the inactivityThreshold. If it is, the user is considered inactive, and the user object is returned.

Check If Users Were Found

if ($users.Count -gt 0) {
Write-Host "Found $($users.Count) inactive users."
# Output the inactive users
$users | Select-Object DisplayName, UserPrincipalName, @{Name="LastSignInDateTime"; Expression={$_.SignInActivity.LastSignInDateTime}}
}else{
Write-Host "No inactive users found."
}

This conditional statement checks if any users were returned from the filter

  • If yes, it prints the number of inactive users found and then lists each user's display name, principal name, and last sign-in date.
  • If no users meet the criteria, it prints "No inactive users found."

Disconnect From Microsoft Graph

  • Disconnect-MgGraph: This command cleanly disconnects the PowerShell session from Microsoft Graph and helps to clear any authentication tokens or session information.

Running the Script

  • Navigate to the location where you have placed the script file and run the file with a ./<your-file-name>.ps1 command.
  • The script prompts you to sign in if you are not signed into Microsoft 365 already.
  • The script checks for inactive users (based on the set inactivity threshold) and lists them out.

Errors You Might Face

  • Permissions not available: Make sure that the required permissions (User.ReadWrite.All, Directory.ReadWrite.All ) are not only added in the Azure portal under your app registration but also have been granted admin consent, especially in organizational contexts.
  • Not running PowerShell as administrator: Ensure you always run the PowerShell as an administrator.
  • Execution policy set to restricted: If execution policy is set to restricted, then you cannot execute scripts. Execute Get-ExecutionPolicy cmdlet to find out the current execution policy. Your execution policy should be set to RemoteSigned. To set execution policy to RemoteSigned, execute the following command: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Related Articles:

Connect to Microsoft 365 Using PowerShell
How to Create Bulk Users in Office 365 Using Graph PowerShell?
Create Microsoft 365 Group Using Microsoft Graph PowerShell
Block Microsoft 365 User Using Microsoft Graph PowerShell
Assign Microsoft 365 License Using Graph PowerShell
Microsoft 365 User Management Using Graph PowerShell
Checking Group Membership in Microsoft 365
Bulk Assign Microsoft 365 License
Find Inactive Users in Microsoft 365
Using Powershell Graph Search Query
Using Powershell Graph Filter Query
Using Where-Object In Graph PowerShell
Using Expand Property In Graph PowerShell
Using Select Object In Graph PowerShell
Using -Contains Operator In Graph PowerShell
Add User to Multiple Microsoft 365 Groups Using Graph PowerShell
Get Microsoft 365 User Location Using Graph PowerShell
Import Microsoft 365 Groups from CSV File Using Graph PowerShell
Microsoft 365 Group User Import Using Graph PowerShell

© m365corner.com. All Rights Reserved. Design by HTML Codex