Advanced Management of Inactive and Licensed User Accounts in Microsoft 365
Kas Nowicka Tue Mar 26 2024 5 min readAdvanced Management of Inactive and Licensed User Accounts in Microsoft 365
Managing inactive user accounts in Microsoft 365 is crucial for maintaining security, reducing unnecessary costs, and ensuring optimal system performance. This guide provides a comprehensive technical approach to identifying and handling inactive user accounts.
1. Understanding Inactivity in User Accounts
Before diving into the tools and techniques, it’s essential to define what constitutes an “inactive” user in the context of Microsoft 365.
Typically, inactivity can be identified by a lack of user sign-ins, no email activity, or unutilized licenses over a set period, often defined by organizational policy (90, 180, or even 360 days).
2. Technical Tools for Identifying Inactive Users
PowerShell Scripts
PowerShell offers granular control to fetch detailed user activity data. By accessing audit logs or user sign-in activity via PowerShell, administrators can script processes to routinely check and report on user inactivity. Here’s a detailed script approach:
- Utilize
Get-MgUser
to fetch user profiles andGet-MgAuditLogSignIn
for sign-in details. - Filter this data based on the last sign-in date to pinpoint inactive accounts.
Microsoft Graph API
For more advanced scenarios, the Microsoft Graph API provides programmatic access to detailed user data and activity logs across Microsoft 365 services. Through Graph API, you can retrieve user sign-in logs, analyze user behavior patterns, and automate the extraction of inactivity reports.
Office 365 Admin Center and Azure AD Reports
The Admin Center provides built-in reports that can serve as a starting point for identifying inactive users. However, for more detailed analysis, leveraging Azure AD’s reporting features can give deeper insights into user activity, including login attempts and application usage.
3. Automating Inactivity Reporting
Automation is key to efficiently managing large environments. Automating the detection and reporting of inactive users can be achieved by:
- Scheduling PowerShell scripts to run at regular intervals.
- Using Microsoft Power Automate to trigger alerts or actions based on specific inactivity metrics.
- Integrating with existing IT management tools that support API connections to Microsoft 365 for continuous monitoring.
4. Handling Inactive User Accounts
Once inactive accounts are identified, several actions can be taken depending on organizational policies:
- Disabling Accounts: Prevent login attempts and secure the user identity.
- Reclaiming Licenses: Unassign licenses from inactive accounts to save on costs.
- Archiving User Data: Ensure that data retention complies with company policies and legal requirements before deactivating accounts.
5. Security Considerations and Compliance
Managing inactive accounts also has significant security and compliance implications:
- Risk Mitigation: Inactive accounts are often easier targets for breaches. Regular audits and prompt deactivation reduce these risks.
- Compliance with Data Protection Regulations: Ensuring that inactive accounts are handled according to GDPR, HIPAA, or other relevant regulations is crucial for legal compliance.
6. Generating Detailed Inactivity Reports Using Microsoft Graph and PowerShell
Microsoft 365 administrators often need to generate reports on inactive users to manage accounts efficiently, optimize licenses, and enhance security. Traditional methods like using Get-MailboxStatistics
or the Microsoft 365 admin center provide last login details but can be inaccurate or labor-intensive.
A more effective approach utilizes Microsoft Graph and PowerShell. By leveraging the Get-MgUser
cmdlet with properties such as SigninActivity
, admins can accurately retrieve and analyze last logon times, helping to identify inactive users with greater precision. This method, while thorough, may require additional processing to determine the duration of inactivity.
7. Identifying Inactive Users with Licenses with MSGraph
The function of this script is to return all users that have licenses and have been inactive in Azure AD sign-in logs for a specified number of days. For customers who have Azure AD Premium P2 subscriptions, the sign-in logs are retained for 30 days. By default, Azure AD retains sign-in logs for 30 days, but the retention period can be increased up to two years by using Azure Monitor and Storage accounts.
Script Steps:
-
Install the required PowerShell modules:
Install-Module -Name Microsoft.Graph.Authentication -Scope CurrentUser Install-Module -Name Microsoft.Graph.Users -Scope CurrentUser Install-Module -Name Microsoft.Graph.Reports -Scope CurrentUser
-
Import the required modules:
Import-Module Microsoft.Graph.Authentication Import-Module Microsoft.Graph.Users Import-Module Microsoft.Graph.Reports
-
Connect to Microsoft Graph using delegated permissions:
Connect-MgGraph -Scopes "User.Read.All AuditLog.Read.All"
-
Download the CSV file containing the product names and SkuPartNumber mappings:
# Replace the .csv file path with your desired path Invoke-WebRequest -Uri "https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv" -OutFile "XXXXX\product_names.csv"
-
Import the CSV file into a variable and create a dictionary using the SkuPartNumber as key and Product_Display_Name as value:
$productNames = Import-Csv "XXXXX\product_names.csv" $skuDict = @{} foreach($product in $productNames) { $skuDict[$product.GUID] = $product.Product_Display_Name }
-
Set the number of days of inactivity to consider:
$DaysInactive = 30 $InactiveDate = (Get-Date).AddDays(-$DaysInactive)
-
Retrieve all users using the Microsoft Graph API:
$AllUsers = Get-MgUser -All -Property Id, DisplayName, UserPrincipalName, AccountEnabled
-
Initialize an empty array to store inactive users:
$InactiveUsers = @()
-
Iterate through each user and check for inactivity in Azure AD sign-in logs:
foreach ($User in $AllUsers) { $LicenseDetail = Get-MgUserLicenseDetail -UserId $User.Id if ($LicenseDetail -ne $null) { $License = ($LicenseDetail | ForEach-Object { $skuDict[$_.SkuId] }) -join " " Write-Output "Checking $($User.userPrincipalName) with License: $License" Write-Output "Getting sign-in logs for $($User.displayName)" $AllSignInLogs = Get-MgAuditLogSignIn -Filter "userDisplayName eq '$($User.displayName)'" $SignIn = $AllSignInLogs | Sort-Object -Property createdDateTime -Descending | Select-Object -First 1 Write-Output "Most recent sign-in log entry:" Write-Output $SignIn.createdDateTime if ($SignIn -eq $null -or $SignIn.createdDateTime -lt $InactiveDate) { $InactiveUsers += [PSCustomObject]@{ DisplayName = $User.displayName UserPrincipalName = $User.userPrincipalName LastSignin = $SignIn Enabled = $User.accountEnabled License = $License } write-output 'InactiveUser! '$User.displayName $License } } }
-
Export the list of inactive users to a CSV file:
# Replace the .csv file path with your desired path $InactiveUsers | Export-Csv -Path "XXXXX\InactiveUsers.csv" -NoTypeInformation
-
Disconnect from Microsoft Graph:
Disconnect-MgGraph
Conclusion
Efficient management of inactive user accounts in Microsoft 365 not only optimizes licensing costs but also enhances security and compliance. By leveraging PowerShell, Microsoft Graph API, and automation, IT administrators can establish robust processes to identify, report, and manage inactive user accounts across their organizations.
However, managing inactive user accounts manually can be time-consuming and error-prone, especially for large and complex Microsoft 365 environments. That’s why many organizations rely on third-party solutions, which can dramatically cut down time spent on these tasks and do not require advanced skills like scripting in PowerShell or retrieving information via Graph.
Ciao,
Kas